Skip to content

Commit 2d6dd39

Browse files
Merge remote-tracking branch 'origin/main' into feat/browser-export-versioned-schemas
2 parents 05187d7 + b75f8a6 commit 2d6dd39

8 files changed

Lines changed: 74 additions & 33 deletions

File tree

MANIFEST.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ A full `manifest.json` with most of the optional fields looks like this:
8484
},
8585
"repository": {
8686
"type": "git",
87-
"url": "https://github.com/your-username/my-mcp-extension"
87+
"url": "https://github.com/your-username/my-mcp-extension.git"
8888
},
8989
"homepage": "https://example.com/my-extension",
9090
"documentation": "https://docs.example.com/my-extension",

src/cli/init.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { confirm, input, select } from "@inquirer/prompts";
22
import { existsSync, readFileSync, writeFileSync } from "fs";
33
import { basename, join, resolve } from "path";
44

5-
import { LATEST_MANIFEST_VERSION } from "../shared/constants.js";
6-
import type { McpbManifestLatest } from "../types.js";
5+
import { DEFAULT_MANIFEST_VERSION } from "../shared/constants.js";
6+
import type { McpbManifest } from "../types.js";
77

88
interface PackageJson {
99
name?: string;
@@ -878,14 +878,14 @@ export function buildManifest(
878878
resources: string;
879879
default_locale: string;
880880
},
881-
): McpbManifestLatest {
881+
): McpbManifest {
882882
const { name, displayName, version, description, authorName } = basicInfo;
883883
const { authorEmail, authorUrl } = authorInfo;
884884
const { serverType, entryPoint, mcp_config } = serverConfig;
885885
const { keywords, license, repository } = optionalFields;
886886

887887
return {
888-
manifest_version: LATEST_MANIFEST_VERSION,
888+
manifest_version: DEFAULT_MANIFEST_VERSION,
889889
name,
890890
...(displayName && displayName !== name
891891
? { display_name: displayName }

src/cli/pack.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@ import { basename, join, relative, resolve, sep } from "path";
1313

1414
import { getAllFilesWithCount, readMcpbIgnorePatterns } from "../node/files.js";
1515
import { validateManifest } from "../node/validate.js";
16-
import {
17-
LATEST_MANIFEST_SCHEMA,
18-
LATEST_MANIFEST_VERSION,
19-
} from "../shared/constants.js";
16+
import { MANIFEST_SCHEMAS } from "../shared/constants.js";
2017
import { getLogger } from "../shared/log.js";
18+
import { getManifestVersionFromRawData } from "../shared/manifestVersionResolve.js";
2119
import { initExtension } from "./init.js";
2220

2321
interface PackOptions {
@@ -95,7 +93,18 @@ export async function packExtension({
9593
try {
9694
const manifestContent = readFileSync(manifestPath, "utf-8");
9795
const manifestData = JSON.parse(manifestContent);
98-
manifest = LATEST_MANIFEST_SCHEMA.parse(manifestData);
96+
const manifestVersion = getManifestVersionFromRawData(manifestData);
97+
if (!manifestVersion) {
98+
logger.error(
99+
`ERROR: Manifest version mismatch. Expected "${Object.keys(MANIFEST_SCHEMAS).join(" or ")}", found "${manifestVersion}"`,
100+
);
101+
logger.error(
102+
` Please update the manifest_version in your manifest.json to a supported version`,
103+
);
104+
return false;
105+
}
106+
107+
manifest = MANIFEST_SCHEMAS[manifestVersion].parse(manifestData);
99108
} catch (error) {
100109
logger.error("ERROR: Failed to parse manifest.json");
101110
if (error instanceof Error) {
@@ -104,17 +113,6 @@ export async function packExtension({
104113
return false;
105114
}
106115

107-
const manifestVersion = manifest.manifest_version || manifest.dxt_version;
108-
if (manifestVersion !== LATEST_MANIFEST_VERSION) {
109-
logger.error(
110-
`ERROR: Manifest version mismatch. Expected "${LATEST_MANIFEST_VERSION}", found "${manifestVersion}"`,
111-
);
112-
logger.error(
113-
` Please update the manifest_version in your manifest.json to "${LATEST_MANIFEST_VERSION}"`,
114-
);
115-
return false;
116-
}
117-
118116
// Determine output path
119117
const extensionName = basename(resolvedPath);
120118
const finalOutputPath = outputPath

src/node/validate.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import prettyBytes from "pretty-bytes";
77

88
import { unpackExtension } from "../cli/unpack.js";
99
import {
10-
LATEST_MANIFEST_SCHEMA,
11-
LATEST_MANIFEST_SCHEMA_LOOSE,
10+
MANIFEST_SCHEMAS,
11+
MANIFEST_SCHEMAS_LOOSE,
1212
} from "../shared/constants.js";
13+
import { getManifestVersionFromRawData } from "../shared/manifestVersionResolve.js";
1314

1415
/**
1516
* Check if a buffer contains a valid PNG file signature
@@ -119,8 +120,13 @@ export function validateManifest(inputPath: string): boolean {
119120

120121
const manifestContent = readFileSync(manifestPath, "utf-8");
121122
const manifestData = JSON.parse(manifestContent);
123+
const manifestVersion = getManifestVersionFromRawData(manifestData);
124+
if (!manifestVersion) {
125+
console.log("Unrecognized or unsupported manifest version");
126+
return false;
127+
}
122128

123-
const result = LATEST_MANIFEST_SCHEMA.safeParse(manifestData);
129+
const result = MANIFEST_SCHEMAS[manifestVersion].safeParse(manifestData);
124130

125131
if (result.success) {
126132
console.log("Manifest schema validation passes!");
@@ -192,7 +198,12 @@ export async function cleanMcpb(inputPath: string) {
192198
const manifestPath = resolve(unpackPath, "manifest.json");
193199
const originalManifest = await fs.readFile(manifestPath, "utf-8");
194200
const manifestData = JSON.parse(originalManifest);
195-
const result = LATEST_MANIFEST_SCHEMA_LOOSE.safeParse(manifestData);
201+
const manifestVersion = getManifestVersionFromRawData(manifestData);
202+
if (!manifestVersion) {
203+
throw new Error("Unrecognized or unsupported manifest version");
204+
}
205+
const result =
206+
MANIFEST_SCHEMAS_LOOSE[manifestVersion].safeParse(manifestData);
196207

197208
if (!result.success) {
198209
throw new Error(

src/shared/constants.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@ import { McpbManifestSchema as CurrentLooseManifestSchema } from "../schemas_loo
99

1010
/**
1111
* Latest manifest version - the version that new manifests should use
12+
* @deprecated
1213
*/
1314
export const LATEST_MANIFEST_VERSION = "0.3" as const;
1415

16+
/**
17+
* Default manifest version for new packages
18+
*/
19+
export const DEFAULT_MANIFEST_VERSION = "0.2" as const;
20+
1521
/**
1622
* Map of manifest versions to their strict schemas
1723
*/
@@ -32,10 +38,12 @@ export const MANIFEST_SCHEMAS_LOOSE = {
3238

3339
/**
3440
* Get the latest manifest schema based on LATEST_MANIFEST_VERSION
41+
* @deprecated
3542
*/
3643
export const LATEST_MANIFEST_SCHEMA = CurrentManifestSchema;
3744

3845
/**
3946
* Get the latest loose manifest schema based on LATEST_MANIFEST_VERSION
47+
* @deprecated
4048
*/
4149
export const LATEST_MANIFEST_SCHEMA_LOOSE = CurrentLooseManifestSchema;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { MANIFEST_SCHEMAS } from "./constants.js";
2+
3+
export function getManifestVersionFromRawData(manifestData: unknown) {
4+
let manifestVersion: keyof typeof MANIFEST_SCHEMAS | null = null;
5+
if (
6+
typeof manifestData === "object" &&
7+
manifestData &&
8+
"manifest_version" in manifestData &&
9+
typeof manifestData.manifest_version === "string" &&
10+
Object.keys(MANIFEST_SCHEMAS).includes(manifestData.manifest_version)
11+
) {
12+
manifestVersion =
13+
manifestData.manifest_version as keyof typeof MANIFEST_SCHEMAS;
14+
} else if (
15+
typeof manifestData === "object" &&
16+
manifestData &&
17+
"dxt_version" in manifestData &&
18+
typeof manifestData.dxt_version === "string" &&
19+
Object.keys(MANIFEST_SCHEMAS).includes(manifestData.dxt_version)
20+
) {
21+
manifestVersion = manifestData.dxt_version as keyof typeof MANIFEST_SCHEMAS;
22+
}
23+
return manifestVersion;
24+
}

test/cli.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { execSync } from "node:child_process";
22
import fs from "node:fs";
33
import { join } from "node:path";
44

5-
import { LATEST_MANIFEST_VERSION } from "../src/schemas/index.js";
5+
import { DEFAULT_MANIFEST_VERSION } from "../src/shared/constants";
66

77
interface ExecSyncError extends Error {
88
stdout: Buffer;
@@ -113,7 +113,7 @@ describe("DXT CLI", () => {
113113
fs.writeFileSync(
114114
manifestWithIcon,
115115
JSON.stringify({
116-
manifest_version: LATEST_MANIFEST_VERSION,
116+
manifest_version: DEFAULT_MANIFEST_VERSION,
117117
name: "test-with-icon",
118118
version: "1.0.0",
119119
description: "Test with icon",
@@ -140,7 +140,7 @@ describe("DXT CLI", () => {
140140
fs.writeFileSync(
141141
manifestWithUrl,
142142
JSON.stringify({
143-
manifest_version: LATEST_MANIFEST_VERSION,
143+
manifest_version: DEFAULT_MANIFEST_VERSION,
144144
name: "test-with-url",
145145
version: "1.0.0",
146146
description: "Test with URL",
@@ -177,7 +177,7 @@ describe("DXT CLI", () => {
177177
fs.writeFileSync(
178178
join(tempDir, "manifest.json"),
179179
JSON.stringify({
180-
manifest_version: LATEST_MANIFEST_VERSION,
180+
manifest_version: DEFAULT_MANIFEST_VERSION,
181181
name: "Test Extension",
182182
version: "1.0.0",
183183
description: "A test extension",
@@ -274,7 +274,7 @@ describe("DXT CLI", () => {
274274
fs.writeFileSync(
275275
join(tempExecDir, "manifest.json"),
276276
JSON.stringify({
277-
manifest_version: LATEST_MANIFEST_VERSION,
277+
manifest_version: DEFAULT_MANIFEST_VERSION,
278278
name: "Test Executable Extension",
279279
version: "1.0.0",
280280
description: "A test extension with executable files",

test/init.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
getDefaultRepositoryUrl,
1111
readPackageJson,
1212
} from "../src/cli/init.js";
13-
import { LATEST_MANIFEST_VERSION } from "../src/schemas/index.js";
13+
import { DEFAULT_MANIFEST_VERSION } from "../src/shared/constants.js";
1414

1515
// Mock the fs module
1616
jest.mock("fs", () => ({
@@ -220,7 +220,7 @@ describe("init functions", () => {
220220
);
221221

222222
expect(manifest).toEqual({
223-
manifest_version: LATEST_MANIFEST_VERSION,
223+
manifest_version: DEFAULT_MANIFEST_VERSION,
224224
name: "test-extension",
225225
version: "1.0.0",
226226
description: "Test description",
@@ -322,7 +322,7 @@ describe("init functions", () => {
322322
);
323323

324324
expect(manifest).toEqual({
325-
manifest_version: LATEST_MANIFEST_VERSION,
325+
manifest_version: DEFAULT_MANIFEST_VERSION,
326326
name: "test-extension",
327327
display_name: "Test Extension",
328328
version: "1.0.0",

0 commit comments

Comments
 (0)