Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a43769d
feat: restructure schemas into versioned folders
joan-anthropic Sep 24, 2025
8e2ec66
fix: add privacy_policies and passthrough to loose schema v0.2
joan-anthropic Sep 24, 2025
2e9e70c
fix: update schema imports to versioned paths
joan-anthropic Sep 24, 2025
3d9c966
fix: rename CURRENT_MANIFEST_VERSION to MANIFEST_VERSION and set corr…
joan-anthropic Sep 24, 2025
16f1738
fix: correct strict schemas for v0.1 and v0.2
joan-anthropic Sep 24, 2025
9f078c6
fix: add deprecation notice to dxt_version in v0.1 schemas
joan-anthropic Sep 24, 2025
336e878
fix: add dxt_version support to v0.2 schemas with deprecation notice
joan-anthropic Sep 24, 2025
6bfd100
feat: export CURRENT_MANIFEST_VERSION from schemas index
joan-anthropic Sep 24, 2025
fe733e3
refactor: use MANIFEST_VERSION variable in z.literal() instead of har…
joan-anthropic Sep 24, 2025
3a0d4a8
feat: create schema version map with CURRENT_MANIFEST_SCHEMA selector
joan-anthropic Sep 24, 2025
76b7955
fix: use CURRENT_MANIFEST_VERSION in pack.ts version check
joan-anthropic Sep 24, 2025
ccb1927
feat: export constants from package entrypoints
joan-anthropic Sep 24, 2025
fefd9e1
fix: add schemas re-export file and update tests to use correct manif…
joan-anthropic Sep 24, 2025
c4a9500
feat: add schema helper aliases (latest)
joan-anthropic Sep 24, 2025
412b124
refactor: update all references to use schemas/latest instead of sche…
joan-anthropic Sep 24, 2025
4c100e2
refactor: rename CURRENT_MANIFEST_VERSION to LATEST_MANIFEST_VERSION
joan-anthropic Sep 24, 2025
6c05338
refactor: remove schemas.ts re-export, use explicit imports in tests
joan-anthropic Sep 24, 2025
e2d6836
Merge branch 'main' into feat/versioned-schemas
joan-anthropic Oct 17, 2025
143aa9a
test: skip _meta tests for v0.3
joan-anthropic Oct 18, 2025
f7efd3a
add WIP 0.3
joan-anthropic Oct 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/browser.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Browser-compatible exports
export * from "./schemas.js";
export * from "./schemas/latest.js";
export * from "./shared/config.js";
export * from "./shared/constants.js";
export * from "./types.js";
3 changes: 2 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ export * from "./cli/init.js";
export * from "./cli/pack.js";

// Include all shared exports
export * from "./schemas.js";
export * from "./schemas/latest.js";
export * from "./shared/config.js";
export * from "./shared/constants.js";
export * from "./types.js";

// Include node exports since CLI needs them
Expand Down
4 changes: 2 additions & 2 deletions src/cli/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { LATEST_MANIFEST_VERSION } from "../shared/constants.js";
import type { McpbManifest } from "../types.js";

interface PackageJson {
Expand Down Expand Up @@ -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 }
Expand Down
13 changes: 8 additions & 5 deletions src/cli/pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, McpbManifestSchema } from "../schemas.js";
import {
LATEST_MANIFEST_SCHEMA,
LATEST_MANIFEST_VERSION,
} from "../shared/constants.js";
import { getLogger } from "../shared/log.js";
import { initExtension } from "./init.js";

Expand Down Expand Up @@ -92,7 +95,7 @@ export async function packExtension({
try {
const manifestContent = readFileSync(manifestPath, "utf-8");
const manifestData = JSON.parse(manifestContent);
manifest = McpbManifestSchema.parse(manifestData);
manifest = LATEST_MANIFEST_SCHEMA.parse(manifestData);
} catch (error) {
logger.error("ERROR: Failed to parse manifest.json");
if (error instanceof Error) {
Expand All @@ -102,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;
}
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +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.js";
export * from "./schemas/latest.js";
export * from "./shared/config.js";
export * from "./shared/constants.js";
export * from "./types.js";
3 changes: 2 additions & 1 deletion src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from "./node/sign.js";
export * from "./node/validate.js";

// Include all shared exports
export * from "./schemas.js";
export * from "./schemas/latest.js";
export * from "./shared/config.js";
export * from "./shared/constants.js";
export * from "./types.js";
10 changes: 6 additions & 4 deletions src/node/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ 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 {
LATEST_MANIFEST_SCHEMA,
LATEST_MANIFEST_SCHEMA_LOOSE,
} from "../shared/constants.js";

export function validateManifest(inputPath: string): boolean {
try {
Expand All @@ -22,7 +24,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 = LATEST_MANIFEST_SCHEMA.safeParse(manifestData);

if (result.success) {
console.log("Manifest schema validation passes!");
Expand Down Expand Up @@ -72,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 = LooseMcpbManifestSchema.safeParse(manifestData);
const result = LATEST_MANIFEST_SCHEMA_LOOSE.safeParse(manifestData);

if (!result.success) {
throw new Error(
Expand Down
29 changes: 13 additions & 16 deletions src/schemas.ts → src/schemas/0.1.ts
Original file line number Diff line number Diff line change
@@ -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(),
Expand Down Expand Up @@ -34,18 +34,16 @@
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(),
Expand Down Expand Up @@ -82,10 +80,10 @@
.strictObject({
$schema: z.string().optional(),
dxt_version: z
.string()
.literal(MANIFEST_VERSION)
.optional()
.describe("@deprecated Use manifest_version instead"),
manifest_version: z.string().optional(),
manifest_version: z.literal(MANIFEST_VERSION).optional(),
name: z.string(),
display_name: z.string().optional(),
version: z.string(),
Expand All @@ -100,12 +98,11 @@
screenshots: z.array(z.string()).optional(),
server: McpbManifestServerSchema,
tools: z.array(McpbManifestToolSchema).optional(),
tools_generated: z.boolean().optional(),

Check warning on line 101 in src/schemas/0.1.ts

View workflow job for this annotation

GitHub Actions / Test (20.19.x, macos-latest)

Delete `··`

Check warning on line 101 in src/schemas/0.1.ts

View workflow job for this annotation

GitHub Actions / Test (20.19.x, ubuntu-latest)

Delete `··`

Check warning on line 101 in src/schemas/0.1.ts

View workflow job for this annotation

GitHub Actions / Test (22.17.x, windows-latest)

Delete `··`

Check warning on line 101 in src/schemas/0.1.ts

View workflow job for this annotation

GitHub Actions / Test (22.17.x, macos-latest)

Delete `··`

Check warning on line 101 in src/schemas/0.1.ts

View workflow job for this annotation

GitHub Actions / Test (20.19.x, windows-latest)

Delete `··`

Check warning on line 101 in src/schemas/0.1.ts

View workflow job for this annotation

GitHub Actions / Test (22.17.x, ubuntu-latest)

Delete `··`
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()).optional(),
compatibility: McpbManifestCompatibilitySchema.optional(),
user_config: z
.record(z.string(), McpbUserConfigurationOptionSchema)
Expand Down
124 changes: 124 additions & 0 deletions src/schemas/0.2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import * as z from "zod";

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(),
});

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(),
})
.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(),
});
Loading