fix: update schema to reflect manifest_version

This commit is contained in:
Joan Xie 2025-08-25 21:09:45 -07:00
commit 76949836e0
No known key found for this signature in database
15 changed files with 72 additions and 56 deletions

View file

@ -11,7 +11,7 @@ A basic `manifest.json` with just the required fields looks like this:
```json ```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) "name": "my-extension", // Machine-readable name (used for CLI, APIs)
"version": "1.0.0", // Semantic version of your extension "version": "1.0.0", // Semantic version of your extension
"description": "A simple MCP extension", // Brief description of what the extension does "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 ```json
{ {
"mcpb_version": "0.1", "manifest_version": "0.1",
"name": "my-extension", "name": "my-extension",
"version": "1.0.0", "version": "1.0.0",
"description": "A simple MCP extension", "description": "A simple MCP extension",
@ -71,7 +71,7 @@ A full `manifest.json` with most of the optional fields looks like this:
```json ```json
{ {
"mcpb_version": "0.1", "manifest_version": "0.1",
"name": "My MCP Extension", "name": "My MCP Extension",
"display_name": "My Awesome MCP Extension", "display_name": "My Awesome MCP Extension",
"version": "1.0.0", "version": "1.0.0",
@ -162,7 +162,7 @@ A full `manifest.json` with most of the optional fields looks like this:
### Required Fields ### 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) - **name**: Machine-readable name (used for CLI, APIs)
- **version**: Semantic version (semver) - **version**: Semantic version (semver)
- **description**: Brief description - **description**: Brief description

View file

@ -1,6 +1,6 @@
{ {
"$schema": "../../dist/dxt-manifest.schema.json", "$schema": "../../dist/mcpb-manifest.schema.json",
"mcpb_version": "0.1", "manifest_version": "0.1",
"name": "chrome-applescript", "name": "chrome-applescript",
"display_name": "Control Chrome with AppleScript", "display_name": "Control Chrome with AppleScript",
"version": "0.1.0", "version": "0.1.0",

View file

@ -1,6 +1,6 @@
{ {
"$schema": "../../dist/dxt-manifest.schema.json", "$schema": "../../dist/mcpb-manifest.schema.json",
"mcpb_version": "0.1", "manifest_version": "0.1",
"name": "file-manager-python", "name": "file-manager-python",
"display_name": "Python File Manager MCP", "display_name": "Python File Manager MCP",
"version": "0.1.0", "version": "0.1.0",

View file

@ -1,5 +1,5 @@
{ {
"mcpb_version": "0.1", "manifest_version": "0.1",
"id": "anthropic.demo.filesystem", "id": "anthropic.demo.filesystem",
"name": "Filesystem", "name": "Filesystem",
"display_name": "Filesystem", "display_name": "Filesystem",

View file

@ -1,6 +1,6 @@
{ {
"$schema": "../../dist/dxt-manifest.schema.json", "$schema": "../../dist/mcpb-manifest.schema.json",
"mcpb_version": "0.1", "manifest_version": "0.1",
"name": "hello-world-node", "name": "hello-world-node",
"display_name": "Hello World MCP Server (Reference Extension)", "display_name": "Hello World MCP Server (Reference Extension)",
"version": "0.1.0", "version": "0.1.0",

View file

@ -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 * as z from "zod/v4";
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import path from "node:path"; import path from "node:path";
const schemasToWrite = { const schemasToWrite = {
"dxt-manifest": DxtManifestSchema, "mcpb-manifest": McpbManifestSchema,
"dxt-signature-info": DxtSignatureInfoSchema, "mcpb-signature-info": McpbSignatureInfoSchema,
}; };
await fs.mkdir(path.join(import.meta.dirname, "../dist"), { recursive: true }); await fs.mkdir(path.join(import.meta.dirname, "../dist"), { recursive: true });

View file

@ -773,7 +773,7 @@ export function buildManifest(
const { keywords, license, repository } = optionalFields; const { keywords, license, repository } = optionalFields;
return { return {
mcpb_version: "0.1", manifest_version: "0.1",
name, name,
...(displayName && displayName !== name ...(displayName && displayName !== name
? { display_name: displayName } ? { display_name: displayName }

View file

@ -76,9 +76,11 @@ export const McpbUserConfigValuesSchema = z.record(
z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]), z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
); );
export const McpbManifestSchema = z.object({ export const McpbManifestSchema = z
$schema: z.string().optional(), .object({
mcpb_version: z.string(), $schema: z.string().optional(),
dxt_version: z.string().optional().describe("@deprecated Use manifest_version instead"),
manifest_version: z.string().optional(),
name: z.string(), name: z.string(),
display_name: z.string().optional(), display_name: z.string().optional(),
version: z.string(), version: z.string(),
@ -102,7 +104,13 @@ export const McpbManifestSchema = z.object({
user_config: z user_config: z
.record(z.string(), McpbUserConfigurationOptionSchema) .record(z.string(), McpbUserConfigurationOptionSchema)
.optional(), .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({ export const McpbSignatureInfoSchema = z.object({
status: z.enum(["signed", "unsigned", "self-signed"]), status: z.enum(["signed", "unsigned", "self-signed"]),

View file

@ -76,33 +76,41 @@ export const McpbUserConfigValuesSchema = z.record(
z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]), z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
); );
export const McpbManifestSchema = z.strictObject({ export const McpbManifestSchema = z
$schema: z.string().optional(), .strictObject({
mcpb_version: z.string(), $schema: z.string().optional(),
name: z.string(), dxt_version: z.string().optional().describe("@deprecated Use manifest_version instead"),
display_name: z.string().optional(), manifest_version: z.string().optional(),
version: z.string(), name: z.string(),
description: z.string(), display_name: z.string().optional(),
long_description: z.string().optional(), version: z.string(),
author: McpbManifestAuthorSchema, description: z.string(),
repository: McpbManifestRepositorySchema.optional(), long_description: z.string().optional(),
homepage: z.string().url().optional(), author: McpbManifestAuthorSchema,
documentation: z.string().url().optional(), repository: McpbManifestRepositorySchema.optional(),
support: z.string().url().optional(), homepage: z.string().url().optional(),
icon: z.string().optional(), documentation: z.string().url().optional(),
screenshots: z.array(z.string()).optional(), support: z.string().url().optional(),
server: McpbManifestServerSchema, icon: z.string().optional(),
tools: z.array(McpbManifestToolSchema).optional(), screenshots: z.array(z.string()).optional(),
tools_generated: z.boolean().optional(), server: McpbManifestServerSchema,
prompts: z.array(McpbManifestPromptSchema).optional(), tools: z.array(McpbManifestToolSchema).optional(),
prompts_generated: z.boolean().optional(), tools_generated: z.boolean().optional(),
keywords: z.array(z.string()).optional(), prompts: z.array(McpbManifestPromptSchema).optional(),
license: z.string().optional(), prompts_generated: z.boolean().optional(),
compatibility: McpbManifestCompatibilitySchema.optional(), keywords: z.array(z.string()).optional(),
user_config: z license: z.string().optional(),
.record(z.string(), McpbUserConfigurationOptionSchema) compatibility: McpbManifestCompatibilitySchema.optional(),
.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({ export const McpbSignatureInfoSchema = z.strictObject({
status: z.enum(["signed", "unsigned", "self-signed"]), status: z.enum(["signed", "unsigned", "self-signed"]),

View file

@ -91,7 +91,7 @@ describe("DXT CLI", () => {
fs.writeFileSync( fs.writeFileSync(
join(tempDir, "manifest.json"), join(tempDir, "manifest.json"),
JSON.stringify({ JSON.stringify({
mcpb_version: "1.0", manifest_version: "1.0",
name: "Test Extension", name: "Test Extension",
version: "1.0.0", version: "1.0.0",
description: "A test extension", description: "A test extension",
@ -188,7 +188,7 @@ describe("DXT CLI", () => {
fs.writeFileSync( fs.writeFileSync(
join(tempExecDir, "manifest.json"), join(tempExecDir, "manifest.json"),
JSON.stringify({ JSON.stringify({
mcpb_version: "1.0", manifest_version: "1.0",
name: "Test Executable Extension", name: "Test Executable Extension",
version: "1.0.0", version: "1.0.0",
description: "A test extension with executable files", description: "A test extension with executable files",

View file

@ -90,7 +90,7 @@ describe("getMcpConfigForManifest", () => {
}; };
const baseManifest: McpbManifest = { const baseManifest: McpbManifest = {
mcpb_version: "1.0.0", manifest_version: "1.0.0",
name: "test-extension", name: "test-extension",
version: "1.0.0", version: "1.0.0",
description: "Test extension", description: "Test extension",
@ -305,7 +305,7 @@ describe("getMcpConfigForManifest", () => {
describe("hasRequiredConfigMissing", () => { describe("hasRequiredConfigMissing", () => {
const baseManifest: McpbManifest = { const baseManifest: McpbManifest = {
mcpb_version: "1.0.0", manifest_version: "1.0.0",
name: "test-extension", name: "test-extension",
version: "1.0.0", version: "1.0.0",
description: "Test extension", description: "Test extension",

View file

@ -217,7 +217,7 @@ describe("init functions", () => {
); );
expect(manifest).toEqual({ expect(manifest).toEqual({
mcpb_version: "0.1", manifest_version: "0.1",
name: "test-extension", name: "test-extension",
version: "1.0.0", version: "1.0.0",
description: "Test description", description: "Test description",
@ -303,7 +303,7 @@ describe("init functions", () => {
); );
expect(manifest).toEqual({ expect(manifest).toEqual({
mcpb_version: "0.1", manifest_version: "0.1",
name: "test-extension", name: "test-extension",
display_name: "Test Extension", display_name: "Test Extension",
version: "1.0.0", version: "1.0.0",

View file

@ -1,5 +1,5 @@
{ {
"mcpb_version": "1.0", "manifest_version": "1.0",
"name": "test-extension", "name": "test-extension",
"version": "1.0.0", "version": "1.0.0",
"description": "A test DXT extension", "description": "A test DXT extension",

View file

@ -37,7 +37,7 @@ describe("McpbManifestSchema", () => {
it("should validate manifest with all optional fields", () => { it("should validate manifest with all optional fields", () => {
const fullManifest = { const fullManifest = {
mcpb_version: "1.0", manifest_version: "1.0",
name: "full-extension", name: "full-extension",
display_name: "Full Featured Extension", display_name: "Full Featured Extension",
version: "2.0.0", version: "2.0.0",
@ -117,7 +117,7 @@ describe("McpbManifestSchema", () => {
serverTypes.forEach((type) => { serverTypes.forEach((type) => {
const manifest = { const manifest = {
mcpb_version: "1.0", manifest_version: "1.0",
name: "test", name: "test",
version: "1.0.0", version: "1.0.0",
description: "Test", description: "Test",

View file

@ -1,5 +1,5 @@
{ {
"mcpb_version": "1.0", "manifest_version": "1.0",
"name": "test-extension", "name": "test-extension",
"display_name": "Test Extension", "display_name": "Test Extension",
"version": "1.0.0", "version": "1.0.0",