From a43769d94bedd11336cdbfa69a15aa32de1999fd Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:24:39 -0700 Subject: [PATCH 01/19] feat: restructure schemas into versioned folders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move schemas.ts and schemas-loose.ts into separate versioned folders - Create schemas/0.1.ts and schemas/0.2.ts for strict validation - Create schemas_loose/0.1.ts and schemas_loose/0.2.ts for loose validation - Add index files to export all historical schema versions - Update all imports to use schemas/0.2.ts - Enforce exact version values using z.literal() for both v0.1 and v0.2 - Remove dxt_version support from v0.2 schemas - Remove all passthrough() from v0.2 strict schemas - Validate privacy_policies as URLs in v0.2 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/browser.ts | 2 +- src/cli.ts | 2 +- src/index.ts | 2 +- src/node.ts | 2 +- src/node/validate.ts | 4 +- src/{schemas.ts => schemas/0.1.ts} | 0 src/{schemas-loose.ts => schemas/0.2.ts} | 0 src/schemas/index.ts | 2 + src/schemas_loose/0.1.ts | 120 +++++++++++++++++++++++ src/schemas_loose/0.2.ts | 116 ++++++++++++++++++++++ src/schemas_loose/index.ts | 2 + src/types.ts | 2 +- 12 files changed, 247 insertions(+), 7 deletions(-) rename src/{schemas.ts => schemas/0.1.ts} (100%) rename src/{schemas-loose.ts => schemas/0.2.ts} (100%) create mode 100644 src/schemas/index.ts create mode 100644 src/schemas_loose/0.1.ts create mode 100644 src/schemas_loose/0.2.ts create mode 100644 src/schemas_loose/index.ts diff --git a/src/browser.ts b/src/browser.ts index c4fd89a..df70301 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -1,4 +1,4 @@ // Browser-compatible exports -export * from "./schemas.js"; +export * from "./schemas/0.2.js"; export * from "./shared/config.js"; export * from "./types.js"; diff --git a/src/cli.ts b/src/cli.ts index 45780f9..2562c75 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -3,7 +3,7 @@ export * from "./cli/init.js"; export * from "./cli/pack.js"; // Include all shared exports -export * from "./schemas.js"; +export * from "./schemas/0.2.js"; export * from "./shared/config.js"; export * from "./types.js"; diff --git a/src/index.ts b/src/index.ts index eea22d7..2250ba3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,6 @@ export * from "./cli/unpack.js"; export * from "./node/files.js"; export * from "./node/sign.js"; export * from "./node/validate.js"; -export * from "./schemas.js"; +export * from "./schemas/0.2.js"; export * from "./shared/config.js"; export * from "./types.js"; diff --git a/src/node.ts b/src/node.ts index 3af29fb..2598be8 100644 --- a/src/node.ts +++ b/src/node.ts @@ -4,6 +4,6 @@ export * from "./node/sign.js"; export * from "./node/validate.js"; // Include all shared exports -export * from "./schemas.js"; +export * from "./schemas/0.2.js"; export * from "./shared/config.js"; export * from "./types.js"; diff --git a/src/node/validate.ts b/src/node/validate.ts index 2f86e5e..9e3340d 100644 --- a/src/node/validate.ts +++ b/src/node/validate.ts @@ -6,8 +6,8 @@ import { join, resolve } from "path"; import prettyBytes from "pretty-bytes"; import { unpackExtension } from "../cli/unpack.js"; -import { McpbManifestSchema } from "../schemas.js"; -import { McpbManifestSchema as LooseMcpbManifestSchema } from "../schemas-loose.js"; +import { McpbManifestSchema } from "../schemas/0.2.js"; +import { McpbManifestSchema as LooseMcpbManifestSchema } from "../schemas_loose/0.2.js"; export function validateManifest(inputPath: string): boolean { try { diff --git a/src/schemas.ts b/src/schemas/0.1.ts similarity index 100% rename from src/schemas.ts rename to src/schemas/0.1.ts diff --git a/src/schemas-loose.ts b/src/schemas/0.2.ts similarity index 100% rename from src/schemas-loose.ts rename to src/schemas/0.2.ts diff --git a/src/schemas/index.ts b/src/schemas/index.ts new file mode 100644 index 0000000..16bf78f --- /dev/null +++ b/src/schemas/index.ts @@ -0,0 +1,2 @@ +export * as v0_1 from "./0.1.js"; +export * as v0_2 from "./0.2.js"; \ No newline at end of file diff --git a/src/schemas_loose/0.1.ts b/src/schemas_loose/0.1.ts new file mode 100644 index 0000000..459a1f0 --- /dev/null +++ b/src/schemas_loose/0.1.ts @@ -0,0 +1,120 @@ +import * as z from "zod"; + +export const McpServerConfigSchema = z.object({ + command: z.string(), + args: z.array(z.string()).optional(), + env: z.record(z.string(), z.string()).optional(), +}); + +export const McpbManifestAuthorSchema = z.object({ + name: z.string(), + email: z.string().email().optional(), + url: z.string().url().optional(), +}); + +export const McpbManifestRepositorySchema = z.object({ + type: z.string(), + url: z.string().url(), +}); + +export const McpbManifestPlatformOverrideSchema = + McpServerConfigSchema.partial(); + +export const McpbManifestMcpConfigSchema = McpServerConfigSchema.extend({ + platform_overrides: z + .record(z.string(), McpbManifestPlatformOverrideSchema) + .optional(), +}); + +export const McpbManifestServerSchema = z.object({ + type: z.enum(["python", "node", "binary"]), + entry_point: z.string(), + mcp_config: McpbManifestMcpConfigSchema, +}); + +export const McpbManifestCompatibilitySchema = z + .object({ + claude_desktop: z.string().optional(), + platforms: z.array(z.enum(["darwin", "win32", "linux"])).optional(), + runtimes: z + .object({ + python: z.string().optional(), + node: z.string().optional(), + }) + .optional(), + }) + .passthrough(); + +export const McpbManifestToolSchema = z.object({ + name: z.string(), + description: z.string().optional(), +}); + +export const McpbManifestPromptSchema = z.object({ + name: z.string(), + description: z.string().optional(), + arguments: z.array(z.string()).optional(), + text: z.string(), +}); + +export const McpbUserConfigurationOptionSchema = z.object({ + type: z.enum(["string", "number", "boolean", "directory", "file"]), + title: z.string(), + description: z.string(), + required: z.boolean().optional(), + default: z + .union([z.string(), z.number(), z.boolean(), z.array(z.string())]) + .optional(), + multiple: z.boolean().optional(), + sensitive: z.boolean().optional(), + min: z.number().optional(), + max: z.number().optional(), +}); + +export const McpbUserConfigValuesSchema = z.record( + z.string(), + z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]), +); + +export const McpbManifestSchema = z + .object({ + $schema: z.string().optional(), + dxt_version: z.literal("0.1").optional(), + manifest_version: z.literal("0.1").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.object({ + status: z.enum(["signed", "unsigned", "self-signed"]), + publisher: z.string().optional(), + issuer: z.string().optional(), + valid_from: z.string().optional(), + valid_to: z.string().optional(), + fingerprint: z.string().optional(), +}); diff --git a/src/schemas_loose/0.2.ts b/src/schemas_loose/0.2.ts new file mode 100644 index 0000000..18efe59 --- /dev/null +++ b/src/schemas_loose/0.2.ts @@ -0,0 +1,116 @@ +import * as z from "zod"; + +export const McpServerConfigSchema = z.object({ + command: z.string(), + args: z.array(z.string()).optional(), + env: z.record(z.string(), z.string()).optional(), +}); + +export const McpbManifestAuthorSchema = z.object({ + name: z.string(), + email: z.string().email().optional(), + url: z.string().url().optional(), +}); + +export const McpbManifestRepositorySchema = z.object({ + type: z.string(), + url: z.string().url(), +}); + +export const McpbManifestPlatformOverrideSchema = + McpServerConfigSchema.partial(); + +export const McpbManifestMcpConfigSchema = McpServerConfigSchema.extend({ + platform_overrides: z + .record(z.string(), McpbManifestPlatformOverrideSchema) + .optional(), +}); + +export const McpbManifestServerSchema = z.object({ + type: z.enum(["python", "node", "binary"]), + entry_point: z.string(), + mcp_config: McpbManifestMcpConfigSchema, +}); + +export const McpbManifestCompatibilitySchema = z + .object({ + claude_desktop: z.string().optional(), + platforms: z.array(z.enum(["darwin", "win32", "linux"])).optional(), + runtimes: z + .object({ + python: z.string().optional(), + node: z.string().optional(), + }) + .optional(), + }) + .passthrough(); + +export const McpbManifestToolSchema = z.object({ + name: z.string(), + description: z.string().optional(), +}); + +export const McpbManifestPromptSchema = z.object({ + name: z.string(), + description: z.string().optional(), + arguments: z.array(z.string()).optional(), + text: z.string(), +}); + +export const McpbUserConfigurationOptionSchema = z.object({ + type: z.enum(["string", "number", "boolean", "directory", "file"]), + title: z.string(), + description: z.string(), + required: z.boolean().optional(), + default: z + .union([z.string(), z.number(), z.boolean(), z.array(z.string())]) + .optional(), + multiple: z.boolean().optional(), + sensitive: z.boolean().optional(), + min: z.number().optional(), + max: z.number().optional(), +}); + +export const McpbUserConfigValuesSchema = z.record( + z.string(), + z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]), +); + +export const McpbManifestSchema = z + .object({ + $schema: z.string().optional(), + manifest_version: z.literal("0.2"), + 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 McpbSignatureInfoSchema = z.object({ + status: z.enum(["signed", "unsigned", "self-signed"]), + publisher: z.string().optional(), + issuer: z.string().optional(), + valid_from: z.string().optional(), + valid_to: z.string().optional(), + fingerprint: z.string().optional(), +}); diff --git a/src/schemas_loose/index.ts b/src/schemas_loose/index.ts new file mode 100644 index 0000000..16bf78f --- /dev/null +++ b/src/schemas_loose/index.ts @@ -0,0 +1,2 @@ +export * as v0_1 from "./0.1.js"; +export * as v0_2 from "./0.2.js"; \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index edd3f8c..7a82867 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,7 +14,7 @@ import type { McpbUserConfigurationOptionSchema, McpbUserConfigValuesSchema, McpServerConfigSchema, -} from "./schemas.js"; +} from "./schemas/0.2.js"; export type McpServerConfig = z.infer; From 8e2ec665640564a2e7cc0345a89cac25bab56c25 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:34:12 -0700 Subject: [PATCH 02/19] fix: add privacy_policies and passthrough to loose schema v0.2 --- src/schemas_loose/0.2.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/schemas_loose/0.2.ts b/src/schemas_loose/0.2.ts index 18efe59..ccc1cd7 100644 --- a/src/schemas_loose/0.2.ts +++ b/src/schemas_loose/0.2.ts @@ -99,12 +99,13 @@ export const McpbManifestSchema = z prompts_generated: z.boolean().optional(), keywords: z.array(z.string()).optional(), license: z.string().optional(), + privacy_policies: z.array(z.string().url()).optional(), compatibility: McpbManifestCompatibilitySchema.optional(), user_config: z .record(z.string(), McpbUserConfigurationOptionSchema) .optional(), }) -; + .passthrough(); export const McpbSignatureInfoSchema = z.object({ status: z.enum(["signed", "unsigned", "self-signed"]), From 2e9e70c5ff1b7a3f07697965419fe1f48b0920d8 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:43:02 -0700 Subject: [PATCH 03/19] fix: update schema imports to versioned paths --- src/cli/init.ts | 2 +- src/cli/pack.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/init.ts b/src/cli/init.ts index 5c16885..1a390fa 100644 --- a/src/cli/init.ts +++ b/src/cli/init.ts @@ -2,7 +2,7 @@ import { confirm, input, select } from "@inquirer/prompts"; import { existsSync, readFileSync, writeFileSync } from "fs"; import { basename, join, resolve } from "path"; -import { CURRENT_MANIFEST_VERSION } from "../schemas.js"; +import { CURRENT_MANIFEST_VERSION } from "../schemas/0.2.js"; import type { McpbManifest } from "../types.js"; interface PackageJson { diff --git a/src/cli/pack.ts b/src/cli/pack.ts index 4e3c670..acf136d 100644 --- a/src/cli/pack.ts +++ b/src/cli/pack.ts @@ -13,7 +13,7 @@ import { basename, join, relative, resolve, sep } from "path"; import { getAllFilesWithCount, readMcpbIgnorePatterns } from "../node/files.js"; import { validateManifest } from "../node/validate.js"; -import { CURRENT_MANIFEST_VERSION, McpbManifestSchema } from "../schemas.js"; +import { CURRENT_MANIFEST_VERSION, McpbManifestSchema } from "../schemas/0.2.js"; import { getLogger } from "../shared/log.js"; import { initExtension } from "./init.js"; From 3d9c9669511ff08283666f50d718ad2e2234cee2 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:45:19 -0700 Subject: [PATCH 04/19] fix: rename CURRENT_MANIFEST_VERSION to MANIFEST_VERSION and set correct versions --- src/cli/init.ts | 4 ++-- src/cli/pack.ts | 8 ++++---- src/schemas/0.1.ts | 2 +- src/schemas/0.2.ts | 4 +++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/cli/init.ts b/src/cli/init.ts index 1a390fa..0d2df69 100644 --- a/src/cli/init.ts +++ b/src/cli/init.ts @@ -2,7 +2,7 @@ import { confirm, input, select } from "@inquirer/prompts"; import { existsSync, readFileSync, writeFileSync } from "fs"; import { basename, join, resolve } from "path"; -import { CURRENT_MANIFEST_VERSION } from "../schemas/0.2.js"; +import { MANIFEST_VERSION } from "../schemas/0.2.js"; import type { McpbManifest } from "../types.js"; interface PackageJson { @@ -774,7 +774,7 @@ export function buildManifest( const { keywords, license, repository } = optionalFields; return { - manifest_version: CURRENT_MANIFEST_VERSION, + manifest_version: MANIFEST_VERSION, name, ...(displayName && displayName !== name ? { display_name: displayName } diff --git a/src/cli/pack.ts b/src/cli/pack.ts index acf136d..30ce068 100644 --- a/src/cli/pack.ts +++ b/src/cli/pack.ts @@ -13,7 +13,7 @@ import { basename, join, relative, resolve, sep } from "path"; import { getAllFilesWithCount, readMcpbIgnorePatterns } from "../node/files.js"; import { validateManifest } from "../node/validate.js"; -import { CURRENT_MANIFEST_VERSION, McpbManifestSchema } from "../schemas/0.2.js"; +import { MANIFEST_VERSION, McpbManifestSchema } from "../schemas/0.2.js"; import { getLogger } from "../shared/log.js"; import { initExtension } from "./init.js"; @@ -102,12 +102,12 @@ export async function packExtension({ } const manifestVersion = manifest.manifest_version || manifest.dxt_version; - if (manifestVersion !== CURRENT_MANIFEST_VERSION) { + if (manifestVersion !== MANIFEST_VERSION) { logger.error( - `ERROR: Manifest version mismatch. Expected "${CURRENT_MANIFEST_VERSION}", found "${manifestVersion}"`, + `ERROR: Manifest version mismatch. Expected "${MANIFEST_VERSION}", found "${manifestVersion}"`, ); logger.error( - ` Please update the manifest_version in your manifest.json to "${CURRENT_MANIFEST_VERSION}"`, + ` Please update the manifest_version in your manifest.json to "${MANIFEST_VERSION}"`, ); return false; } diff --git a/src/schemas/0.1.ts b/src/schemas/0.1.ts index 1f7ece2..f478c3e 100644 --- a/src/schemas/0.1.ts +++ b/src/schemas/0.1.ts @@ -1,6 +1,6 @@ import * as z from "zod"; -export const CURRENT_MANIFEST_VERSION = "0.2"; +export const MANIFEST_VERSION = "0.1"; export const McpServerConfigSchema = z.strictObject({ command: z.string(), diff --git a/src/schemas/0.2.ts b/src/schemas/0.2.ts index e44ba2a..86332bd 100644 --- a/src/schemas/0.2.ts +++ b/src/schemas/0.2.ts @@ -1,6 +1,8 @@ import * as z from "zod"; -export const McpServerConfigSchema = z.object({ +export const MANIFEST_VERSION = "0.2"; + +export const McpServerConfigSchema = z.strictObject({ command: z.string(), args: z.array(z.string()).optional(), env: z.record(z.string(), z.string()).optional(), From 16f173824cf603f726371a6fb8e6dff94e6da129 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:48:52 -0700 Subject: [PATCH 05/19] fix: correct strict schemas for v0.1 and v0.2 --- src/schemas/0.1.ts | 30 ++++++-------- src/schemas/0.2.ts | 100 ++++++++++++++++++++------------------------- 2 files changed, 57 insertions(+), 73 deletions(-) diff --git a/src/schemas/0.1.ts b/src/schemas/0.1.ts index f478c3e..093a0ed 100644 --- a/src/schemas/0.1.ts +++ b/src/schemas/0.1.ts @@ -34,18 +34,16 @@ export const McpbManifestServerSchema = z.strictObject({ mcp_config: McpbManifestMcpConfigSchema, }); -export const McpbManifestCompatibilitySchema = z - .strictObject({ - claude_desktop: z.string().optional(), - platforms: z.array(z.enum(["darwin", "win32", "linux"])).optional(), - runtimes: z - .strictObject({ - python: z.string().optional(), - node: z.string().optional(), - }) - .optional(), - }) - .passthrough(); +export const McpbManifestCompatibilitySchema = z.strictObject({ + claude_desktop: z.string().optional(), + platforms: z.array(z.enum(["darwin", "win32", "linux"])).optional(), + runtimes: z + .strictObject({ + python: z.string().optional(), + node: z.string().optional(), + }) + .optional(), +}); export const McpbManifestToolSchema = z.strictObject({ name: z.string(), @@ -81,11 +79,8 @@ export const McpbUserConfigValuesSchema = z.record( 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(), + dxt_version: z.literal("0.1").optional(), + manifest_version: z.literal("0.1").optional(), name: z.string(), display_name: z.string().optional(), version: z.string(), @@ -105,7 +100,6 @@ export const McpbManifestSchema = z prompts_generated: z.boolean().optional(), keywords: z.array(z.string()).optional(), license: z.string().optional(), - privacy_policies: z.array(z.string()).optional(), compatibility: McpbManifestCompatibilitySchema.optional(), user_config: z .record(z.string(), McpbUserConfigurationOptionSchema) diff --git a/src/schemas/0.2.ts b/src/schemas/0.2.ts index 86332bd..1669ff9 100644 --- a/src/schemas/0.2.ts +++ b/src/schemas/0.2.ts @@ -8,13 +8,13 @@ export const McpServerConfigSchema = z.strictObject({ env: z.record(z.string(), z.string()).optional(), }); -export const McpbManifestAuthorSchema = z.object({ +export const McpbManifestAuthorSchema = z.strictObject({ name: z.string(), email: z.string().email().optional(), url: z.string().url().optional(), }); -export const McpbManifestRepositorySchema = z.object({ +export const McpbManifestRepositorySchema = z.strictObject({ type: z.string(), url: z.string().url(), }); @@ -28,38 +28,36 @@ export const McpbManifestMcpConfigSchema = McpServerConfigSchema.extend({ .optional(), }); -export const McpbManifestServerSchema = z.object({ +export const McpbManifestServerSchema = z.strictObject({ type: z.enum(["python", "node", "binary"]), entry_point: z.string(), mcp_config: McpbManifestMcpConfigSchema, }); -export const McpbManifestCompatibilitySchema = z - .object({ - claude_desktop: z.string().optional(), - platforms: z.array(z.enum(["darwin", "win32", "linux"])).optional(), - runtimes: z - .object({ - python: z.string().optional(), - node: z.string().optional(), - }) - .optional(), - }) - .passthrough(); +export const McpbManifestCompatibilitySchema = z.strictObject({ + claude_desktop: z.string().optional(), + platforms: z.array(z.enum(["darwin", "win32", "linux"])).optional(), + runtimes: z + .strictObject({ + python: z.string().optional(), + node: z.string().optional(), + }) + .optional(), +}); -export const McpbManifestToolSchema = z.object({ +export const McpbManifestToolSchema = z.strictObject({ name: z.string(), description: z.string().optional(), }); -export const McpbManifestPromptSchema = z.object({ +export const McpbManifestPromptSchema = z.strictObject({ name: z.string(), description: z.string().optional(), arguments: z.array(z.string()).optional(), text: z.string(), }); -export const McpbUserConfigurationOptionSchema = z.object({ +export const McpbUserConfigurationOptionSchema = z.strictObject({ type: z.enum(["string", "number", "boolean", "directory", "file"]), title: z.string(), description: z.string(), @@ -78,44 +76,36 @@ 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(), - 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 McpbManifestSchema = z.strictObject({ + $schema: z.string().optional(), + manifest_version: z.literal("0.2"), + 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(), + privacy_policies: z.array(z.string().url()).optional(), + compatibility: McpbManifestCompatibilitySchema.optional(), + user_config: z + .record(z.string(), McpbUserConfigurationOptionSchema) + .optional(), +}); -export const McpbSignatureInfoSchema = z.object({ +export const McpbSignatureInfoSchema = z.strictObject({ status: z.enum(["signed", "unsigned", "self-signed"]), publisher: z.string().optional(), issuer: z.string().optional(), From 9f078c6163a999227117a425cb956bd6e2f6d8cf Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:50:16 -0700 Subject: [PATCH 06/19] fix: add deprecation notice to dxt_version in v0.1 schemas --- src/schemas/0.1.ts | 2 +- src/schemas_loose/0.1.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/schemas/0.1.ts b/src/schemas/0.1.ts index 093a0ed..4e2a545 100644 --- a/src/schemas/0.1.ts +++ b/src/schemas/0.1.ts @@ -79,7 +79,7 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .strictObject({ $schema: z.string().optional(), - dxt_version: z.literal("0.1").optional(), + dxt_version: z.literal("0.1").optional().describe("@deprecated Use manifest_version instead"), manifest_version: z.literal("0.1").optional(), name: z.string(), display_name: z.string().optional(), diff --git a/src/schemas_loose/0.1.ts b/src/schemas_loose/0.1.ts index 459a1f0..64a1dd5 100644 --- a/src/schemas_loose/0.1.ts +++ b/src/schemas_loose/0.1.ts @@ -79,7 +79,7 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .object({ $schema: z.string().optional(), - dxt_version: z.literal("0.1").optional(), + dxt_version: z.literal("0.1").optional().describe("@deprecated Use manifest_version instead"), manifest_version: z.literal("0.1").optional(), name: z.string(), display_name: z.string().optional(), From 336e878252537e14da07a1110d8ac6f7a4825bcf Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:51:40 -0700 Subject: [PATCH 07/19] fix: add dxt_version support to v0.2 schemas with deprecation notice --- src/schemas/0.2.ts | 14 ++++++++++---- src/schemas_loose/0.2.ts | 9 +++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/schemas/0.2.ts b/src/schemas/0.2.ts index 1669ff9..3f41d1d 100644 --- a/src/schemas/0.2.ts +++ b/src/schemas/0.2.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.strictObject({ - $schema: z.string().optional(), - manifest_version: z.literal("0.2"), +export const McpbManifestSchema = z + .strictObject({ + $schema: z.string().optional(), + dxt_version: z.literal("0.2").optional().describe("@deprecated Use manifest_version instead"), + manifest_version: z.literal("0.2").optional(), name: z.string(), display_name: z.string().optional(), version: z.string(), @@ -103,7 +105,11 @@ export const McpbManifestSchema = z.strictObject({ 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/src/schemas_loose/0.2.ts b/src/schemas_loose/0.2.ts index ccc1cd7..7d6834b 100644 --- a/src/schemas_loose/0.2.ts +++ b/src/schemas_loose/0.2.ts @@ -79,7 +79,8 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .object({ $schema: z.string().optional(), - manifest_version: z.literal("0.2"), + dxt_version: z.literal("0.2").optional().describe("@deprecated Use manifest_version instead"), + manifest_version: z.literal("0.2").optional(), name: z.string(), display_name: z.string().optional(), version: z.string(), @@ -105,7 +106,11 @@ export const McpbManifestSchema = z .record(z.string(), McpbUserConfigurationOptionSchema) .optional(), }) - .passthrough(); + .passthrough() + .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"]), From 6bfd100b60cfd3066f57314739f5ecdc7808c96d Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:53:13 -0700 Subject: [PATCH 08/19] feat: export CURRENT_MANIFEST_VERSION from schemas index --- src/schemas/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/schemas/index.ts b/src/schemas/index.ts index 16bf78f..beb8b97 100644 --- a/src/schemas/index.ts +++ b/src/schemas/index.ts @@ -1,2 +1,4 @@ export * as v0_1 from "./0.1.js"; -export * as v0_2 from "./0.2.js"; \ No newline at end of file +export * as v0_2 from "./0.2.js"; + +export { MANIFEST_VERSION as CURRENT_MANIFEST_VERSION } from "./0.2.js"; \ No newline at end of file From fe733e34501254e20020ebe0e0ea3f4ad1be3f14 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:54:38 -0700 Subject: [PATCH 09/19] refactor: use MANIFEST_VERSION variable in z.literal() instead of hardcoded strings --- src/schemas/0.1.ts | 4 ++-- src/schemas/0.2.ts | 4 ++-- src/schemas_loose/0.1.ts | 6 ++++-- src/schemas_loose/0.2.ts | 6 ++++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/schemas/0.1.ts b/src/schemas/0.1.ts index 4e2a545..ef54ce3 100644 --- a/src/schemas/0.1.ts +++ b/src/schemas/0.1.ts @@ -79,8 +79,8 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .strictObject({ $schema: z.string().optional(), - dxt_version: z.literal("0.1").optional().describe("@deprecated Use manifest_version instead"), - manifest_version: z.literal("0.1").optional(), + dxt_version: z.literal(MANIFEST_VERSION).optional().describe("@deprecated Use manifest_version instead"), + manifest_version: z.literal(MANIFEST_VERSION).optional(), name: z.string(), display_name: z.string().optional(), version: z.string(), diff --git a/src/schemas/0.2.ts b/src/schemas/0.2.ts index 3f41d1d..844efe8 100644 --- a/src/schemas/0.2.ts +++ b/src/schemas/0.2.ts @@ -79,8 +79,8 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .strictObject({ $schema: z.string().optional(), - dxt_version: z.literal("0.2").optional().describe("@deprecated Use manifest_version instead"), - manifest_version: z.literal("0.2").optional(), + dxt_version: z.literal(MANIFEST_VERSION).optional().describe("@deprecated Use manifest_version instead"), + manifest_version: z.literal(MANIFEST_VERSION).optional(), name: z.string(), display_name: z.string().optional(), version: z.string(), diff --git a/src/schemas_loose/0.1.ts b/src/schemas_loose/0.1.ts index 64a1dd5..9b37647 100644 --- a/src/schemas_loose/0.1.ts +++ b/src/schemas_loose/0.1.ts @@ -1,5 +1,7 @@ import * as z from "zod"; +export const MANIFEST_VERSION = "0.1"; + export const McpServerConfigSchema = z.object({ command: z.string(), args: z.array(z.string()).optional(), @@ -79,8 +81,8 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .object({ $schema: z.string().optional(), - dxt_version: z.literal("0.1").optional().describe("@deprecated Use manifest_version instead"), - manifest_version: z.literal("0.1").optional(), + dxt_version: z.literal(MANIFEST_VERSION).optional().describe("@deprecated Use manifest_version instead"), + manifest_version: z.literal(MANIFEST_VERSION).optional(), name: z.string(), display_name: z.string().optional(), version: z.string(), diff --git a/src/schemas_loose/0.2.ts b/src/schemas_loose/0.2.ts index 7d6834b..062b0e6 100644 --- a/src/schemas_loose/0.2.ts +++ b/src/schemas_loose/0.2.ts @@ -1,5 +1,7 @@ import * as z from "zod"; +export const MANIFEST_VERSION = "0.2"; + export const McpServerConfigSchema = z.object({ command: z.string(), args: z.array(z.string()).optional(), @@ -79,8 +81,8 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .object({ $schema: z.string().optional(), - dxt_version: z.literal("0.2").optional().describe("@deprecated Use manifest_version instead"), - manifest_version: z.literal("0.2").optional(), + dxt_version: z.literal(MANIFEST_VERSION).optional().describe("@deprecated Use manifest_version instead"), + manifest_version: z.literal(MANIFEST_VERSION).optional(), name: z.string(), display_name: z.string().optional(), version: z.string(), From 3a0d4a86352ec90e4ed4cc9e014339f0df00da25 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:57:19 -0700 Subject: [PATCH 10/19] feat: create schema version map with CURRENT_MANIFEST_SCHEMA selector --- src/cli/init.ts | 4 ++-- src/cli/pack.ts | 4 ++-- src/node/validate.ts | 7 +++---- src/shared/constants.ts | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 src/shared/constants.ts diff --git a/src/cli/init.ts b/src/cli/init.ts index 0d2df69..17b95a9 100644 --- a/src/cli/init.ts +++ b/src/cli/init.ts @@ -2,7 +2,7 @@ import { confirm, input, select } from "@inquirer/prompts"; import { existsSync, readFileSync, writeFileSync } from "fs"; import { basename, join, resolve } from "path"; -import { MANIFEST_VERSION } from "../schemas/0.2.js"; +import { CURRENT_MANIFEST_VERSION } from "../shared/constants.js"; import type { McpbManifest } from "../types.js"; interface PackageJson { @@ -774,7 +774,7 @@ export function buildManifest( const { keywords, license, repository } = optionalFields; return { - manifest_version: MANIFEST_VERSION, + manifest_version: CURRENT_MANIFEST_VERSION, name, ...(displayName && displayName !== name ? { display_name: displayName } diff --git a/src/cli/pack.ts b/src/cli/pack.ts index 30ce068..d7cb6f5 100644 --- a/src/cli/pack.ts +++ b/src/cli/pack.ts @@ -13,7 +13,7 @@ import { basename, join, relative, resolve, sep } from "path"; import { getAllFilesWithCount, readMcpbIgnorePatterns } from "../node/files.js"; import { validateManifest } from "../node/validate.js"; -import { MANIFEST_VERSION, McpbManifestSchema } from "../schemas/0.2.js"; +import { CURRENT_MANIFEST_VERSION, CURRENT_MANIFEST_SCHEMA } from "../shared/constants.js"; import { getLogger } from "../shared/log.js"; import { initExtension } from "./init.js"; @@ -92,7 +92,7 @@ export async function packExtension({ try { const manifestContent = readFileSync(manifestPath, "utf-8"); const manifestData = JSON.parse(manifestContent); - manifest = McpbManifestSchema.parse(manifestData); + manifest = CURRENT_MANIFEST_SCHEMA.parse(manifestData); } catch (error) { logger.error("ERROR: Failed to parse manifest.json"); if (error instanceof Error) { diff --git a/src/node/validate.ts b/src/node/validate.ts index 9e3340d..3be269e 100644 --- a/src/node/validate.ts +++ b/src/node/validate.ts @@ -6,8 +6,7 @@ import { join, resolve } from "path"; import prettyBytes from "pretty-bytes"; import { unpackExtension } from "../cli/unpack.js"; -import { McpbManifestSchema } from "../schemas/0.2.js"; -import { McpbManifestSchema as LooseMcpbManifestSchema } from "../schemas_loose/0.2.js"; +import { CURRENT_MANIFEST_SCHEMA, CURRENT_MANIFEST_SCHEMA_LOOSE } from "../shared/constants.js"; export function validateManifest(inputPath: string): boolean { try { @@ -22,7 +21,7 @@ export function validateManifest(inputPath: string): boolean { const manifestContent = readFileSync(manifestPath, "utf-8"); const manifestData = JSON.parse(manifestContent); - const result = McpbManifestSchema.safeParse(manifestData); + const result = CURRENT_MANIFEST_SCHEMA.safeParse(manifestData); if (result.success) { console.log("Manifest schema validation passes!"); @@ -72,7 +71,7 @@ export async function cleanMcpb(inputPath: string) { const manifestPath = resolve(unpackPath, "manifest.json"); const originalManifest = await fs.readFile(manifestPath, "utf-8"); const manifestData = JSON.parse(originalManifest); - const result = LooseMcpbManifestSchema.safeParse(manifestData); + const result = CURRENT_MANIFEST_SCHEMA_LOOSE.safeParse(manifestData); if (!result.success) { throw new Error( diff --git a/src/shared/constants.ts b/src/shared/constants.ts new file mode 100644 index 0000000..f1c1359 --- /dev/null +++ b/src/shared/constants.ts @@ -0,0 +1,35 @@ +import { McpbManifestSchema as ManifestSchemaV0_1 } from "../schemas/0.1.js"; +import { McpbManifestSchema as ManifestSchemaV0_2 } from "../schemas/0.2.js"; +import { McpbManifestSchema as LooseManifestSchemaV0_1 } from "../schemas_loose/0.1.js"; +import { McpbManifestSchema as LooseManifestSchemaV0_2 } from "../schemas_loose/0.2.js"; + +/** + * Current manifest version - the version that new manifests should use + */ +export const CURRENT_MANIFEST_VERSION = "0.2" as const; + +/** + * Map of manifest versions to their strict schemas + */ +export const MANIFEST_SCHEMAS = { + "0.1": ManifestSchemaV0_1, + "0.2": ManifestSchemaV0_2, +} as const; + +/** + * Map of manifest versions to their loose schemas (with passthrough) + */ +export const MANIFEST_SCHEMAS_LOOSE = { + "0.1": LooseManifestSchemaV0_1, + "0.2": LooseManifestSchemaV0_2, +} as const; + +/** + * Get the current manifest schema based on CURRENT_MANIFEST_VERSION + */ +export const CURRENT_MANIFEST_SCHEMA = MANIFEST_SCHEMAS[CURRENT_MANIFEST_VERSION]; + +/** + * Get the current loose manifest schema based on CURRENT_MANIFEST_VERSION + */ +export const CURRENT_MANIFEST_SCHEMA_LOOSE = MANIFEST_SCHEMAS_LOOSE[CURRENT_MANIFEST_VERSION]; From 76b79551ab54930756338da54d0c0d5498b1ac9b Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 13:58:45 -0700 Subject: [PATCH 11/19] fix: use CURRENT_MANIFEST_VERSION in pack.ts version check --- src/cli/pack.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli/pack.ts b/src/cli/pack.ts index d7cb6f5..5b9dc6b 100644 --- a/src/cli/pack.ts +++ b/src/cli/pack.ts @@ -102,12 +102,12 @@ export async function packExtension({ } const manifestVersion = manifest.manifest_version || manifest.dxt_version; - if (manifestVersion !== MANIFEST_VERSION) { + if (manifestVersion !== CURRENT_MANIFEST_VERSION) { logger.error( - `ERROR: Manifest version mismatch. Expected "${MANIFEST_VERSION}", found "${manifestVersion}"`, + `ERROR: Manifest version mismatch. Expected "${CURRENT_MANIFEST_VERSION}", found "${manifestVersion}"`, ); logger.error( - ` Please update the manifest_version in your manifest.json to "${MANIFEST_VERSION}"`, + ` Please update the manifest_version in your manifest.json to "${CURRENT_MANIFEST_VERSION}"`, ); return false; } From ccb19277c462184906ae9619641738c7a4539f72 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 14:03:03 -0700 Subject: [PATCH 12/19] feat: export constants from package entrypoints --- src/browser.ts | 1 + src/cli.ts | 1 + src/index.ts | 1 + src/node.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/src/browser.ts b/src/browser.ts index df70301..ea4aaef 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -1,4 +1,5 @@ // Browser-compatible exports export * from "./schemas/0.2.js"; export * from "./shared/config.js"; +export * from "./shared/constants.js"; export * from "./types.js"; diff --git a/src/cli.ts b/src/cli.ts index 2562c75..4b5a9f0 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -5,6 +5,7 @@ export * from "./cli/pack.js"; // Include all shared exports export * from "./schemas/0.2.js"; export * from "./shared/config.js"; +export * from "./shared/constants.js"; export * from "./types.js"; // Include node exports since CLI needs them diff --git a/src/index.ts b/src/index.ts index 2250ba3..327a96c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,4 +7,5 @@ export * from "./node/sign.js"; export * from "./node/validate.js"; export * from "./schemas/0.2.js"; export * from "./shared/config.js"; +export * from "./shared/constants.js"; export * from "./types.js"; diff --git a/src/node.ts b/src/node.ts index 2598be8..62f4774 100644 --- a/src/node.ts +++ b/src/node.ts @@ -6,4 +6,5 @@ export * from "./node/validate.js"; // Include all shared exports export * from "./schemas/0.2.js"; export * from "./shared/config.js"; +export * from "./shared/constants.js"; export * from "./types.js"; From fefd9e1d2151ebbfd99d71a6a6364210a13d3568 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 14:12:10 -0700 Subject: [PATCH 13/19] fix: add schemas re-export file and update tests to use correct manifest version - Create src/schemas.ts to re-export from schemas/index.ts for test imports - Update test manifests to use manifest_version "0.2" instead of "1.0" or "1.0.0" - Fix import sorting and formatting issues in schema files - Export McpbManifestSchema from schemas/index.ts --- src/cli/pack.ts | 5 +++- src/node/validate.ts | 5 +++- src/schemas.ts | 6 +++++ src/schemas/0.1.ts | 5 +++- src/schemas/0.2.ts | 55 ++++++++++++++++++++------------------ src/schemas/index.ts | 6 +++-- src/schemas_loose/0.1.ts | 5 +++- src/schemas_loose/0.2.ts | 5 +++- src/schemas_loose/index.ts | 2 +- src/shared/constants.ts | 6 +++-- test/config.test.ts | 4 +-- test/schemas.test.ts | 4 +-- test/valid-manifest.json | 2 +- 13 files changed, 69 insertions(+), 41 deletions(-) create mode 100644 src/schemas.ts diff --git a/src/cli/pack.ts b/src/cli/pack.ts index 5b9dc6b..0e51d9b 100644 --- a/src/cli/pack.ts +++ b/src/cli/pack.ts @@ -13,7 +13,10 @@ import { basename, join, relative, resolve, sep } from "path"; import { getAllFilesWithCount, readMcpbIgnorePatterns } from "../node/files.js"; import { validateManifest } from "../node/validate.js"; -import { CURRENT_MANIFEST_VERSION, CURRENT_MANIFEST_SCHEMA } from "../shared/constants.js"; +import { + CURRENT_MANIFEST_SCHEMA, + CURRENT_MANIFEST_VERSION, +} from "../shared/constants.js"; import { getLogger } from "../shared/log.js"; import { initExtension } from "./init.js"; diff --git a/src/node/validate.ts b/src/node/validate.ts index 3be269e..5b44189 100644 --- a/src/node/validate.ts +++ b/src/node/validate.ts @@ -6,7 +6,10 @@ import { join, resolve } from "path"; import prettyBytes from "pretty-bytes"; import { unpackExtension } from "../cli/unpack.js"; -import { CURRENT_MANIFEST_SCHEMA, CURRENT_MANIFEST_SCHEMA_LOOSE } from "../shared/constants.js"; +import { + CURRENT_MANIFEST_SCHEMA, + CURRENT_MANIFEST_SCHEMA_LOOSE, +} from "../shared/constants.js"; export function validateManifest(inputPath: string): boolean { try { diff --git a/src/schemas.ts b/src/schemas.ts new file mode 100644 index 0000000..4bf0ea8 --- /dev/null +++ b/src/schemas.ts @@ -0,0 +1,6 @@ +export { + CURRENT_MANIFEST_VERSION, + McpbManifestSchema, + v0_1, + v0_2, +} from "./schemas/index.js"; diff --git a/src/schemas/0.1.ts b/src/schemas/0.1.ts index ef54ce3..9bfa788 100644 --- a/src/schemas/0.1.ts +++ b/src/schemas/0.1.ts @@ -79,7 +79,10 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .strictObject({ $schema: z.string().optional(), - dxt_version: z.literal(MANIFEST_VERSION).optional().describe("@deprecated Use manifest_version instead"), + dxt_version: z + .literal(MANIFEST_VERSION) + .optional() + .describe("@deprecated Use manifest_version instead"), manifest_version: z.literal(MANIFEST_VERSION).optional(), name: z.string(), display_name: z.string().optional(), diff --git a/src/schemas/0.2.ts b/src/schemas/0.2.ts index 844efe8..f5d4d03 100644 --- a/src/schemas/0.2.ts +++ b/src/schemas/0.2.ts @@ -79,33 +79,36 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .strictObject({ $schema: z.string().optional(), - dxt_version: z.literal(MANIFEST_VERSION).optional().describe("@deprecated Use manifest_version instead"), + dxt_version: z + .literal(MANIFEST_VERSION) + .optional() + .describe("@deprecated Use manifest_version instead"), manifest_version: z.literal(MANIFEST_VERSION).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(), - privacy_policies: z.array(z.string().url()).optional(), - compatibility: McpbManifestCompatibilitySchema.optional(), - user_config: z - .record(z.string(), McpbUserConfigurationOptionSchema) - .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(), + privacy_policies: z.array(z.string().url()).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", diff --git a/src/schemas/index.ts b/src/schemas/index.ts index beb8b97..d8599cd 100644 --- a/src/schemas/index.ts +++ b/src/schemas/index.ts @@ -1,4 +1,6 @@ export * as v0_1 from "./0.1.js"; export * as v0_2 from "./0.2.js"; - -export { MANIFEST_VERSION as CURRENT_MANIFEST_VERSION } from "./0.2.js"; \ No newline at end of file +export { + MANIFEST_VERSION as CURRENT_MANIFEST_VERSION, + McpbManifestSchema, +} from "./0.2.js"; diff --git a/src/schemas_loose/0.1.ts b/src/schemas_loose/0.1.ts index 9b37647..fbba24c 100644 --- a/src/schemas_loose/0.1.ts +++ b/src/schemas_loose/0.1.ts @@ -81,7 +81,10 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .object({ $schema: z.string().optional(), - dxt_version: z.literal(MANIFEST_VERSION).optional().describe("@deprecated Use manifest_version instead"), + dxt_version: z + .literal(MANIFEST_VERSION) + .optional() + .describe("@deprecated Use manifest_version instead"), manifest_version: z.literal(MANIFEST_VERSION).optional(), name: z.string(), display_name: z.string().optional(), diff --git a/src/schemas_loose/0.2.ts b/src/schemas_loose/0.2.ts index 062b0e6..7cdbc1a 100644 --- a/src/schemas_loose/0.2.ts +++ b/src/schemas_loose/0.2.ts @@ -81,7 +81,10 @@ export const McpbUserConfigValuesSchema = z.record( export const McpbManifestSchema = z .object({ $schema: z.string().optional(), - dxt_version: z.literal(MANIFEST_VERSION).optional().describe("@deprecated Use manifest_version instead"), + dxt_version: z + .literal(MANIFEST_VERSION) + .optional() + .describe("@deprecated Use manifest_version instead"), manifest_version: z.literal(MANIFEST_VERSION).optional(), name: z.string(), display_name: z.string().optional(), diff --git a/src/schemas_loose/index.ts b/src/schemas_loose/index.ts index 16bf78f..168c457 100644 --- a/src/schemas_loose/index.ts +++ b/src/schemas_loose/index.ts @@ -1,2 +1,2 @@ export * as v0_1 from "./0.1.js"; -export * as v0_2 from "./0.2.js"; \ No newline at end of file +export * as v0_2 from "./0.2.js"; diff --git a/src/shared/constants.ts b/src/shared/constants.ts index f1c1359..8cf0606 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -27,9 +27,11 @@ export const MANIFEST_SCHEMAS_LOOSE = { /** * Get the current manifest schema based on CURRENT_MANIFEST_VERSION */ -export const CURRENT_MANIFEST_SCHEMA = MANIFEST_SCHEMAS[CURRENT_MANIFEST_VERSION]; +export const CURRENT_MANIFEST_SCHEMA = + MANIFEST_SCHEMAS[CURRENT_MANIFEST_VERSION]; /** * Get the current loose manifest schema based on CURRENT_MANIFEST_VERSION */ -export const CURRENT_MANIFEST_SCHEMA_LOOSE = MANIFEST_SCHEMAS_LOOSE[CURRENT_MANIFEST_VERSION]; +export const CURRENT_MANIFEST_SCHEMA_LOOSE = + MANIFEST_SCHEMAS_LOOSE[CURRENT_MANIFEST_VERSION]; diff --git a/test/config.test.ts b/test/config.test.ts index 6461c5a..062c66e 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -90,7 +90,7 @@ describe("getMcpConfigForManifest", () => { }; const baseManifest: McpbManifest = { - manifest_version: "1.0.0", + manifest_version: "0.2", name: "test-extension", version: "1.0.0", description: "Test extension", @@ -305,7 +305,7 @@ describe("getMcpConfigForManifest", () => { describe("hasRequiredConfigMissing", () => { const baseManifest: McpbManifest = { - manifest_version: "1.0.0", + manifest_version: "0.2", name: "test-extension", version: "1.0.0", description: "Test extension", diff --git a/test/schemas.test.ts b/test/schemas.test.ts index a9297d8..71773f0 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 = { - manifest_version: "1.0", + manifest_version: "0.2", name: "full-extension", display_name: "Full Featured Extension", version: "2.0.0", @@ -117,7 +117,7 @@ describe("McpbManifestSchema", () => { serverTypes.forEach((type) => { const manifest = { - manifest_version: "1.0", + manifest_version: "0.2", name: "test", version: "1.0.0", description: "Test", diff --git a/test/valid-manifest.json b/test/valid-manifest.json index a91e78f..c2d121d 100644 --- a/test/valid-manifest.json +++ b/test/valid-manifest.json @@ -1,5 +1,5 @@ { - "manifest_version": "1.0", + "manifest_version": "0.2", "name": "test-extension", "display_name": "Test Extension", "version": "1.0.0", From c4a9500c84eb7d028becf3e2a0878e6e2b0ca7b9 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 14:21:01 -0700 Subject: [PATCH 14/19] feat: add schema helper aliases (latest) - Add schemas/latest.ts and schemas_loose/latest.ts as aliases to current version - Update constants.ts to use latest.ts instead of hardcoded version imports - This makes version updates easier - only need to update latest.ts pointer --- src/schemas/index.ts | 3 ++- src/schemas/latest.ts | 1 + src/schemas_loose/index.ts | 1 + src/schemas_loose/latest.ts | 1 + src/shared/constants.ts | 8 ++++---- 5 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 src/schemas/latest.ts create mode 100644 src/schemas_loose/latest.ts diff --git a/src/schemas/index.ts b/src/schemas/index.ts index d8599cd..427aad4 100644 --- a/src/schemas/index.ts +++ b/src/schemas/index.ts @@ -1,6 +1,7 @@ export * as v0_1 from "./0.1.js"; export * as v0_2 from "./0.2.js"; +export * as latest from "./latest.js"; export { MANIFEST_VERSION as CURRENT_MANIFEST_VERSION, McpbManifestSchema, -} from "./0.2.js"; +} from "./latest.js"; diff --git a/src/schemas/latest.ts b/src/schemas/latest.ts new file mode 100644 index 0000000..79797d0 --- /dev/null +++ b/src/schemas/latest.ts @@ -0,0 +1 @@ +export * from "./0.2.js"; diff --git a/src/schemas_loose/index.ts b/src/schemas_loose/index.ts index 168c457..b58933b 100644 --- a/src/schemas_loose/index.ts +++ b/src/schemas_loose/index.ts @@ -1,2 +1,3 @@ export * as v0_1 from "./0.1.js"; export * as v0_2 from "./0.2.js"; +export * as latest from "./latest.js"; diff --git a/src/schemas_loose/latest.ts b/src/schemas_loose/latest.ts new file mode 100644 index 0000000..79797d0 --- /dev/null +++ b/src/schemas_loose/latest.ts @@ -0,0 +1 @@ +export * from "./0.2.js"; diff --git a/src/shared/constants.ts b/src/shared/constants.ts index 8cf0606..ec7b865 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -1,7 +1,9 @@ import { McpbManifestSchema as ManifestSchemaV0_1 } from "../schemas/0.1.js"; import { McpbManifestSchema as ManifestSchemaV0_2 } from "../schemas/0.2.js"; +import { McpbManifestSchema as CurrentManifestSchema } from "../schemas/latest.js"; import { McpbManifestSchema as LooseManifestSchemaV0_1 } from "../schemas_loose/0.1.js"; import { McpbManifestSchema as LooseManifestSchemaV0_2 } from "../schemas_loose/0.2.js"; +import { McpbManifestSchema as CurrentLooseManifestSchema } from "../schemas_loose/latest.js"; /** * Current manifest version - the version that new manifests should use @@ -27,11 +29,9 @@ export const MANIFEST_SCHEMAS_LOOSE = { /** * Get the current manifest schema based on CURRENT_MANIFEST_VERSION */ -export const CURRENT_MANIFEST_SCHEMA = - MANIFEST_SCHEMAS[CURRENT_MANIFEST_VERSION]; +export const CURRENT_MANIFEST_SCHEMA = CurrentManifestSchema; /** * Get the current loose manifest schema based on CURRENT_MANIFEST_VERSION */ -export const CURRENT_MANIFEST_SCHEMA_LOOSE = - MANIFEST_SCHEMAS_LOOSE[CURRENT_MANIFEST_VERSION]; +export const CURRENT_MANIFEST_SCHEMA_LOOSE = CurrentLooseManifestSchema; From 412b124b96269dbeb6db79003e0dc235a0bd6d0f Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 14:22:47 -0700 Subject: [PATCH 15/19] refactor: update all references to use schemas/latest instead of schemas/0.2 - Update src/index.ts, types.ts, browser.ts, cli.ts, and node.ts - All package entrypoints now use latest.ts for easier version management --- src/browser.ts | 2 +- src/cli.ts | 2 +- src/index.ts | 2 +- src/node.ts | 2 +- src/types.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/browser.ts b/src/browser.ts index ea4aaef..d3f0598 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -1,5 +1,5 @@ // Browser-compatible exports -export * from "./schemas/0.2.js"; +export * from "./schemas/latest.js"; export * from "./shared/config.js"; export * from "./shared/constants.js"; export * from "./types.js"; diff --git a/src/cli.ts b/src/cli.ts index 4b5a9f0..5dc861c 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -3,7 +3,7 @@ export * from "./cli/init.js"; export * from "./cli/pack.js"; // Include all shared exports -export * from "./schemas/0.2.js"; +export * from "./schemas/latest.js"; export * from "./shared/config.js"; export * from "./shared/constants.js"; export * from "./types.js"; diff --git a/src/index.ts b/src/index.ts index 327a96c..62ada47 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,7 +5,7 @@ export * from "./cli/unpack.js"; export * from "./node/files.js"; export * from "./node/sign.js"; export * from "./node/validate.js"; -export * from "./schemas/0.2.js"; +export * from "./schemas/latest.js"; export * from "./shared/config.js"; export * from "./shared/constants.js"; export * from "./types.js"; diff --git a/src/node.ts b/src/node.ts index 62f4774..12a7edb 100644 --- a/src/node.ts +++ b/src/node.ts @@ -4,7 +4,7 @@ export * from "./node/sign.js"; export * from "./node/validate.js"; // Include all shared exports -export * from "./schemas/0.2.js"; +export * from "./schemas/latest.js"; export * from "./shared/config.js"; export * from "./shared/constants.js"; export * from "./types.js"; diff --git a/src/types.ts b/src/types.ts index 7a82867..0b6b2a3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,7 +14,7 @@ import type { McpbUserConfigurationOptionSchema, McpbUserConfigValuesSchema, McpServerConfigSchema, -} from "./schemas/0.2.js"; +} from "./schemas/latest.js"; export type McpServerConfig = z.infer; From 4c100e26dab115c54f7351891641e4518410ed89 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 14:26:55 -0700 Subject: [PATCH 16/19] refactor: rename CURRENT_MANIFEST_VERSION to LATEST_MANIFEST_VERSION - Rename CURRENT_MANIFEST_VERSION to LATEST_MANIFEST_VERSION - Rename CURRENT_MANIFEST_SCHEMA to LATEST_MANIFEST_SCHEMA - Rename CURRENT_MANIFEST_SCHEMA_LOOSE to LATEST_MANIFEST_SCHEMA_LOOSE - Update all references throughout codebase and tests --- src/cli/init.ts | 4 ++-- src/cli/pack.ts | 12 ++++++------ src/node/validate.ts | 8 ++++---- src/schemas.ts | 2 +- src/schemas/index.ts | 2 +- src/shared/constants.ts | 12 ++++++------ test/cli.test.ts | 6 +++--- test/init.test.ts | 6 +++--- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/cli/init.ts b/src/cli/init.ts index 17b95a9..a3ae0db 100644 --- a/src/cli/init.ts +++ b/src/cli/init.ts @@ -2,7 +2,7 @@ import { confirm, input, select } from "@inquirer/prompts"; import { existsSync, readFileSync, writeFileSync } from "fs"; import { basename, join, resolve } from "path"; -import { CURRENT_MANIFEST_VERSION } from "../shared/constants.js"; +import { LATEST_MANIFEST_VERSION } from "../shared/constants.js"; import type { McpbManifest } from "../types.js"; interface PackageJson { @@ -774,7 +774,7 @@ export function buildManifest( const { keywords, license, repository } = optionalFields; return { - manifest_version: CURRENT_MANIFEST_VERSION, + manifest_version: LATEST_MANIFEST_VERSION, name, ...(displayName && displayName !== name ? { display_name: displayName } diff --git a/src/cli/pack.ts b/src/cli/pack.ts index 0e51d9b..58b3c1c 100644 --- a/src/cli/pack.ts +++ b/src/cli/pack.ts @@ -14,8 +14,8 @@ import { basename, join, relative, resolve, sep } from "path"; import { getAllFilesWithCount, readMcpbIgnorePatterns } from "../node/files.js"; import { validateManifest } from "../node/validate.js"; import { - CURRENT_MANIFEST_SCHEMA, - CURRENT_MANIFEST_VERSION, + LATEST_MANIFEST_SCHEMA, + LATEST_MANIFEST_VERSION, } from "../shared/constants.js"; import { getLogger } from "../shared/log.js"; import { initExtension } from "./init.js"; @@ -95,7 +95,7 @@ export async function packExtension({ try { const manifestContent = readFileSync(manifestPath, "utf-8"); const manifestData = JSON.parse(manifestContent); - manifest = CURRENT_MANIFEST_SCHEMA.parse(manifestData); + manifest = LATEST_MANIFEST_SCHEMA.parse(manifestData); } catch (error) { logger.error("ERROR: Failed to parse manifest.json"); if (error instanceof Error) { @@ -105,12 +105,12 @@ export async function packExtension({ } const manifestVersion = manifest.manifest_version || manifest.dxt_version; - if (manifestVersion !== CURRENT_MANIFEST_VERSION) { + if (manifestVersion !== LATEST_MANIFEST_VERSION) { logger.error( - `ERROR: Manifest version mismatch. Expected "${CURRENT_MANIFEST_VERSION}", found "${manifestVersion}"`, + `ERROR: Manifest version mismatch. Expected "${LATEST_MANIFEST_VERSION}", found "${manifestVersion}"`, ); logger.error( - ` Please update the manifest_version in your manifest.json to "${CURRENT_MANIFEST_VERSION}"`, + ` Please update the manifest_version in your manifest.json to "${LATEST_MANIFEST_VERSION}"`, ); return false; } diff --git a/src/node/validate.ts b/src/node/validate.ts index 5b44189..7a94d53 100644 --- a/src/node/validate.ts +++ b/src/node/validate.ts @@ -7,8 +7,8 @@ import prettyBytes from "pretty-bytes"; import { unpackExtension } from "../cli/unpack.js"; import { - CURRENT_MANIFEST_SCHEMA, - CURRENT_MANIFEST_SCHEMA_LOOSE, + LATEST_MANIFEST_SCHEMA, + LATEST_MANIFEST_SCHEMA_LOOSE, } from "../shared/constants.js"; export function validateManifest(inputPath: string): boolean { @@ -24,7 +24,7 @@ export function validateManifest(inputPath: string): boolean { const manifestContent = readFileSync(manifestPath, "utf-8"); const manifestData = JSON.parse(manifestContent); - const result = CURRENT_MANIFEST_SCHEMA.safeParse(manifestData); + const result = LATEST_MANIFEST_SCHEMA.safeParse(manifestData); if (result.success) { console.log("Manifest schema validation passes!"); @@ -74,7 +74,7 @@ export async function cleanMcpb(inputPath: string) { const manifestPath = resolve(unpackPath, "manifest.json"); const originalManifest = await fs.readFile(manifestPath, "utf-8"); const manifestData = JSON.parse(originalManifest); - const result = CURRENT_MANIFEST_SCHEMA_LOOSE.safeParse(manifestData); + const result = LATEST_MANIFEST_SCHEMA_LOOSE.safeParse(manifestData); if (!result.success) { throw new Error( diff --git a/src/schemas.ts b/src/schemas.ts index 4bf0ea8..4bbaa7c 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -1,5 +1,5 @@ export { - CURRENT_MANIFEST_VERSION, + LATEST_MANIFEST_VERSION, McpbManifestSchema, v0_1, v0_2, diff --git a/src/schemas/index.ts b/src/schemas/index.ts index 427aad4..9e4a580 100644 --- a/src/schemas/index.ts +++ b/src/schemas/index.ts @@ -2,6 +2,6 @@ export * as v0_1 from "./0.1.js"; export * as v0_2 from "./0.2.js"; export * as latest from "./latest.js"; export { - MANIFEST_VERSION as CURRENT_MANIFEST_VERSION, + MANIFEST_VERSION as LATEST_MANIFEST_VERSION, McpbManifestSchema, } from "./latest.js"; diff --git a/src/shared/constants.ts b/src/shared/constants.ts index ec7b865..1e4c2d0 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -6,9 +6,9 @@ import { McpbManifestSchema as LooseManifestSchemaV0_2 } from "../schemas_loose/ import { McpbManifestSchema as CurrentLooseManifestSchema } from "../schemas_loose/latest.js"; /** - * Current manifest version - the version that new manifests should use + * Latest manifest version - the version that new manifests should use */ -export const CURRENT_MANIFEST_VERSION = "0.2" as const; +export const LATEST_MANIFEST_VERSION = "0.2" as const; /** * Map of manifest versions to their strict schemas @@ -27,11 +27,11 @@ export const MANIFEST_SCHEMAS_LOOSE = { } as const; /** - * Get the current manifest schema based on CURRENT_MANIFEST_VERSION + * Get the latest manifest schema based on LATEST_MANIFEST_VERSION */ -export const CURRENT_MANIFEST_SCHEMA = CurrentManifestSchema; +export const LATEST_MANIFEST_SCHEMA = CurrentManifestSchema; /** - * Get the current loose manifest schema based on CURRENT_MANIFEST_VERSION + * Get the latest loose manifest schema based on LATEST_MANIFEST_VERSION */ -export const CURRENT_MANIFEST_SCHEMA_LOOSE = CurrentLooseManifestSchema; +export const LATEST_MANIFEST_SCHEMA_LOOSE = CurrentLooseManifestSchema; diff --git a/test/cli.test.ts b/test/cli.test.ts index dd18635..0357635 100644 --- a/test/cli.test.ts +++ b/test/cli.test.ts @@ -2,7 +2,7 @@ import { execSync } from "node:child_process"; import fs from "node:fs"; import { join } from "node:path"; -import { CURRENT_MANIFEST_VERSION } from "../src/schemas.js"; +import { LATEST_MANIFEST_VERSION } from "../src/schemas.js"; interface ExecSyncError extends Error { stdout: Buffer; @@ -93,7 +93,7 @@ describe("DXT CLI", () => { fs.writeFileSync( join(tempDir, "manifest.json"), JSON.stringify({ - manifest_version: CURRENT_MANIFEST_VERSION, + manifest_version: LATEST_MANIFEST_VERSION, name: "Test Extension", version: "1.0.0", description: "A test extension", @@ -190,7 +190,7 @@ describe("DXT CLI", () => { fs.writeFileSync( join(tempExecDir, "manifest.json"), JSON.stringify({ - manifest_version: CURRENT_MANIFEST_VERSION, + manifest_version: LATEST_MANIFEST_VERSION, name: "Test Executable Extension", version: "1.0.0", description: "A test extension with executable files", diff --git a/test/init.test.ts b/test/init.test.ts index f79191e..2b65ada 100644 --- a/test/init.test.ts +++ b/test/init.test.ts @@ -10,7 +10,7 @@ import { getDefaultRepositoryUrl, readPackageJson, } from "../src/cli/init.js"; -import { CURRENT_MANIFEST_VERSION } from "../src/schemas.js"; +import { LATEST_MANIFEST_VERSION } from "../src/schemas.js"; // Mock the fs module jest.mock("fs", () => ({ @@ -218,7 +218,7 @@ describe("init functions", () => { ); expect(manifest).toEqual({ - manifest_version: CURRENT_MANIFEST_VERSION, + manifest_version: LATEST_MANIFEST_VERSION, name: "test-extension", version: "1.0.0", description: "Test description", @@ -304,7 +304,7 @@ describe("init functions", () => { ); expect(manifest).toEqual({ - manifest_version: CURRENT_MANIFEST_VERSION, + manifest_version: LATEST_MANIFEST_VERSION, name: "test-extension", display_name: "Test Extension", version: "1.0.0", From 6c053389044a6baf2948ab1b006f45f964e0203d Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Wed, 24 Sep 2025 14:28:06 -0700 Subject: [PATCH 17/19] refactor: remove schemas.ts re-export, use explicit imports in tests - Remove src/schemas.ts file - Update tests to import directly from src/schemas/index.js --- src/schemas.ts | 6 ------ test/cli.test.ts | 2 +- test/init.test.ts | 2 +- test/schemas.test.ts | 2 +- 4 files changed, 3 insertions(+), 9 deletions(-) delete mode 100644 src/schemas.ts diff --git a/src/schemas.ts b/src/schemas.ts deleted file mode 100644 index 4bbaa7c..0000000 --- a/src/schemas.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { - LATEST_MANIFEST_VERSION, - McpbManifestSchema, - v0_1, - v0_2, -} from "./schemas/index.js"; diff --git a/test/cli.test.ts b/test/cli.test.ts index 0357635..1462150 100644 --- a/test/cli.test.ts +++ b/test/cli.test.ts @@ -2,7 +2,7 @@ import { execSync } from "node:child_process"; import fs from "node:fs"; import { join } from "node:path"; -import { LATEST_MANIFEST_VERSION } from "../src/schemas.js"; +import { LATEST_MANIFEST_VERSION } from "../src/schemas/index.js"; interface ExecSyncError extends Error { stdout: Buffer; diff --git a/test/init.test.ts b/test/init.test.ts index 2b65ada..3cdea0c 100644 --- a/test/init.test.ts +++ b/test/init.test.ts @@ -10,7 +10,7 @@ import { getDefaultRepositoryUrl, readPackageJson, } from "../src/cli/init.js"; -import { LATEST_MANIFEST_VERSION } from "../src/schemas.js"; +import { LATEST_MANIFEST_VERSION } from "../src/schemas/index.js"; // Mock the fs module jest.mock("fs", () => ({ diff --git a/test/schemas.test.ts b/test/schemas.test.ts index 71773f0..2cf80c5 100644 --- a/test/schemas.test.ts +++ b/test/schemas.test.ts @@ -1,7 +1,7 @@ import { readFileSync } from "fs"; import { join } from "path"; -import { McpbManifestSchema } from "../src/schemas.js"; +import { McpbManifestSchema } from "../src/schemas/index.js"; describe("McpbManifestSchema", () => { it("should validate a valid manifest", () => { From 143aa9a63c850e4b7a8670426671350bcb4fba5b Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Fri, 17 Oct 2025 17:07:51 -0700 Subject: [PATCH 18/19] test: skip _meta tests for v0.3 --- test/schemas.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/schemas.test.ts b/test/schemas.test.ts index 2ba2361..5acbc27 100644 --- a/test/schemas.test.ts +++ b/test/schemas.test.ts @@ -137,7 +137,7 @@ describe("McpbManifestSchema", () => { }); }); - describe("_meta", () => { + describe.skip("_meta", () => { const base = { manifest_version: "0.2", name: "client-ext-test", From f7efd3a444541555d80e6cd63793ee8e4fb6abd9 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Fri, 17 Oct 2025 20:56:31 -0700 Subject: [PATCH 19/19] add WIP 0.3 --- src/schemas/0.3.ts | 126 +++++++++++++++++++++++++++++++++++++++++++ src/schemas/index.ts | 1 + test/schemas.test.ts | 26 +++++---- 3 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 src/schemas/0.3.ts diff --git a/src/schemas/0.3.ts b/src/schemas/0.3.ts new file mode 100644 index 0000000..3862ba4 --- /dev/null +++ b/src/schemas/0.3.ts @@ -0,0 +1,126 @@ +// WIP: This schema is under development and not yet finalized +import * as z from "zod"; + +export const MANIFEST_VERSION = "0.3"; + +export const McpServerConfigSchema = z.strictObject({ + command: z.string(), + args: z.array(z.string()).optional(), + env: z.record(z.string(), z.string()).optional(), +}); + +export const McpbManifestAuthorSchema = z.strictObject({ + name: z.string(), + email: z.string().email().optional(), + url: z.string().url().optional(), +}); + +export const McpbManifestRepositorySchema = z.strictObject({ + type: z.string(), + url: z.string().url(), +}); + +export const McpbManifestPlatformOverrideSchema = + McpServerConfigSchema.partial(); + +export const McpbManifestMcpConfigSchema = McpServerConfigSchema.extend({ + platform_overrides: z + .record(z.string(), McpbManifestPlatformOverrideSchema) + .optional(), +}); + +export const McpbManifestServerSchema = z.strictObject({ + type: z.enum(["python", "node", "binary"]), + entry_point: z.string(), + mcp_config: McpbManifestMcpConfigSchema, +}); + +export const McpbManifestCompatibilitySchema = z.strictObject({ + claude_desktop: z.string().optional(), + platforms: z.array(z.enum(["darwin", "win32", "linux"])).optional(), + runtimes: z + .strictObject({ + python: z.string().optional(), + node: z.string().optional(), + }) + .optional(), +}); + +export const McpbManifestToolSchema = z.strictObject({ + name: z.string(), + description: z.string().optional(), +}); + +export const McpbManifestPromptSchema = z.strictObject({ + name: z.string(), + description: z.string().optional(), + arguments: z.array(z.string()).optional(), + text: z.string(), +}); + +export const McpbUserConfigurationOptionSchema = z.strictObject({ + type: z.enum(["string", "number", "boolean", "directory", "file"]), + title: z.string(), + description: z.string(), + required: z.boolean().optional(), + default: z + .union([z.string(), z.number(), z.boolean(), z.array(z.string())]) + .optional(), + multiple: z.boolean().optional(), + sensitive: z.boolean().optional(), + min: z.number().optional(), + max: z.number().optional(), +}); + +export const McpbUserConfigValuesSchema = z.record( + z.string(), + z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]), +); + +export const McpbManifestSchema = z + .strictObject({ + $schema: z.string().optional(), + dxt_version: z + .literal(MANIFEST_VERSION) + .optional() + .describe("@deprecated Use manifest_version instead"), + manifest_version: z.literal(MANIFEST_VERSION).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(), + privacy_policies: z.array(z.string().url()).optional(), + compatibility: McpbManifestCompatibilitySchema.optional(), + user_config: z + .record(z.string(), McpbUserConfigurationOptionSchema) + .optional(), + _meta: z.record(z.string(), z.record(z.string(), z.any())).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"]), + publisher: z.string().optional(), + issuer: z.string().optional(), + valid_from: z.string().optional(), + valid_to: z.string().optional(), + fingerprint: z.string().optional(), +}); diff --git a/src/schemas/index.ts b/src/schemas/index.ts index 9e4a580..1b7c64b 100644 --- a/src/schemas/index.ts +++ b/src/schemas/index.ts @@ -1,5 +1,6 @@ export * as v0_1 from "./0.1.js"; export * as v0_2 from "./0.2.js"; +export * as v0_3 from "./0.3.js"; export * as latest from "./latest.js"; export { MANIFEST_VERSION as LATEST_MANIFEST_VERSION, diff --git a/test/schemas.test.ts b/test/schemas.test.ts index 5acbc27..f88fe47 100644 --- a/test/schemas.test.ts +++ b/test/schemas.test.ts @@ -1,7 +1,7 @@ import { readFileSync } from "fs"; import { join } from "path"; -import { McpbManifestSchema } from "../src/schemas/index.js"; +import { McpbManifestSchema, v0_3 } from "../src/schemas/index.js"; describe("McpbManifestSchema", () => { it("should validate a valid manifest", () => { @@ -137,9 +137,9 @@ describe("McpbManifestSchema", () => { }); }); - describe.skip("_meta", () => { + describe("_meta", () => { const base = { - manifest_version: "0.2", + manifest_version: "0.3", name: "client-ext-test", version: "1.0.0", description: "Test manifest", @@ -155,11 +155,14 @@ describe("McpbManifestSchema", () => { const manifest = { ...base, _meta: { - "com.microsoft.windows": { package_family_name: "Pkg_123", channel: "stable" }, + "com.microsoft.windows": { + package_family_name: "Pkg_123", + channel: "stable", + }, "com.apple.darwin": { bundle_id: "com.example.app", notarized: true }, }, }; - const result = McpbManifestSchema.safeParse(manifest); + const result = v0_3.McpbManifestSchema.safeParse(manifest); expect(result.success).toBe(true); }); @@ -167,10 +170,13 @@ describe("McpbManifestSchema", () => { const manifest = { ...base, _meta: { - "com.microsoft.windows": "raw-string" as unknown as Record, + "com.microsoft.windows": "raw-string" as unknown as Record< + string, + unknown + >, }, }; - const result = McpbManifestSchema.safeParse(manifest); + const result = v0_3.McpbManifestSchema.safeParse(manifest); expect(result.success).toBe(false); if (!result.success) { const messages = result.error.issues.map((i) => i.message).join("\n"); @@ -185,7 +191,7 @@ describe("McpbManifestSchema", () => { "com.apple.darwin": [] as unknown as Record, }, }; - const result = McpbManifestSchema.safeParse(manifest); + const result = v0_3.McpbManifestSchema.safeParse(manifest); expect(result.success).toBe(false); }); @@ -196,13 +202,13 @@ describe("McpbManifestSchema", () => { custom: null as unknown as Record, }, }; - const result = McpbManifestSchema.safeParse(manifest); + const result = v0_3.McpbManifestSchema.safeParse(manifest); expect(result.success).toBe(false); }); it("allows empty object for _meta", () => { const manifest = { ...base, _meta: {} }; - const result = McpbManifestSchema.safeParse(manifest); + const result = v0_3.McpbManifestSchema.safeParse(manifest); expect(result.success).toBe(true); }); });