diff --git a/MANIFEST.md b/MANIFEST.md index 195a9d1..08d88fd 100644 --- a/MANIFEST.md +++ b/MANIFEST.md @@ -11,7 +11,7 @@ A basic `manifest.json` with just the required fields looks like this: ```json { - "$schema": "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", // JSON Schema URL for validation + "manifest_version": "0.1", // Manifest spec version this manifest conforms to "name": "my-extension", // Machine-readable name (used for CLI, APIs) "version": "1.0.0", // Semantic version of your extension "description": "A simple MCP extension", // Brief description of what the extension does @@ -37,7 +37,7 @@ A basic `manifest.json` with just the required fields looks like this: ```json { - "$schema": "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + "manifest_version": "0.1", "name": "my-extension", "version": "1.0.0", "description": "A simple MCP extension", @@ -71,7 +71,7 @@ A full `manifest.json` with most of the optional fields looks like this: ```json { - "$schema": "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + "manifest_version": "0.1", "name": "My MCP Extension", "display_name": "My Awesome MCP Extension", "version": "1.0.0", @@ -162,7 +162,7 @@ A full `manifest.json` with most of the optional fields looks like this: ### Required Fields -- **$schema**: JSON Schema URL for validation (defaults to https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json) +- **manifest_version**: Specification version this extension conforms to - **name**: Machine-readable name (used for CLI, APIs) - **version**: Semantic version (semver) - **description**: Brief description diff --git a/examples/chrome-applescript/manifest.json b/examples/chrome-applescript/manifest.json index eb54ca4..cb9261e 100644 --- a/examples/chrome-applescript/manifest.json +++ b/examples/chrome-applescript/manifest.json @@ -1,5 +1,6 @@ { - "$schema": "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + "$schema": "../../dist/mcpb-manifest.schema.json", + "manifest_version": "0.1", "name": "chrome-applescript", "display_name": "Control Chrome with AppleScript", "version": "0.1.0", diff --git a/examples/file-manager-python/manifest.json b/examples/file-manager-python/manifest.json index 8a8f4d6..89546f3 100644 --- a/examples/file-manager-python/manifest.json +++ b/examples/file-manager-python/manifest.json @@ -1,5 +1,6 @@ { - "$schema": "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + "$schema": "../../dist/mcpb-manifest.schema.json", + "manifest_version": "0.1", "name": "file-manager-python", "display_name": "Python File Manager MCP", "version": "0.1.0", diff --git a/examples/file-system-node/manifest.json b/examples/file-system-node/manifest.json index 0076dc5..890ecdb 100644 --- a/examples/file-system-node/manifest.json +++ b/examples/file-system-node/manifest.json @@ -1,5 +1,5 @@ { - "$schema": "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + "manifest_version": "0.1", "id": "anthropic.demo.filesystem", "name": "Filesystem", "display_name": "Filesystem", diff --git a/examples/hello-world-node/manifest.json b/examples/hello-world-node/manifest.json index ccfa440..30837eb 100644 --- a/examples/hello-world-node/manifest.json +++ b/examples/hello-world-node/manifest.json @@ -1,5 +1,6 @@ { - "$schema": "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + "$schema": "../../dist/mcpb-manifest.schema.json", + "manifest_version": "0.1", "name": "hello-world-node", "display_name": "Hello World MCP Server (Reference Extension)", "version": "0.1.0", diff --git a/src/cli/init.ts b/src/cli/init.ts index 91b97d8..4f104be 100644 --- a/src/cli/init.ts +++ b/src/cli/init.ts @@ -773,7 +773,7 @@ export function buildManifest( const { keywords, license, repository } = optionalFields; return { - $schema: "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + manifest_version: "0.1", name, ...(displayName && displayName !== name ? { display_name: displayName } diff --git a/src/schemas-loose.ts b/src/schemas-loose.ts index 37d2c3a..882b1a5 100644 --- a/src/schemas-loose.ts +++ b/src/schemas-loose.ts @@ -79,7 +79,8 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .object({ $schema: z.string().optional(), - dxt_version: z.string().optional().describe("@deprecated - Use $schema instead"), + dxt_version: z.string().optional().describe("@deprecated Use manifest_version instead"), + manifest_version: z.string().optional(), name: z.string(), display_name: z.string().optional(), version: z.string(), @@ -105,9 +106,9 @@ export const McpbManifestSchema = z .optional(), }) .refine( - (data) => !!(data.$schema || data.dxt_version), + (data) => !!(data.dxt_version || data.manifest_version), { - message: "Either '$schema' or 'dxt_version' (deprecated) must be provided", + message: "Either 'dxt_version' (deprecated) or 'manifest_version' must be provided", } ); diff --git a/src/schemas.ts b/src/schemas.ts index 7998d8e..2b59709 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -79,7 +79,8 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .strictObject({ $schema: z.string().optional(), - dxt_version: z.string().optional().describe("@deprecated - Use $schema instead"), + dxt_version: z.string().optional().describe("@deprecated Use manifest_version instead"), + manifest_version: z.string().optional(), name: z.string(), display_name: z.string().optional(), version: z.string(), @@ -105,9 +106,9 @@ export const McpbManifestSchema = z .optional(), }) .refine( - (data) => !!(data.$schema || data.dxt_version), + (data) => !!(data.dxt_version || data.manifest_version), { - message: "Either '$schema' or 'dxt_version' (deprecated) must be provided", + message: "Either 'dxt_version' (deprecated) or 'manifest_version' must be provided", } ); diff --git a/test/cli.test.ts b/test/cli.test.ts index c11bdfc..d250b5c 100644 --- a/test/cli.test.ts +++ b/test/cli.test.ts @@ -91,7 +91,7 @@ describe("DXT CLI", () => { fs.writeFileSync( join(tempDir, "manifest.json"), JSON.stringify({ - $schema: "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + manifest_version: "1.0", name: "Test Extension", version: "1.0.0", description: "A test extension", @@ -188,7 +188,7 @@ describe("DXT CLI", () => { fs.writeFileSync( join(tempExecDir, "manifest.json"), JSON.stringify({ - $schema: "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + manifest_version: "1.0", name: "Test Executable Extension", version: "1.0.0", description: "A test extension with executable files", diff --git a/test/config.test.ts b/test/config.test.ts index 0b1c382..6461c5a 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -90,7 +90,7 @@ describe("getMcpConfigForManifest", () => { }; const baseManifest: McpbManifest = { - $schema: "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + manifest_version: "1.0.0", name: "test-extension", version: "1.0.0", description: "Test extension", @@ -305,7 +305,7 @@ describe("getMcpConfigForManifest", () => { describe("hasRequiredConfigMissing", () => { const baseManifest: McpbManifest = { - $schema: "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + manifest_version: "1.0.0", name: "test-extension", version: "1.0.0", description: "Test extension", diff --git a/test/init.test.ts b/test/init.test.ts index 5685580..68730ce 100644 --- a/test/init.test.ts +++ b/test/init.test.ts @@ -217,7 +217,7 @@ describe("init functions", () => { ); expect(manifest).toEqual({ - $schema: "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + manifest_version: "0.1", name: "test-extension", version: "1.0.0", description: "Test description", @@ -303,7 +303,7 @@ describe("init functions", () => { ); expect(manifest).toEqual({ - $schema: "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + manifest_version: "0.1", name: "test-extension", display_name: "Test Extension", version: "1.0.0", diff --git a/test/invalid-manifest.json b/test/invalid-manifest.json index 729746d..ccfcd3a 100644 --- a/test/invalid-manifest.json +++ b/test/invalid-manifest.json @@ -1,5 +1,5 @@ { - "$schema": "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + "manifest_version": "1.0", "name": "test-extension", "version": "1.0.0", "description": "A test DXT extension", diff --git a/test/schemas.test.ts b/test/schemas.test.ts index 3b8f237..a9297d8 100644 --- a/test/schemas.test.ts +++ b/test/schemas.test.ts @@ -37,7 +37,7 @@ describe("McpbManifestSchema", () => { it("should validate manifest with all optional fields", () => { const fullManifest = { - $schema: "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + manifest_version: "1.0", name: "full-extension", display_name: "Full Featured Extension", version: "2.0.0", @@ -117,7 +117,7 @@ describe("McpbManifestSchema", () => { serverTypes.forEach((type) => { const manifest = { - $schema: "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + manifest_version: "1.0", name: "test", version: "1.0.0", description: "Test", @@ -136,73 +136,4 @@ describe("McpbManifestSchema", () => { expect(result.success).toBe(true); }); }); - - describe("backward compatibility", () => { - it("should accept manifest with dxt_version instead of $schema", () => { - const legacyManifest = { - dxt_version: "0.1", - name: "legacy-extension", - version: "1.0.0", - description: "Legacy extension", - author: { name: "Test Author" }, - server: { - type: "node", - entry_point: "server.js", - mcp_config: { - command: "node", - args: ["server.js"], - }, - }, - }; - - const result = McpbManifestSchema.safeParse(legacyManifest); - expect(result.success).toBe(true); - }); - - it("should accept manifest with $schema", () => { - const modernManifest = { - $schema: "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", - name: "modern-extension", - version: "1.0.0", - description: "Modern extension", - author: { name: "Test Author" }, - server: { - type: "node", - entry_point: "server.js", - mcp_config: { - command: "node", - args: ["server.js"], - }, - }, - }; - - const result = McpbManifestSchema.safeParse(modernManifest); - expect(result.success).toBe(true); - }); - - it("should reject manifest without $schema or dxt_version", () => { - const invalidManifest = { - name: "invalid-extension", - version: "1.0.0", - description: "Invalid extension", - author: { name: "Test Author" }, - server: { - type: "node", - entry_point: "server.js", - mcp_config: { - command: "node", - args: ["server.js"], - }, - }, - }; - - const result = McpbManifestSchema.safeParse(invalidManifest); - expect(result.success).toBe(false); - if (!result.success) { - expect(result.error.issues[0].message).toContain( - "Either '$schema' or 'dxt_version' (deprecated) must be provided" - ); - } - }); - }); }); diff --git a/test/valid-manifest.json b/test/valid-manifest.json index 40a1d92..a91e78f 100644 --- a/test/valid-manifest.json +++ b/test/valid-manifest.json @@ -1,5 +1,5 @@ { - "$schema": "https://static.modelcontextprotocol.io/schemas/2025-08-26/mcpb.manifest.schema.json", + "manifest_version": "1.0", "name": "test-extension", "display_name": "Test Extension", "version": "1.0.0",