From 76949836e07146c8f464020f80ec3581bebf40a1 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Mon, 25 Aug 2025 21:09:45 -0700 Subject: [PATCH] fix: update schema to reflect manifest_version --- MANIFEST.md | 8 +-- examples/chrome-applescript/manifest.json | 4 +- examples/file-manager-python/manifest.json | 4 +- examples/file-system-node/manifest.json | 2 +- examples/hello-world-node/manifest.json | 4 +- scripts/build-mcpb-schema.js | 6 +-- src/cli/init.ts | 2 +- src/schemas-loose.ts | 16 ++++-- src/schemas.ts | 62 ++++++++++++---------- test/cli.test.ts | 4 +- test/config.test.ts | 4 +- test/init.test.ts | 4 +- test/invalid-manifest.json | 2 +- test/schemas.test.ts | 4 +- test/valid-manifest.json | 2 +- 15 files changed, 72 insertions(+), 56 deletions(-) diff --git a/MANIFEST.md b/MANIFEST.md index cfff8d6..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 { - "mcpb_version": "0.1", // MCPB spec version this manifest conforms to + "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 { - "mcpb_version": "0.1", + "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 { - "mcpb_version": "0.1", + "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 -- **mcpb_version**: Specification version this extension conforms to +- **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 8e8a559..cb9261e 100644 --- a/examples/chrome-applescript/manifest.json +++ b/examples/chrome-applescript/manifest.json @@ -1,6 +1,6 @@ { - "$schema": "../../dist/dxt-manifest.schema.json", - "mcpb_version": "0.1", + "$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 2aa0941..89546f3 100644 --- a/examples/file-manager-python/manifest.json +++ b/examples/file-manager-python/manifest.json @@ -1,6 +1,6 @@ { - "$schema": "../../dist/dxt-manifest.schema.json", - "mcpb_version": "0.1", + "$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 e808ce7..890ecdb 100644 --- a/examples/file-system-node/manifest.json +++ b/examples/file-system-node/manifest.json @@ -1,5 +1,5 @@ { - "mcpb_version": "0.1", + "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 13391fa..30837eb 100644 --- a/examples/hello-world-node/manifest.json +++ b/examples/hello-world-node/manifest.json @@ -1,6 +1,6 @@ { - "$schema": "../../dist/dxt-manifest.schema.json", - "mcpb_version": "0.1", + "$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/scripts/build-mcpb-schema.js b/scripts/build-mcpb-schema.js index b9c0c74..b24856f 100644 --- a/scripts/build-mcpb-schema.js +++ b/scripts/build-mcpb-schema.js @@ -1,11 +1,11 @@ -import { DxtManifestSchema, DxtSignatureInfoSchema } from "../dist/schemas.js"; +import { McpbManifestSchema, McpbSignatureInfoSchema } from "../dist/schemas.js"; import * as z from "zod/v4"; import fs from "node:fs/promises"; import path from "node:path"; const schemasToWrite = { - "dxt-manifest": DxtManifestSchema, - "dxt-signature-info": DxtSignatureInfoSchema, + "mcpb-manifest": McpbManifestSchema, + "mcpb-signature-info": McpbSignatureInfoSchema, }; await fs.mkdir(path.join(import.meta.dirname, "../dist"), { recursive: true }); diff --git a/src/cli/init.ts b/src/cli/init.ts index 1dc2bad..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 { - mcpb_version: "0.1", + manifest_version: "0.1", name, ...(displayName && displayName !== name ? { display_name: displayName } diff --git a/src/schemas-loose.ts b/src/schemas-loose.ts index b88270a..882b1a5 100644 --- a/src/schemas-loose.ts +++ b/src/schemas-loose.ts @@ -76,9 +76,11 @@ export const McpbUserConfigValuesSchema = z.record( z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]), ); -export const McpbManifestSchema = z.object({ - $schema: z.string().optional(), - mcpb_version: z.string(), +export const McpbManifestSchema = z + .object({ + $schema: z.string().optional(), + 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(), @@ -102,7 +104,13 @@ export const McpbManifestSchema = z.object({ user_config: z .record(z.string(), McpbUserConfigurationOptionSchema) .optional(), -}); + }) + .refine( + (data) => !!(data.dxt_version || data.manifest_version), + { + message: "Either 'dxt_version' (deprecated) or 'manifest_version' must be provided", + } + ); export const McpbSignatureInfoSchema = z.object({ status: z.enum(["signed", "unsigned", "self-signed"]), diff --git a/src/schemas.ts b/src/schemas.ts index 82d5921..2b59709 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -76,33 +76,41 @@ export const McpbUserConfigValuesSchema = z.record( z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]), ); -export const McpbManifestSchema = z.strictObject({ - $schema: z.string().optional(), - mcpb_version: z.string(), - name: z.string(), - display_name: z.string().optional(), - version: z.string(), - description: z.string(), - long_description: z.string().optional(), - author: McpbManifestAuthorSchema, - repository: McpbManifestRepositorySchema.optional(), - homepage: z.string().url().optional(), - documentation: z.string().url().optional(), - support: z.string().url().optional(), - icon: z.string().optional(), - screenshots: z.array(z.string()).optional(), - server: McpbManifestServerSchema, - tools: z.array(McpbManifestToolSchema).optional(), - tools_generated: z.boolean().optional(), - prompts: z.array(McpbManifestPromptSchema).optional(), - prompts_generated: z.boolean().optional(), - keywords: z.array(z.string()).optional(), - license: z.string().optional(), - compatibility: McpbManifestCompatibilitySchema.optional(), - user_config: z - .record(z.string(), McpbUserConfigurationOptionSchema) - .optional(), -}); +export const McpbManifestSchema = z + .strictObject({ + $schema: z.string().optional(), + 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(), + description: z.string(), + long_description: z.string().optional(), + author: McpbManifestAuthorSchema, + repository: McpbManifestRepositorySchema.optional(), + homepage: z.string().url().optional(), + documentation: z.string().url().optional(), + support: z.string().url().optional(), + icon: z.string().optional(), + screenshots: z.array(z.string()).optional(), + server: McpbManifestServerSchema, + tools: z.array(McpbManifestToolSchema).optional(), + tools_generated: z.boolean().optional(), + prompts: z.array(McpbManifestPromptSchema).optional(), + prompts_generated: z.boolean().optional(), + keywords: z.array(z.string()).optional(), + license: z.string().optional(), + compatibility: McpbManifestCompatibilitySchema.optional(), + user_config: z + .record(z.string(), McpbUserConfigurationOptionSchema) + .optional(), + }) + .refine( + (data) => !!(data.dxt_version || data.manifest_version), + { + message: "Either 'dxt_version' (deprecated) or 'manifest_version' must be provided", + } + ); export const McpbSignatureInfoSchema = z.strictObject({ status: z.enum(["signed", "unsigned", "self-signed"]), diff --git a/test/cli.test.ts b/test/cli.test.ts index 142b916..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({ - mcpb_version: "1.0", + 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({ - mcpb_version: "1.0", + 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 e76668c..6461c5a 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -90,7 +90,7 @@ describe("getMcpConfigForManifest", () => { }; const baseManifest: McpbManifest = { - mcpb_version: "1.0.0", + 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 = { - mcpb_version: "1.0.0", + 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 bf96951..68730ce 100644 --- a/test/init.test.ts +++ b/test/init.test.ts @@ -217,7 +217,7 @@ describe("init functions", () => { ); expect(manifest).toEqual({ - mcpb_version: "0.1", + manifest_version: "0.1", name: "test-extension", version: "1.0.0", description: "Test description", @@ -303,7 +303,7 @@ describe("init functions", () => { ); expect(manifest).toEqual({ - mcpb_version: "0.1", + 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 de8d9c4..ccfcd3a 100644 --- a/test/invalid-manifest.json +++ b/test/invalid-manifest.json @@ -1,5 +1,5 @@ { - "mcpb_version": "1.0", + "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 b85cdeb..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 = { - mcpb_version: "1.0", + 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 = { - mcpb_version: "1.0", + manifest_version: "1.0", name: "test", version: "1.0.0", description: "Test", diff --git a/test/valid-manifest.json b/test/valid-manifest.json index feac8be..a91e78f 100644 --- a/test/valid-manifest.json +++ b/test/valid-manifest.json @@ -1,5 +1,5 @@ { - "mcpb_version": "1.0", + "manifest_version": "1.0", "name": "test-extension", "display_name": "Test Extension", "version": "1.0.0",