From ddad8064ef077c4f232f38e82e68a2194e0fdbce Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Thu, 30 Oct 2025 09:40:32 -0700 Subject: [PATCH 1/5] feat: use latest MCPB schema for BUILD manifest validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update manifest type usage in config and packaging to strictly enforce the latest schema version (0.3) instead of accepting any version. Changes: - src/shared/config.ts: Use McpbManifestLatest instead of McpbManifest - src/types.ts: Add McpbManifestLatest type export - test/config.test.ts: Update tests to use McpbManifestLatest This ensures BUILD manifests are validated against the latest schema only during packaging, preventing use of older schema versions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/shared/config.ts | 6 +++--- src/types.ts | 18 +++++++++++++++++- test/config.test.ts | 32 ++++++++++++++++---------------- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/shared/config.ts b/src/shared/config.ts index 20e4262..ab8e096 100644 --- a/src/shared/config.ts +++ b/src/shared/config.ts @@ -1,6 +1,6 @@ import type { Logger, - McpbManifest, + McpbManifestLatest, McpbUserConfigValues, McpServerConfig, } from "../types.js"; @@ -85,7 +85,7 @@ export function replaceVariables( } interface GetMcpConfigForManifestOptions { - manifest: McpbManifest; + manifest: McpbManifestLatest; extensionPath: string; systemDirs: Record; userConfig: McpbUserConfigValues; @@ -179,7 +179,7 @@ export async function getMcpConfigForManifest( } interface HasRequiredConfigMissingOptions { - manifest: McpbManifest; + manifest: McpbManifestLatest; userConfig?: McpbUserConfigValues; } diff --git a/src/types.ts b/src/types.ts index 0b6b2a3..a620b0d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -15,6 +15,7 @@ import type { McpbUserConfigValuesSchema, McpServerConfigSchema, } from "./schemas/latest.js"; +import type { McpbManifestSchema as McpbManifestSchemaAny } from "./schemas/any.js"; export type McpServerConfig = z.infer; @@ -46,7 +47,22 @@ export type McpbUserConfigurationOption = z.infer< export type McpbUserConfigValues = z.infer; -export type McpbManifest = z.infer; +/** + * McpbManifest type that accepts any supported manifest version (0.1, 0.2, 0.3). + * This is the default manifest type that should be used for maximum compatibility. + */ +export type McpbManifest = z.infer; + +/** + * @deprecated Use McpbManifest instead. This alias is kept for backward compatibility. + */ +export type McpbManifestAny = z.infer; + +/** + * McpbManifest type for the latest manifest version only (0.3). + * Use this when you specifically need the latest version. + */ +export type McpbManifestLatest = z.infer; /** * Information about a MCPB package signature diff --git a/test/config.test.ts b/test/config.test.ts index f7a0eb8..4701890 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -3,7 +3,7 @@ import { hasRequiredConfigMissing, replaceVariables, } from "../src/shared/config"; -import type { Logger, McpbManifest } from "../src/types"; +import type { Logger, McpbManifestLatest } from "../src/types"; describe("replaceVariables", () => { it("should replace variables in strings", () => { @@ -89,7 +89,7 @@ describe("getMcpConfigForManifest", () => { data: "/data", }; - const baseManifest: McpbManifest = { + const baseManifest: McpbManifestLatest = { manifest_version: "0.3", name: "test-extension", version: "1.0.0", @@ -114,7 +114,7 @@ describe("getMcpConfigForManifest", () => { const manifest = { ...baseManifest, server: undefined, - } as unknown as McpbManifest; + } as unknown as McpbManifestLatest; const result = await getMcpConfigForManifest({ manifest, @@ -129,7 +129,7 @@ describe("getMcpConfigForManifest", () => { }); it("should return undefined when required config is missing", async () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { apiKey: { @@ -171,7 +171,7 @@ describe("getMcpConfigForManifest", () => { }); it("should apply platform overrides", async () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, server: { type: "node", @@ -203,7 +203,7 @@ describe("getMcpConfigForManifest", () => { }); it("should handle user config variable replacement with defaults", async () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { port: { @@ -236,7 +236,7 @@ describe("getMcpConfigForManifest", () => { }); it("should handle user config variable replacement with user values", async () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { paths: { @@ -270,7 +270,7 @@ describe("getMcpConfigForManifest", () => { }); it("should convert boolean user config values to strings", async () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { verbose: { @@ -304,7 +304,7 @@ describe("getMcpConfigForManifest", () => { }); describe("hasRequiredConfigMissing", () => { - const baseManifest: McpbManifest = { + const baseManifest: McpbManifestLatest = { manifest_version: "0.3", name: "test-extension", version: "1.0.0", @@ -329,7 +329,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return false when no config fields are required", () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { port: { @@ -349,7 +349,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return false when required config is provided", () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { apiKey: { @@ -369,7 +369,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return true when required config is undefined", () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { apiKey: { @@ -389,7 +389,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return true when required config is empty string", () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { apiKey: { @@ -409,7 +409,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return true when required config is array with invalid values", () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { paths: { @@ -430,7 +430,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return true when required config is empty array", () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { paths: { @@ -459,7 +459,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should handle multiple required config fields", () => { - const manifest: McpbManifest = { + const manifest: McpbManifestLatest = { ...baseManifest, user_config: { apiKey: { From 184173e3421c8c7af25a2e05092bcd8fa1ca3bd0 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Thu, 30 Oct 2025 09:47:08 -0700 Subject: [PATCH 2/5] fix: use correct manifest types for reading vs building MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply proper type distinction: - Reading/validating existing manifests: Use McpbManifest (any version) - Building/creating new manifests: Use McpbManifestLatest (latest only) Changes: - src/shared/config.ts: Revert to McpbManifest for config operations - src/cli/init.ts: Use McpbManifestLatest for new manifest creation - test/config.test.ts: Use McpbManifest for testing config operations This ensures backward compatibility when reading existing manifests while enforcing latest schema for new builds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/cli/init.ts | 4 ++-- src/shared/config.ts | 6 +++--- test/config.test.ts | 32 ++++++++++++++++---------------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/cli/init.ts b/src/cli/init.ts index c8e764a..3111b3f 100644 --- a/src/cli/init.ts +++ b/src/cli/init.ts @@ -3,7 +3,7 @@ import { existsSync, readFileSync, writeFileSync } from "fs"; import { basename, join, resolve } from "path"; import { LATEST_MANIFEST_VERSION } from "../shared/constants.js"; -import type { McpbManifest } from "../types.js"; +import type { McpbManifestLatest } from "../types.js"; interface PackageJson { name?: string; @@ -878,7 +878,7 @@ export function buildManifest( resources: string; default_locale: string; }, -): McpbManifest { +): McpbManifestLatest { const { name, displayName, version, description, authorName } = basicInfo; const { authorEmail, authorUrl } = authorInfo; const { serverType, entryPoint, mcp_config } = serverConfig; diff --git a/src/shared/config.ts b/src/shared/config.ts index ab8e096..20e4262 100644 --- a/src/shared/config.ts +++ b/src/shared/config.ts @@ -1,6 +1,6 @@ import type { Logger, - McpbManifestLatest, + McpbManifest, McpbUserConfigValues, McpServerConfig, } from "../types.js"; @@ -85,7 +85,7 @@ export function replaceVariables( } interface GetMcpConfigForManifestOptions { - manifest: McpbManifestLatest; + manifest: McpbManifest; extensionPath: string; systemDirs: Record; userConfig: McpbUserConfigValues; @@ -179,7 +179,7 @@ export async function getMcpConfigForManifest( } interface HasRequiredConfigMissingOptions { - manifest: McpbManifestLatest; + manifest: McpbManifest; userConfig?: McpbUserConfigValues; } diff --git a/test/config.test.ts b/test/config.test.ts index 4701890..f7a0eb8 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -3,7 +3,7 @@ import { hasRequiredConfigMissing, replaceVariables, } from "../src/shared/config"; -import type { Logger, McpbManifestLatest } from "../src/types"; +import type { Logger, McpbManifest } from "../src/types"; describe("replaceVariables", () => { it("should replace variables in strings", () => { @@ -89,7 +89,7 @@ describe("getMcpConfigForManifest", () => { data: "/data", }; - const baseManifest: McpbManifestLatest = { + const baseManifest: McpbManifest = { manifest_version: "0.3", name: "test-extension", version: "1.0.0", @@ -114,7 +114,7 @@ describe("getMcpConfigForManifest", () => { const manifest = { ...baseManifest, server: undefined, - } as unknown as McpbManifestLatest; + } as unknown as McpbManifest; const result = await getMcpConfigForManifest({ manifest, @@ -129,7 +129,7 @@ describe("getMcpConfigForManifest", () => { }); it("should return undefined when required config is missing", async () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { apiKey: { @@ -171,7 +171,7 @@ describe("getMcpConfigForManifest", () => { }); it("should apply platform overrides", async () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, server: { type: "node", @@ -203,7 +203,7 @@ describe("getMcpConfigForManifest", () => { }); it("should handle user config variable replacement with defaults", async () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { port: { @@ -236,7 +236,7 @@ describe("getMcpConfigForManifest", () => { }); it("should handle user config variable replacement with user values", async () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { paths: { @@ -270,7 +270,7 @@ describe("getMcpConfigForManifest", () => { }); it("should convert boolean user config values to strings", async () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { verbose: { @@ -304,7 +304,7 @@ describe("getMcpConfigForManifest", () => { }); describe("hasRequiredConfigMissing", () => { - const baseManifest: McpbManifestLatest = { + const baseManifest: McpbManifest = { manifest_version: "0.3", name: "test-extension", version: "1.0.0", @@ -329,7 +329,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return false when no config fields are required", () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { port: { @@ -349,7 +349,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return false when required config is provided", () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { apiKey: { @@ -369,7 +369,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return true when required config is undefined", () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { apiKey: { @@ -389,7 +389,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return true when required config is empty string", () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { apiKey: { @@ -409,7 +409,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return true when required config is array with invalid values", () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { paths: { @@ -430,7 +430,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should return true when required config is empty array", () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { paths: { @@ -459,7 +459,7 @@ describe("hasRequiredConfigMissing", () => { }); it("should handle multiple required config fields", () => { - const manifest: McpbManifestLatest = { + const manifest: McpbManifest = { ...baseManifest, user_config: { apiKey: { From a2bb7589b6565d3fc024ad008d67e352cf760550 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Thu, 30 Oct 2025 09:57:16 -0700 Subject: [PATCH 3/5] fix: sort imports in types.ts --- src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types.ts b/src/types.ts index a620b0d..22b4c42 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,6 @@ import type * as z from "zod"; +import type { McpbManifestSchema as McpbManifestSchemaAny } from "./schemas/any.js"; import type { McpbManifestAuthorSchema, McpbManifestCompatibilitySchema, @@ -15,7 +16,6 @@ import type { McpbUserConfigValuesSchema, McpServerConfigSchema, } from "./schemas/latest.js"; -import type { McpbManifestSchema as McpbManifestSchemaAny } from "./schemas/any.js"; export type McpServerConfig = z.infer; From 8bea47f0b7dd1b710d820fb06660be64228f6ce5 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Thu, 30 Oct 2025 10:00:13 -0700 Subject: [PATCH 4/5] chore: bump version to 1.1.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cec3546..117ea90 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@anthropic-ai/mcpb", "description": "Tools for building MCP Bundles", - "version": "1.1.3", + "version": "1.1.4", "type": "module", "main": "dist/index.js", "module": "dist/index.js", From 7ecb050280285e76286f364a5a86d112ad8f4607 Mon Sep 17 00:00:00 2001 From: Joan Xie Date: Thu, 30 Oct 2025 14:19:34 -0700 Subject: [PATCH 5/5] cleanup --- src/types.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/types.ts b/src/types.ts index 22b4c42..9fb510f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -48,18 +48,13 @@ export type McpbUserConfigurationOption = z.infer< export type McpbUserConfigValues = z.infer; /** - * McpbManifest type that accepts any supported manifest version (0.1, 0.2, 0.3). + * McpbManifest type that accepts any supported manifest version * This is the default manifest type that should be used for maximum compatibility. */ export type McpbManifest = z.infer; /** - * @deprecated Use McpbManifest instead. This alias is kept for backward compatibility. - */ -export type McpbManifestAny = z.infer; - -/** - * McpbManifest type for the latest manifest version only (0.3). + * McpbManifest type for the latest manifest version only * Use this when you specifically need the latest version. */ export type McpbManifestLatest = z.infer;