Merge pull request #114 from anthropics/feat/versioned-schemas
feat: versioned schemas
This commit is contained in:
commit
d595dd66dc
23 changed files with 495 additions and 54 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
// Browser-compatible exports
|
// Browser-compatible exports
|
||||||
export * from "./schemas.js";
|
export * from "./schemas/latest.js";
|
||||||
export * from "./shared/config.js";
|
export * from "./shared/config.js";
|
||||||
|
export * from "./shared/constants.js";
|
||||||
export * from "./types.js";
|
export * from "./types.js";
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@ export * from "./cli/init.js";
|
||||||
export * from "./cli/pack.js";
|
export * from "./cli/pack.js";
|
||||||
|
|
||||||
// Include all shared exports
|
// Include all shared exports
|
||||||
export * from "./schemas.js";
|
export * from "./schemas/latest.js";
|
||||||
export * from "./shared/config.js";
|
export * from "./shared/config.js";
|
||||||
|
export * from "./shared/constants.js";
|
||||||
export * from "./types.js";
|
export * from "./types.js";
|
||||||
|
|
||||||
// Include node exports since CLI needs them
|
// Include node exports since CLI needs them
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { confirm, input, select } from "@inquirer/prompts";
|
||||||
import { existsSync, readFileSync, writeFileSync } from "fs";
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||||
import { basename, join, resolve } from "path";
|
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";
|
import type { McpbManifest } from "../types.js";
|
||||||
|
|
||||||
interface PackageJson {
|
interface PackageJson {
|
||||||
|
|
@ -774,7 +774,7 @@ export function buildManifest(
|
||||||
const { keywords, license, repository } = optionalFields;
|
const { keywords, license, repository } = optionalFields;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
manifest_version: CURRENT_MANIFEST_VERSION,
|
manifest_version: LATEST_MANIFEST_VERSION,
|
||||||
name,
|
name,
|
||||||
...(displayName && displayName !== name
|
...(displayName && displayName !== name
|
||||||
? { display_name: displayName }
|
? { display_name: displayName }
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,10 @@ import { basename, join, relative, resolve, sep } from "path";
|
||||||
|
|
||||||
import { getAllFilesWithCount, readMcpbIgnorePatterns } from "../node/files.js";
|
import { getAllFilesWithCount, readMcpbIgnorePatterns } from "../node/files.js";
|
||||||
import { validateManifest } from "../node/validate.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 { getLogger } from "../shared/log.js";
|
||||||
import { initExtension } from "./init.js";
|
import { initExtension } from "./init.js";
|
||||||
|
|
||||||
|
|
@ -92,7 +95,7 @@ export async function packExtension({
|
||||||
try {
|
try {
|
||||||
const manifestContent = readFileSync(manifestPath, "utf-8");
|
const manifestContent = readFileSync(manifestPath, "utf-8");
|
||||||
const manifestData = JSON.parse(manifestContent);
|
const manifestData = JSON.parse(manifestContent);
|
||||||
manifest = McpbManifestSchema.parse(manifestData);
|
manifest = LATEST_MANIFEST_SCHEMA.parse(manifestData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("ERROR: Failed to parse manifest.json");
|
logger.error("ERROR: Failed to parse manifest.json");
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
|
|
@ -102,12 +105,12 @@ export async function packExtension({
|
||||||
}
|
}
|
||||||
|
|
||||||
const manifestVersion = manifest.manifest_version || manifest.dxt_version;
|
const manifestVersion = manifest.manifest_version || manifest.dxt_version;
|
||||||
if (manifestVersion !== CURRENT_MANIFEST_VERSION) {
|
if (manifestVersion !== LATEST_MANIFEST_VERSION) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`ERROR: Manifest version mismatch. Expected "${CURRENT_MANIFEST_VERSION}", found "${manifestVersion}"`,
|
`ERROR: Manifest version mismatch. Expected "${LATEST_MANIFEST_VERSION}", found "${manifestVersion}"`,
|
||||||
);
|
);
|
||||||
logger.error(
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ export * from "./cli/unpack.js";
|
||||||
export * from "./node/files.js";
|
export * from "./node/files.js";
|
||||||
export * from "./node/sign.js";
|
export * from "./node/sign.js";
|
||||||
export * from "./node/validate.js";
|
export * from "./node/validate.js";
|
||||||
export * from "./schemas.js";
|
export * from "./schemas/latest.js";
|
||||||
export * from "./shared/config.js";
|
export * from "./shared/config.js";
|
||||||
|
export * from "./shared/constants.js";
|
||||||
export * from "./types.js";
|
export * from "./types.js";
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ export * from "./node/sign.js";
|
||||||
export * from "./node/validate.js";
|
export * from "./node/validate.js";
|
||||||
|
|
||||||
// Include all shared exports
|
// Include all shared exports
|
||||||
export * from "./schemas.js";
|
export * from "./schemas/latest.js";
|
||||||
export * from "./shared/config.js";
|
export * from "./shared/config.js";
|
||||||
|
export * from "./shared/constants.js";
|
||||||
export * from "./types.js";
|
export * from "./types.js";
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,10 @@ import { join, resolve } from "path";
|
||||||
import prettyBytes from "pretty-bytes";
|
import prettyBytes from "pretty-bytes";
|
||||||
|
|
||||||
import { unpackExtension } from "../cli/unpack.js";
|
import { unpackExtension } from "../cli/unpack.js";
|
||||||
import { McpbManifestSchema } from "../schemas.js";
|
import {
|
||||||
import { McpbManifestSchema as LooseMcpbManifestSchema } from "../schemas-loose.js";
|
LATEST_MANIFEST_SCHEMA,
|
||||||
|
LATEST_MANIFEST_SCHEMA_LOOSE,
|
||||||
|
} from "../shared/constants.js";
|
||||||
|
|
||||||
export function validateManifest(inputPath: string): boolean {
|
export function validateManifest(inputPath: string): boolean {
|
||||||
try {
|
try {
|
||||||
|
|
@ -22,7 +24,7 @@ export function validateManifest(inputPath: string): boolean {
|
||||||
const manifestContent = readFileSync(manifestPath, "utf-8");
|
const manifestContent = readFileSync(manifestPath, "utf-8");
|
||||||
const manifestData = JSON.parse(manifestContent);
|
const manifestData = JSON.parse(manifestContent);
|
||||||
|
|
||||||
const result = McpbManifestSchema.safeParse(manifestData);
|
const result = LATEST_MANIFEST_SCHEMA.safeParse(manifestData);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
console.log("Manifest schema validation passes!");
|
console.log("Manifest schema validation passes!");
|
||||||
|
|
@ -72,7 +74,7 @@ export async function cleanMcpb(inputPath: string) {
|
||||||
const manifestPath = resolve(unpackPath, "manifest.json");
|
const manifestPath = resolve(unpackPath, "manifest.json");
|
||||||
const originalManifest = await fs.readFile(manifestPath, "utf-8");
|
const originalManifest = await fs.readFile(manifestPath, "utf-8");
|
||||||
const manifestData = JSON.parse(originalManifest);
|
const manifestData = JSON.parse(originalManifest);
|
||||||
const result = LooseMcpbManifestSchema.safeParse(manifestData);
|
const result = LATEST_MANIFEST_SCHEMA_LOOSE.safeParse(manifestData);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
|
||||||
124
src/schemas/0.1.ts
Normal file
124
src/schemas/0.1.ts
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
import * as z from "zod";
|
||||||
|
|
||||||
|
export const MANIFEST_VERSION = "0.1";
|
||||||
|
|
||||||
|
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(),
|
||||||
|
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(),
|
||||||
|
});
|
||||||
124
src/schemas/0.2.ts
Normal file
124
src/schemas/0.2.ts
Normal file
|
|
@ -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(),
|
||||||
|
});
|
||||||
126
src/schemas/0.3.ts
Normal file
126
src/schemas/0.3.ts
Normal file
|
|
@ -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(),
|
||||||
|
});
|
||||||
8
src/schemas/index.ts
Normal file
8
src/schemas/index.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
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,
|
||||||
|
McpbManifestSchema,
|
||||||
|
} from "./latest.js";
|
||||||
1
src/schemas/latest.ts
Normal file
1
src/schemas/latest.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./0.2.js";
|
||||||
126
src/schemas_loose/0.1.ts
Normal file
126
src/schemas_loose/0.1.ts
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
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(),
|
||||||
|
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(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(),
|
||||||
|
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.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(),
|
||||||
|
});
|
||||||
127
src/schemas_loose/0.2.ts
Normal file
127
src/schemas_loose/0.2.ts
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
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(),
|
||||||
|
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(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(),
|
||||||
|
})
|
||||||
|
.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"]),
|
||||||
|
publisher: z.string().optional(),
|
||||||
|
issuer: z.string().optional(),
|
||||||
|
valid_from: z.string().optional(),
|
||||||
|
valid_to: z.string().optional(),
|
||||||
|
fingerprint: z.string().optional(),
|
||||||
|
});
|
||||||
3
src/schemas_loose/index.ts
Normal file
3
src/schemas_loose/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
export * as v0_1 from "./0.1.js";
|
||||||
|
export * as v0_2 from "./0.2.js";
|
||||||
|
export * as latest from "./latest.js";
|
||||||
1
src/schemas_loose/latest.ts
Normal file
1
src/schemas_loose/latest.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./0.2.js";
|
||||||
37
src/shared/constants.ts
Normal file
37
src/shared/constants.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
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";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Latest manifest version - the version that new manifests should use
|
||||||
|
*/
|
||||||
|
export const LATEST_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 latest manifest schema based on LATEST_MANIFEST_VERSION
|
||||||
|
*/
|
||||||
|
export const LATEST_MANIFEST_SCHEMA = CurrentManifestSchema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the latest loose manifest schema based on LATEST_MANIFEST_VERSION
|
||||||
|
*/
|
||||||
|
export const LATEST_MANIFEST_SCHEMA_LOOSE = CurrentLooseManifestSchema;
|
||||||
|
|
@ -14,7 +14,7 @@ import type {
|
||||||
McpbUserConfigurationOptionSchema,
|
McpbUserConfigurationOptionSchema,
|
||||||
McpbUserConfigValuesSchema,
|
McpbUserConfigValuesSchema,
|
||||||
McpServerConfigSchema,
|
McpServerConfigSchema,
|
||||||
} from "./schemas.js";
|
} from "./schemas/latest.js";
|
||||||
|
|
||||||
export type McpServerConfig = z.infer<typeof McpServerConfigSchema>;
|
export type McpServerConfig = z.infer<typeof McpServerConfigSchema>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { execSync } from "node:child_process";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
|
|
||||||
import { CURRENT_MANIFEST_VERSION } from "../src/schemas.js";
|
import { LATEST_MANIFEST_VERSION } from "../src/schemas/index.js";
|
||||||
|
|
||||||
interface ExecSyncError extends Error {
|
interface ExecSyncError extends Error {
|
||||||
stdout: Buffer;
|
stdout: Buffer;
|
||||||
|
|
@ -93,7 +93,7 @@ describe("DXT CLI", () => {
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
join(tempDir, "manifest.json"),
|
join(tempDir, "manifest.json"),
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
manifest_version: CURRENT_MANIFEST_VERSION,
|
manifest_version: LATEST_MANIFEST_VERSION,
|
||||||
name: "Test Extension",
|
name: "Test Extension",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
description: "A test extension",
|
description: "A test extension",
|
||||||
|
|
@ -190,7 +190,7 @@ describe("DXT CLI", () => {
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
join(tempExecDir, "manifest.json"),
|
join(tempExecDir, "manifest.json"),
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
manifest_version: CURRENT_MANIFEST_VERSION,
|
manifest_version: LATEST_MANIFEST_VERSION,
|
||||||
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",
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ describe("getMcpConfigForManifest", () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const baseManifest: McpbManifest = {
|
const baseManifest: McpbManifest = {
|
||||||
manifest_version: "1.0.0",
|
manifest_version: "0.2",
|
||||||
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 = {
|
||||||
manifest_version: "1.0.0",
|
manifest_version: "0.2",
|
||||||
name: "test-extension",
|
name: "test-extension",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
description: "Test extension",
|
description: "Test extension",
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue