Compare commits

...
Author SHA1 Message Date
joan-anthropic
70fe3b34cd
Merge pull request #234 from modelcontextprotocol/revert-233-docs/publishing-bundle-readme
Some checks failed
Test / Test (push) Has been cancelled
Test / Test-1 (push) Has been cancelled
Test / Test-2 (push) Has been cancelled
Test / Test-3 (push) Has been cancelled
Test / Test-4 (push) Has been cancelled
Test / Test-5 (push) Has been cancelled
Test / Validate JSON Schemas (push) Has been cancelled
Revert "docs: add "Publishing Your Bundle" section to README"
2026-04-22 12:16:05 -04:00
Tobin South
b4acc3f730
Revert "docs: add "Publishing Your Bundle" section to README" 2026-04-22 17:14:57 +01:00
Tobin South
0817c20eb3
Merge pull request #233 from bryan-anthropic/docs/publishing-bundle-readme
docs: add "Publishing Your Bundle" section to README
2026-04-22 09:14:13 -07:00
Bryan Thompson
5161613c79
docs: add "Publishing Your Bundle" section to README
Covers the recommended distribution pattern (GitHub Release assets),
tag convention for monorepos, per-platform asset naming, compatibility.
platforms correctness, a minimum CI shape, and ${__dirname} guidance
for relocatable entry points.
2026-04-22 10:51:05 -05:00
Tobin South
f9a551bf47
Merge pull request #231 from modelcontextprotocol/fix/chrome-applescript-json-stringify-interpolation
fix(examples/chrome-applescript): use JSON.stringify for AppleScript string interpolation
2026-04-17 13:04:22 -07:00
Bryan Thompson
73f8475a80
fix(examples/chrome-applescript): use JSON.stringify for AppleScript string interpolation 2026-04-17 14:22:56 -05:00
Tobin South
e2d6196a39
Merge pull request #230 from modelcontextprotocol/fix/chrome-applescript-tab-id-sanitize
fix(examples/chrome-applescript): sanitize tab_id to prevent AppleScript injection
2026-04-17 12:12:41 -07:00
Bryan Thompson
dace08d31f
fix(examples/chrome-applescript): sanitize tab_id to prevent AppleScript injection
The inputSchema `type: "number"` is advisory only — runtime may receive a
string payload that gets interpolated into the osascript template. Coerce
tab_id via Number.parseInt before interpolating at all four sites.

Affected sites:
- findTabById(tabId)
- executeTabOperation(tabId, ...) (close_tab, switch_to_tab, reload_tab,
  go_back, go_forward)
- execute_javascript handler
- get_page_content handler

The shared toSafeTabId() helper returns null for missing values (preserving
the active-tab fallthrough) and throws on non-numeric input (surfacing misuse
via the existing request-level try/catch, consistent with the missing-code
path in execute_javascript).
2026-04-17 13:49:30 -05:00
Bryan Thompson
a3a662451e
Merge pull request #186 from vcolin7/patch-1
[Documentation] Fix signature format documentation to match implementation
2026-04-16 07:42:25 -05:00
Bryan Thompson
e54083549b
Merge pull request #207 from modelcontextprotocol/examples/calculator-rust
feat: add Rust binary calculator example
2026-04-14 07:43:02 -05:00
Bryan Thompson
a2c331b513
Merge pull request #208 from modelcontextprotocol/feat/pack-manifest-flag
feat: add --manifest flag to pack command
2026-04-14 07:42:57 -05:00
Bryan Thompson
a3bd97131e
Merge pull request #209 from modelcontextprotocol/feat/enhanced-validate
feat: enhanced structural validation for validate command
2026-04-14 07:42:50 -05:00
Bryan Thompson
7f4596d8c8
Merge pull request #221 from modelcontextprotocol/fix/platform-overrides-env-merge
Fixes #217 — platform_overrides.*.env was replacing base mcp_config.env instead of merging. One-line fix: spread-merge instead of overwrite.
2026-04-13 12:59:06 -05:00
joan-anthropic
cf1f956935
Merge pull request #206 from modelcontextprotocol/worktree-fix-examples-uv-graduation
fix: repair broken examples and graduate UV runtime
2026-04-05 11:01:13 -07:00
Bryan Thompson
122ef0e9e9
fix: enforce executable permissions on binary entry points during pack
When server.type is "binary", mcpb pack now ensures the entry_point
file has execute bits (|0o111) in the ZIP external_attr, regardless
of the source filesystem permissions. This prevents EACCES failures
when Claude Desktop extracts Windows-built binary MCPBs (which store
644 because Windows has no Unix execute bit).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 09:18:30 -05:00
Bryan Thompson
cb052a20e5
fix: merge platform_overrides env with base env instead of replacing
platform_overrides.*.env was replacing the entire mcp_config.env object
instead of merging, causing base env vars (including ${user_config.*}
references) to be silently dropped when platform overrides defined any
env vars.

Fixes #217

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 08:23:18 -05:00
Tobin South
8f5f2104df
Merge pull request #204 from modelcontextprotocol/fix/eocd-comment-length
fix: update ZIP EOCD comment_length when signing
2026-03-18 18:08:17 +00:00
Bryan Thompson
f14863bcdc
feat: enhanced structural validation for mcpb validate (#57)
Add three pre-pack validators to catch common runtime failures early:

- validateEntryPoint: checks file exists, extension matches server type,
  binary has executable bit (Unix)
- validateCommandVariables: scans mcp_config for unrecognized ${...}
  variables against the runtime allowlist
- validateSensitiveFiles: warns about credentials.json, *.pem, *.key,
  .ssh/, etc. that would be bundled

validateManifest() now accepts optional { projectDir } to separate the
manifest directory from the source file directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 06:56:55 -05:00
Bryan Thompson
f4671638a2
feat: add --manifest flag to pack command (#87)
Allow specifying an external manifest file path with `mcpb pack --manifest <path>`.
The manifest resolves relative to CWD, is validated, injected into the bundle,
and errors immediately if the specified file is not found.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 06:54:22 -05:00
Bryan Thompson
a907aead99
chore: remove Dockerfile and .gitignore from calculator-rust example
Align with other examples — no example ships a Dockerfile or its own
.gitignore. Rust build artifacts are now covered by the repo-level
.gitignore instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 16:41:30 -05:00
Bryan Thompson
cc4aa751b6
feat: add Rust binary calculator example
First example of the binary server type — a compiled Rust MCP server
packaged as an MCPB. Based on the official Rust SDK calculator example
(rmcp 1.2.0, 2 tools: sum/sub, ~80 LOC).

Includes Cargo.toml, Dockerfile for Docker-based builds, .mcpbignore
to exclude source from the bundle, and README with build/pack/test
instructions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 16:36:47 -05:00
Bryan Thompson
a5d9ae8ed2
fix: repair broken examples and graduate UV runtime from experimental
- hello-world-node: wrap server startup in async main() with proper
  await on server.connect(transport) — fixes crash on initialize in
  Claude Desktop UtilityProcess runtime (closes #200)
- hello-world-uv: add required mcp_config block — v0.4 schema requires
  it but the example omitted it, causing mcpb pack to fail
- file-manager-python: convert from broken v0.1/python to v0.4/uv —
  the old manifest had privacy_policies on v0.1 (schema violation),
  used command "python" (ENOENT on macOS), and had no bundled deps.
  Now uses UV runtime with proper mcp_config (closes #47, closes #72)
- Graduate UV runtime from experimental across docs and schema comments
- Bump DEFAULT_MANIFEST_VERSION from 0.2 to 0.3

All three examples verified: pack succeeds, server responds to MCP
initialize over stdio, tools/list returns expected tools.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-12 11:16:30 -05:00
Bryan Thompson
bb676eb17d
fix: update ZIP EOCD comment_length when signing MCPB files (#194)
The signMcpbFile function appended a signature block to the ZIP file but
did not update the EOCD comment_length field. Strict ZIP parsers (like
Claude Desktop's) rejected these files because the declared comment
length didn't account for the appended signature data.

Now scans backwards for the EOCD magic bytes, reads the current
comment_length, and adds the signature block length before concatenating.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-12 08:59:13 -05:00
Tobin South
1dca91e2be
Merge pull request #178 from modelcontextprotocol/chore/apache-2.0-license
chore: update licensing to Apache 2.0 for new contributions
2026-02-12 10:24:17 -08:00
vcolin7
19afbcdc18
Update MCPB signature format description
Clarify the MCPB signature format in documentation.
2026-02-06 16:13:29 -08:00
Adam Jones
24aa4efc88
chore: update licensing to Apache 2.0 for new contributions 2026-01-12 22:50:15 +00:00
joan-anthropic
27083dcf93
Merge pull request #172 from modelcontextprotocol/feat/init-manifest-version-option
feat: add --manifest-version option to init command
2025-12-03 21:32:27 -08:00
Joan Xie
163fa29a1c
style: fix Prettier formatting in cli.ts
Break function parameters onto separate lines with trailing comma.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 21:03:04 -08:00
joan-anthropic
2a788100a6
Merge pull request #173 from modelcontextprotocol/fix/mcp-config-required
fix: make mcp_config required for all server types in v0.4 schema
2025-12-03 20:49:16 -08:00
Joan Xie
1dbbffc972
fix: make mcp_config required for all server types in v0.4 schema
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 20:48:31 -08:00
Joan Xie
761e834ba8
feat: add --manifest-version option to init command
Allow developers to specify which manifest version to use when
initializing a new manifest.json file.

Usage: mcpb init --manifest-version 0.3

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 20:18:45 -08:00
Alexander Sklar
3635e20ca8
Merge pull request #169 from asklar/asklar-patch-1
Fix file-system-node example
2025-12-03 18:53:50 -08:00
joan-anthropic
7c7f4b6af0
Merge pull request #168 from modelcontextprotocol/fix/node-forge-vulnerabilities
fix: upgrade node-forge to 1.3.2 to address security vulnerabilities
2025-12-03 17:08:35 -08:00
Alexander Sklar
2ed5481016
Bump version and update dependencies in package.json
update filesystem server version
2025-12-03 17:07:25 -08:00
Joan Xie
be3b8f2561
fix: upgrade node-forge to 1.3.2 to address security vulnerabilities
Fixes three known vulnerabilities:
- GHSA-554w-wpv2-vw27: ASN.1 Unbounded Recursion (High)
- GHSA-5gfm-wpxj-wjgq: ASN.1 Validator Desynchronization (High)
- GHSA-65ch-62r8-g69g: ASN.1 OID Integer Truncation (Medium)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 17:06:23 -08:00
joan-anthropic
9c22416146
Merge pull request #167 from modelcontextprotocol/bump-minor-version-2.1.0
chore: bump minor version to 2.1.0
2025-12-03 16:56:10 -08:00
Joan Xie
2ab44ffa5b
chore: bump minor version to 2.1.0
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 16:51:56 -08:00
joan-anthropic
970f2d5e5d
Merge pull request #158 from modelcontextprotocol/joan/uv-runtime-support
feat: add experimental UV runtime support in manifest v0.4
2025-12-03 16:50:01 -08:00
Joan Xie
ca4a8819a0
chore: mark v0.4 schema as experimental
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 11:48:15 -08:00
Joan Xie
d90365e626
feat: add UV runtime support in manifest v0.4
Add UV as a new server type for Python extensions that use UV runtime
for dependency management instead of bundling dependencies.

Schema changes (v0.4):
- Add "uv" to server.type enum
- Make mcp_config optional (not needed for UV type)
- UV extensions rely on pyproject.toml for dependencies

Documentation:
- Add UV runtime section to MANIFEST.md explaining benefits and usage
- Update README.md to recommend UV runtime for Python
- Add complete hello-world-uv example

Benefits of UV runtime:
- Cross-platform support (Windows/macOS/Linux, Intel/ARM)
- Small bundle size (~100 KB vs 5-10 MB)
- Handles compiled dependencies portably
- No user Python installation required

Example manifest:
{
  "manifest_version": "0.4",
  "server": {
    "type": "uv",
    "entry_point": "src/server.py"
  }
}

Co-authored-by: Joan <joan@anthropic.com>
2025-12-02 21:22:19 -08:00
joan-anthropic
dd9502e8ec
Merge pull request #151 from anthropics/fix/backport-privacy-policices-0_1
fix: remove _meta from 0.1
2025-11-06 13:09:39 -08:00
Joan Xie
349b0ceb47
chore: update patch version 2025-11-06 11:10:53 -08:00
Joan Xie
00e4bb9d10
chore: update version 2025-11-06 11:02:42 -08:00
Joan Xie
671d3d6f2d
rm privacy_policies 2025-11-06 11:01:20 -08:00
Joan Xie
29d23abfe6
fix: backport privacy_policies to 0.1, remove _meta 2025-11-06 09:29:33 -08:00
joan-anthropic
dc7e1514ce
Merge pull request #150 from anthropics/feat/restore-type-exports
Fix: Restore type exports
2025-11-04 13:11:11 -08:00
Joan Xie
d2826644b6
Restore missing type exports for mcpb package
- Export McpbManifestAny and Logger types from types.js
- Export McpbSignatureInfo and McpbUserConfigValues from shared/common.ts
- Add exports to both main and browser entry points
- Bump version to 2.0.1

This eliminates the need for manual type inference in consuming code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 13:09:14 -08:00
joan-anthropic
5079fcfe30
Merge pull request #148 from anthropics/feat/browser-export-versioned-schemas
feat: export versioned zod schemas in mcpb/browser, remove vLatest artifacts
2025-11-04 10:39:43 -08:00
Samuel Attard
5f6b15bc81
remove da bad tings 2025-11-04 10:33:16 -08:00
Joan Xie
5f87ea58d6
Comment out localization parameter in tests
The localization parameter is commented out in the buildManifest function
signature, so it should also be commented out in the test calls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 16:37:27 -08:00
Joan Xie
e4f1236bf2
Fix TypeScript error: remove localization argument from buildManifest call
The buildManifest function signature has the localization parameter
commented out (expecting 13 params), but the function call was still
passing it as the 14th argument, causing a type error.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 16:26:38 -08:00
Joan Xie
08cb52bc86
remove localization param 2025-11-03 16:07:24 -08:00
Joan Xie
e59797f9ce
chore: major version bump 2025-11-03 16:04:56 -08:00
Joan Xie
07b77432a6
Fix lint errors: sort imports and rename unused parameter
- Reorganize imports in types.ts to satisfy simple-import-sort
- Rename unused localization parameter to _localization in init.ts
2025-11-03 16:02:09 -08:00
Joan Xie
3a9ee6e007
Export schemas/index instead of specific version
Changed all entry points (index.ts, cli.ts, node.ts) to export from schemas/index.js
instead of schemas/0.3.js. This provides access to all versioned schemas (v0_1, v0_2,
v0_3, vAny) and VERSIONED_MANIFEST_SCHEMAS without exposing a specific version.
2025-11-03 15:59:40 -08:00
Joan Xie
21c9710584
Fix lint errors in types.ts and remove any casts
- Use import type for VERSIONED_MANIFEST_SCHEMAS and DEFAULT_MANIFEST_VERSION
- Remove unnecessary any type annotations from test file
2025-11-03 15:57:20 -08:00
Joan Xie
8018a9a2e0
Remove latest schema reference from build script
The build script was still importing from the deleted schemas/latest.js file.
Updated to import McpbSignatureInfoSchema from 0.3.js and removed the
mcpb-manifest-latest entry from versionedManifestSchemas.
2025-11-03 15:54:54 -08:00
Joan Xie
3fffc30560
Use McpbManifestDefault derived from DEFAULT_MANIFEST_VERSION
Changes:
- Create McpbManifestDefault type derived from VERSIONED_MANIFEST_SCHEMAS[DEFAULT_MANIFEST_VERSION]
- Update init.ts to use McpbManifestDefault instead of hardcoded v0.2 schema
- Import schema types from version matching DEFAULT_MANIFEST_VERSION (0.2)
- Update test to match commented-out localization field
- Make McpbManifest (deprecated) point to McpbManifestDefault

This makes the codebase more maintainable by deriving types from DEFAULT_MANIFEST_VERSION instead of hardcoding version references.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 15:47:05 -08:00
Joan Xie
70c3615fc9
Add LATEST_MANIFEST_VERSION export (hardcoded to 0.3)
Export LATEST_MANIFEST_VERSION to indicate the maximum supported manifest version by the vAny schema. This allows clients to know what the highest version is that they can use.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 15:35:15 -08:00
Joan Xie
efe9e3345d
Make McpbManifest point to v0.2 for backwards compatibility
- Change McpbManifest type to point to v0.2 schema instead of McpbManifestAny
- Add DEFAULT_MANIFEST_VERSION export to browser.ts
- Update test fixtures to use manifest_version "0.2" when using McpbManifest type
- Keep @deprecated annotation directing users to McpbManifestAny for multi-version support

This maintains backwards compatibility for existing code using McpbManifest while encouraging new code to use McpbManifestAny for broader version support.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 15:33:31 -08:00
Joan Xie
30a3b8e779
Remove vLatest concept and associated files
Remove the concept of "vLatest" throughout the codebase to encourage use of McpbManifestAny which supports all manifest versions. Changes include:

- Delete src/schemas/latest.ts and src/schemas_loose/latest.ts
- Remove vLatest and latest-related exports from schema index files
- Remove McpbManifestLatest type, replace McpbManifest to point to McpbManifestAny
- Remove LATEST_MANIFEST_VERSION, LATEST_MANIFEST_SCHEMA constants
- Update all main export files (index.ts, cli.ts, node.ts) to export from 0.3.js instead of latest.js
- Update tests to use v0_3.McpbManifestSchema explicitly
- Add @deprecated annotation to McpbManifest directing users to McpbManifestAny

This encourages better version compatibility by using the union type that supports all manifest versions rather than assuming a single "latest" version.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 15:30:03 -08:00
Joan Xie
d7f76fc02d
Fix linting issues
- Remove unused McpbManifest import from config.ts
- Auto-fix formatting and import sorting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 20:41:34 -07:00
Joan Xie
e7d6ea3e68
Fix type error in buildManifest return type
Changed return type to use the specific v0.2 manifest schema type since the
function returns a manifest with DEFAULT_MANIFEST_VERSION (0.2).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 20:38:05 -07:00
Joan Xie
7f40d5be42
rm McpbUserConfigValuesSchema export 2025-11-01 20:34:47 -07:00
Joan Xie
753f27e1ba
Revert yarn.lock to match main (zod 3.25.67)
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 20:31:26 -07:00
Joan Xie
3538bd4f3b
Bump version to 1.3.0
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 20:29:04 -07:00
Joan Xie
2d6dd39b3e
Merge remote-tracking branch 'origin/main' into feat/browser-export-versioned-schemas 2025-11-01 20:28:49 -07:00
Joan Xie
05187d7235
Remove zod resolution and bump version to 1.2.0
- Removed zod version resolution from package.json
- Bumped version from 1.1.5 to 1.2.0

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 20:27:58 -07:00
Joan Xie
c137df512d
Remove validate utilities from browser exports
This removes the validateManifest utilities that were added to the browser bundle. These functions are not needed for the browser export.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 19:48:58 -07:00
Joan Xie
2d76201204
Export versioned schemas and validation utilities in browser bundle
- Update browser.ts to export validation utilities
- Export McpbManifestSchema for backwards compatibility
- Update config.ts to accept McpbManifestAny for broader manifest version support
- Add validate.ts with version-aware validation functions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 16:34:02 -07:00
Joan Xie
5fb25a253e
add McpbManifestAny type 2025-11-01 15:46:37 -07:00
Joan Xie
86166630b4
revert: undo preprocessing changes to any.ts and types.ts
Reverts the preprocessing logic and type name changes to restore
the simpler union schema approach.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 15:37:15 -07:00
Joan Xie
f3ac79afda
update browser exports to incl. vAny schema 2025-11-01 15:27:38 -07:00
Joan Xie
98fc900d5a
WIP 2025-11-01 15:07:43 -07:00
Felix Rieseberg
b75f8a67f9
chore: update version from 1.1.5 to 1.2.0 (#147) 2025-11-01 12:35:45 -07:00
Samuel Attard
98126b777e
feat: use 0.2 as the default schema (#145) 2025-11-01 12:31:25 -07:00
joan-anthropic
ce8a5aec4a
Merge pull request #121 from guyru/patch-1
The repository url should actually point to the git repo
2025-10-31 13:52:06 -07:00
joan-anthropic
8c543a32f6
Merge pull request #141 from asklar/user/asklar/single-size-per-icon
fix: update icon size property from 'sizes' to 'size'
2025-10-30 16:54:44 -07:00
Alexander Sklar
bc2d083d18
chore: update version from 1.1.4 to 1.1.5 in package.json 2025-10-30 16:44:19 -07:00
Alexander Sklar
86e641c0b5
chore: update version from 1.1.3 to 1.1.4 in package.json 2025-10-30 16:43:59 -07:00
Alexander Sklar
257af30812
fix: update icon size property from 'sizes' to 'size' in manifest and schema files 2025-10-30 16:43:54 -07:00
Samuel Attard
406e7bb5bd
feat: add CI job to validate JSON schema generation (#139)
Add a new validate-schemas job to the CI workflow that ensures the
committed JSON schemas in the schemas/ directory are up-to-date with
the schema generation script. This prevents drift between the source
code and generated schemas.

The job:
- Runs the schema generation script (yarn build:schema)
- Checks if any schemas were modified
- Fails if changes are detected, prompting developers to regenerate
  and commit the schemas

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-30 16:31:10 -07:00
joan-anthropic
82b12a406e
Merge pull request #140 from anthropics/feat/use-latest-schema-only
feat: export McpbManifestAny type, use latest MCPB schema for BUILD manifest validation
2025-10-30 14:26:23 -07:00
Joan Xie
7ecb050280
cleanup 2025-10-30 14:19:34 -07:00
joan-anthropic
ba74af5217
Merge pull request #136 from bthompson-sys/feat/icon-validation
feat: add comprehensive icon validation to mcpb validate command
2025-10-30 10:40:02 -07:00
Joan Xie
8bea47f0b7
chore: bump version to 1.1.4 2025-10-30 10:00:13 -07:00
Joan Xie
a2bb7589b6
fix: sort imports in types.ts 2025-10-30 09:57:16 -07:00
Joan Xie
184173e342
fix: use correct manifest types for reading vs building
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 <noreply@anthropic.com>
2025-10-30 09:47:08 -07:00
Joan Xie
ddad8064ef
feat: use latest MCPB schema for BUILD manifest validation
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 <noreply@anthropic.com>
2025-10-30 09:40:32 -07:00
Bryan Thompson
55e3c3cfd8
fix: resolve linting errors
- Remove duplicate node:path import in test/icon-validation.test.ts
- Replace 4 instances of 'any' type with 'unknown' in error handlers
- Auto-format code with prettier (27 formatting fixes)

Addresses review feedback from PR #136
All 6 errors and 27 warnings resolved
2025-10-30 07:53:06 -05:00
joan-anthropic
11d1397ee8
Merge pull request #138 from anthropics/feat/export-versioned-schemas
feat: export versioned schemas in package.json
2025-10-29 17:20:17 -07:00
Joan Xie
c29d1000f3
feat: add any schema 2025-10-29 17:06:55 -07:00
Joan Xie
1660697588
refactor: remove legacy mcpb-manifest.schema.json
Removed the non-versioned mcpb-manifest.schema.json from schemas/
directory. All schemas are now explicitly versioned.

Available schemas:
- mcpb-manifest-v0.1.schema.json
- mcpb-manifest-v0.2.schema.json
- mcpb-manifest-v0.3.schema.json
- mcpb-manifest-latest.schema.json

Consumers should use -latest or specific version to be explicit
about which schema version they're validating against.
2025-10-29 17:01:04 -07:00
Joan Xie
789b37087c
revert: restore McpbManifest type to use latest schema
Reverted the discriminated union type change. McpbManifest now uses
the latest schema as before. Consumers can use versioned schemas
directly if they need to validate specific versions.
2025-10-29 16:59:06 -07:00
Joan Xie
db5d6be33c
Reapply "chore: bump version to 1.1.3"
This reverts commit ae3d9614e2.
2025-10-29 16:58:41 -07:00
Joan Xie
ae3d9614e2
Revert "chore: bump version to 1.1.3"
This reverts commit 48232bf64e.
2025-10-29 16:58:15 -07:00
Joan Xie
48232bf64e
chore: bump version to 1.1.3 2025-10-29 16:57:49 -07:00
Joan Xie
e7282946b6
fix: lint errors - remove unused import and format files
- Remove unused McpbManifestSchema import from types.ts
- Run prettier on modified files
2025-10-29 16:51:27 -07:00
Joan Xie
eeb9dca819
refactor: remove non-versioned mcpb-manifest.schema.json export
Remove the generic mcpb-manifest.schema.json export from package.json
in favor of explicit versioned exports.

Changes:
- Removed ./mcpb-manifest.schema.json from package exports
- Stop generating mcpb-manifest.schema.json in dist/
- Keep mcpb-manifest.schema.json in schemas/ for backward compatibility

Consumers should now use:
- mcpb-manifest-latest.schema.json (for latest version)
- mcpb-manifest-v0.1.schema.json (for specific version)
- etc.

This makes versioning explicit and prevents ambiguity about which
schema version is being used.
2025-10-29 16:49:41 -07:00
Joan Xie
b5fa7df6eb
feat: generate JSON schemas for all manifest versions
Updated build script to generate JSON schemas for all historical manifest
versions (v0.1, v0.2, v0.3) in addition to the latest version.

Changes:
- Generate mcpb-manifest-v0.1.schema.json
- Generate mcpb-manifest-v0.2.schema.json
- Generate mcpb-manifest-v0.3.schema.json
- Generate mcpb-manifest-latest.schema.json
- Keep mcpb-manifest.schema.json as alias for latest
- All schemas generated to both dist/ and schemas/ directories
- Added exports in package.json for all versioned schemas

Benefits:
- Tools can validate against specific manifest versions
- Backwards compatibility for all historical versions
- Latest schema always available at predictable path
- JSON schema files match the Zod schema versions

Usage:
import manifestSchema from '@anthropic-ai/mcpb/mcpb-manifest-v0.2.schema.json'
import latestSchema from '@anthropic-ai/mcpb/mcpb-manifest-latest.schema.json'
2025-10-29 16:39:57 -07:00
Joan Xie
faafd4523a
feat: make McpbManifest a discriminated union of all versions
Changed McpbManifest type from a single version to a discriminated union
of all historical manifest versions (0.1, 0.2, 0.3).

This allows the type system to properly handle manifests from any version
while maintaining type safety through the manifest_version/dxt_version
discriminator field.

Benefits:
- Type-safe handling of multiple manifest versions
- TypeScript can narrow types based on version field
- No need for type assertions when working with versioned manifests
- Maintains backward compatibility with all historical versions
2025-10-29 16:33:23 -07:00
Joan Xie
67938cdab9
feat: export versioned schemas in package.json
Add exports for versioned schemas to allow consumers to import:
- ./schemas: All versioned schemas (v0_1, v0_2, v0_3, latest)
- ./schemas/*: Specific schema versions (./schemas/0.1, ./schemas/any, etc.)
- ./schemas-loose: Loose validation schemas

This enables cleaner imports like:
import { McpbManifestSchema } from '@anthropic-ai/mcpb/schemas/any'
import * as v0_2 from '@anthropic-ai/mcpb/schemas/0.2'
import * as schemas from '@anthropic-ai/mcpb/schemas'
2025-10-29 16:30:32 -07:00
joan-anthropic
7961b32cfc
Merge pull request #137 from anthropics/chore/1.1.2
chore: update to 1.1.2
2025-10-29 15:49:49 -07:00
Joan Xie
f37496928b
chore: update to 1.1.2 2025-10-29 15:47:25 -07:00
Bryan Thompson
ccf9470979
feat: add comprehensive icon validation to mcpb validate command
Implements icon validation to catch common issues that prevent icons from
displaying in Claude Desktop. Uses a non-blocking warning approach for
remote URLs to maintain flexibility for MCPB's evolving multi-platform
ecosystem.

## Changes

### Core Implementation (src/node/validate.ts)
- Add `isPNG()` helper to validate PNG file signatures via magic bytes
- Add `validateIcon()` function with comprehensive checks:
  - **Warn** about remote URLs (non-blocking, best practice guidance)
  - **Reject** ${__dirname} variable usage in icon field (doesn't work)
  - **Reject** absolute paths (not portable)
  - Verify icon file exists at specified path
  - Verify icon file is valid PNG format
  - Recommend 512×512 size for Claude Desktop
- Integrate icon validation into `validateManifest()` after schema validation

### Test Coverage
- Update `test/icon-validation.test.ts` - Remote URL test now expects warning
- Update `test/cli.test.ts` - Integration test updated for warnings
- All 109 tests passing

### Documentation Updates
- Update examples/hello-world-node/manifest.json to v0.3

## Validation Behavior

**Remote URLs (WARNING - non-blocking):**
```
Icon path uses a remote URL. Best practice for local MCP servers:
Use local files like "icon": "icon.png" for maximum compatibility.
Claude Desktop currently only supports local icon files in bundles.
```
**Result:** Validation passes, developer is informed

**Other Issues (ERROR - blocking):**
- ${__dirname} usage: Rejects (doesn't work)
- Absolute paths: Rejects (not portable)
- Missing files: Rejects (broken reference)
- Non-PNG files: Rejects (wrong format)

## Rationale

**Non-Blocking Approach:**
- Doesn't prevent valid bundles from being created
- Educates developers about best practices
- Maintains flexibility as MCPB evolves beyond Claude Desktop
- Future-proof if remote URL support is added

**Still Protective:**
- Blocks truly broken configurations (missing files, wrong formats)
- Provides actionable error messages for fixable issues

Based on real-world findings from investigating icon display issues in
Claude Desktop with production MCPB bundles.
2025-10-28 09:14:12 -05:00
joan-anthropic
49c68b0452
Merge pull request #132 from asklar/user/asklar/localization
[0.3] Add localization/theming
2025-10-27 14:23:32 -07:00
Alexander Sklar
55154fa6fb
fix linting 2025-10-27 14:06:11 -07:00
Alexander Sklar
d929b8c33c
add default for resources property 2025-10-27 11:33:35 -07:00
joan-anthropic
ef6908e612
Merge pull request #117 from anthropics/fix/json-schema-generation
fix: restore JSON schema generation
2025-10-27 10:38:16 -07:00
Alexander Sklar
18d096526e
fix typo 2025-10-27 09:57:53 -07:00
Alexander Sklar
bdcfeadac5
. 2025-10-27 09:43:54 -07:00
Alexander Sklar
1640adefe8
Add localization/theming feature to 0.3 version 2025-10-24 15:48:46 -07:00
Joan Xie
2a0ba89918
fix: improve JSON schema generation and publishing
- Refactor JSON schema generation to use zod-to-json-schema
- Publish manifest schema to schemas/ directory
- Update package.json exports for schema files
- Add WIP version 0.3 support
- Clean up schema generation scripts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 17:16:06 -07:00
joan-anthropic
d595dd66dc
Merge pull request #114 from anthropics/feat/versioned-schemas
feat: versioned schemas
2025-10-20 17:12:19 -07:00
Joan Xie
f7efd3a444
add WIP 0.3 2025-10-20 17:07:44 -07:00
Joan Xie
143aa9a63c
test: skip _meta tests for v0.3 2025-10-20 17:07:44 -07:00
joan-anthropic
2b193ac391
Merge pull request #127 from anthropics/docs/license-and-contributing
chore: Add CONTRIBUTING.md
2025-10-20 16:49:03 -07:00
Joan Xie
0496e93851
add req for commit signing 2025-10-20 08:41:45 -07:00
Joan Xie
ec05e897c7
Add CONTRIBUTING.md and rename LICENSE.md to LICENSE
- Add comprehensive contributing guidelines with setup instructions, workflow, and code standards
- Rename LICENSE.md to LICENSE to follow standard naming convention and fix README link

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 11:16:27 -07:00
Joan Xie
e2d6836622
Merge branch 'main' into feat/versioned-schemas 2025-10-17 16:05:16 -07:00
joan-anthropic
d12057eefd
Merge pull request #124 from asklar/user/asklar/static_responses_and_extensions
Add _meta to manifest schema and tests
2025-10-10 16:46:02 -07:00
Alexander Sklar
443d849420
Refactor manifest schema to replace static_responses and client_extensions with _meta for improved organization 2025-10-10 16:43:33 -07:00
Alexander Sklar
caa61bcc49
Update example to be more real 2025-10-10 16:43:18 -07:00
Alexander Sklar
90c18ca9fb
Add static_responses and client_extensions to manifest schema and tests 2025-10-10 16:43:03 -07:00
Samuel Attard
e9aa4d0029
build: use yarn v4 (#125) 2025-10-10 14:43:35 -07:00
Joan Xie
6c05338904
refactor: remove schemas.ts re-export, use explicit imports in tests
- Remove src/schemas.ts file
- Update tests to import directly from src/schemas/index.js
2025-09-24 14:28:06 -07:00
Joan Xie
4c100e26da
refactor: rename CURRENT_MANIFEST_VERSION to LATEST_MANIFEST_VERSION
- Rename CURRENT_MANIFEST_VERSION to LATEST_MANIFEST_VERSION
- Rename CURRENT_MANIFEST_SCHEMA to LATEST_MANIFEST_SCHEMA
- Rename CURRENT_MANIFEST_SCHEMA_LOOSE to LATEST_MANIFEST_SCHEMA_LOOSE
- Update all references throughout codebase and tests
2025-09-24 14:26:55 -07:00
Joan Xie
412b124b96
refactor: update all references to use schemas/latest instead of schemas/0.2
- Update src/index.ts, types.ts, browser.ts, cli.ts, and node.ts
- All package entrypoints now use latest.ts for easier version management
2025-09-24 14:22:47 -07:00
Joan Xie
c4a9500c84
feat: add schema helper aliases (latest)
- Add schemas/latest.ts and schemas_loose/latest.ts as aliases to current version
- Update constants.ts to use latest.ts instead of hardcoded version imports
- This makes version updates easier - only need to update latest.ts pointer
2025-09-24 14:21:01 -07:00
Joan Xie
fefd9e1d21
fix: add schemas re-export file and update tests to use correct manifest version
- Create src/schemas.ts to re-export from schemas/index.ts for test imports
- Update test manifests to use manifest_version "0.2" instead of "1.0" or "1.0.0"
- Fix import sorting and formatting issues in schema files
- Export McpbManifestSchema from schemas/index.ts
2025-09-24 14:12:10 -07:00
Joan Xie
ccb19277c4
feat: export constants from package entrypoints 2025-09-24 14:03:03 -07:00
Joan Xie
76b79551ab
fix: use CURRENT_MANIFEST_VERSION in pack.ts version check 2025-09-24 13:58:45 -07:00
Joan Xie
3a0d4a8635
feat: create schema version map with CURRENT_MANIFEST_SCHEMA selector 2025-09-24 13:57:19 -07:00
Joan Xie
fe733e3450
refactor: use MANIFEST_VERSION variable in z.literal() instead of hardcoded strings 2025-09-24 13:54:38 -07:00
Joan Xie
6bfd100b60
feat: export CURRENT_MANIFEST_VERSION from schemas index 2025-09-24 13:53:13 -07:00
Joan Xie
336e878252
fix: add dxt_version support to v0.2 schemas with deprecation notice 2025-09-24 13:51:40 -07:00
Joan Xie
9f078c6163
fix: add deprecation notice to dxt_version in v0.1 schemas 2025-09-24 13:50:16 -07:00
Joan Xie
16f173824c
fix: correct strict schemas for v0.1 and v0.2 2025-09-24 13:48:52 -07:00
Joan Xie
3d9c966951
fix: rename CURRENT_MANIFEST_VERSION to MANIFEST_VERSION and set correct versions 2025-09-24 13:45:19 -07:00
Joan Xie
2e9e70c5ff
fix: update schema imports to versioned paths 2025-09-24 13:43:02 -07:00
Joan Xie
8e2ec66564
fix: add privacy_policies and passthrough to loose schema v0.2 2025-09-24 13:42:03 -07:00
Joan Xie
a43769d94b
feat: restructure schemas into versioned folders
- Move schemas.ts and schemas-loose.ts into separate versioned folders
- Create schemas/0.1.ts and schemas/0.2.ts for strict validation
- Create schemas_loose/0.1.ts and schemas_loose/0.2.ts for loose validation
- Add index files to export all historical schema versions
- Update all imports to use schemas/0.2.ts
- Enforce exact version values using z.literal() for both v0.1 and v0.2
- Remove dxt_version support from v0.2 schemas
- Remove all passthrough() from v0.2 strict schemas
- Validate privacy_policies as URLs in v0.2

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-24 13:42:03 -07:00
adam jones
9ac5d8806c
Merge pull request #104 from asklar/patch-1
Change syntax highlighting to jsonc in MANIFEST.md
2025-09-24 11:47:21 +01:00
adam jones
f2284f6681
Merge pull request #108 from nicolasff/manifest-md-jsonc-syntax
docs: use jsonc syntax highlighting for manifest example
2025-09-24 11:47:01 +01:00
adam jones
8c231cfbdb
Merge pull request #111 from anthropics/jwei/push-for-node
Add language choice recommendation to readme
2025-09-24 11:46:35 +01:00
Justin Wei
454b0be584
Add language choice recommendation to readme 2025-09-23 20:22:21 -04:00
joan-anthropic
c2d42b3e0a
Merge pull request #109 from anthropics/feat/validate-manifest-version-in-pack
feat: validate manifest version during pack command
2025-09-22 15:42:51 -07:00
Joan Xie
b7a2acb969
bump version 2025-09-22 15:32:23 -07:00
Joan Xie
e772ed753d
fix: update test to match new validation message
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-22 15:28:42 -07:00
Joan Xie
232e6b3f91
improve schema validation logs 2025-09-22 15:17:16 -07:00
Joan Xie
16e569a337
fix examples 2025-09-22 14:59:42 -07:00
Joan Xie
f92fe4ab69
feat: validate manifest version during pack command
Add validation to ensure the manifest_version matches the current expected
version (0.2) during the mcpb pack command. This prevents users from
packing extensions with outdated or incorrect manifest versions.

Changes:
- Add CURRENT_MANIFEST_VERSION constant to centralize version management
- Validate manifest version in pack command before creating bundle
- Update init command to use version constant
- Update tests to use version constant
- Fix prettier formatting issues
2025-09-22 14:43:28 -07:00
guyru
39fe803479
The repository url should actually point to the git repo
In the example, the repo URL should actually point to the git repo and not the github project.
2025-09-22 17:19:05 +03:00
Nicolas Favre-Felix
9fce5b58d9
docs: use jsonc syntax highlighting for manifest example
The example at the start of MANIFEST.md uses // comments in a ```json
code block, which are highlighted as errors on GitHub. Change this
syntax hint to ```jsonc (JSON with comments) for better rendering.
2025-09-20 07:32:09 -07:00
Alexander Sklar
8ce2cc3840
Change syntax highlighting to jsonc in MANIFEST.md
fix json -> jsonc in manifest.md
2025-09-16 00:10:49 -07:00
joan-anthropic
2825da1d6a
Merge pull request #100 from anthropics/bump-version-1.1.0
chore: bump version to 1.1.0
2025-09-12 13:48:34 -07:00
Joan Xie
a65e7d0c59
chore: bump version to 1.1.0 2025-09-12 13:15:49 -07:00
joan-anthropic
b991c5fcfc
Merge pull request #99 from anthropics/feat/add-privacy-policies-to-manifest
feat: add privacy_policies field to manifest schema
2025-09-12 13:11:21 -07:00
Joan Xie
bc129a7223
docs: bump manifest version to 0.2
Update manifest spec version from 0.1 to 0.2 to reflect the addition
of the privacy_policies field. Update last updated date to current date.
2025-09-12 12:04:38 -07:00
Joan Xie
9d62ba5d50
docs: clarify privacy_policies field description for external services
Update the privacy_policies field description to be more specific about
its purpose - linking to privacy policies of external services that
handle user data, as required for extensions connecting to first- or
third-party services.
2025-09-12 12:02:52 -07:00
Joan Xie
bd7fdf7e3c
docs: update privacy_policies example to show single URL
Simplify the privacy_policies field example in the documentation to
show a single privacy policy URL.
2025-09-12 11:59:18 -07:00
Joan Xie
a48002ec69
feat: add privacy_policies field to manifest schema
Add optional privacy_policies array field to manifest.json that allows
developers to declare their data handling practices. This field accepts
an array of privacy policy statements that describe how the extension
collects, uses, and protects user data.

- Update manifest schema to include privacy_policies field
- Add empty privacy_policies array to all example manifests
- Document the new field in MANIFEST.md
2025-09-12 11:53:11 -07:00
joan-anthropic
241c65be00
Merge pull request #92 from anthropics/joan/rename-dxt-mcpb
chore: rename DXT -> MCP Bundle (MCPB)
2025-08-28 11:46:01 -07:00
Joan Xie
841698fbe2
update README - project "is being renamed" 2025-08-28 11:14:47 -07:00
Joan Xie
5a46a05108
Revert "feat: replace manifest_version with $schema field"
This reverts commit 7997e72758.
2025-08-27 11:24:18 -07:00
Joan Xie
1de373a9c9
docs: update package rename notice to future tense 2025-08-27 10:51:03 -07:00
Joan Xie
7997e72758
feat: replace manifest_version with $schema field
- Replace manifest_version with $schema field pointing to official schema URL
- Support backward compatibility with legacy dxt_version field
- Update all examples and tests to use new $schema field
- Mark dxt_version as deprecated but still functional
- Require either $schema or dxt_version (at least one must be present)
2025-08-27 10:38:57 -07:00
Joan Xie
cd922a0704
update package version 2025-08-26 13:28:18 -07:00
Joan Xie
76949836e0
fix: update schema to reflect manifest_version 2025-08-25 21:09:45 -07:00
Joan Xie
cc7b6cde44
Remove 'For App Developers' section from README
This section was added alongside the rename but is not necessary for the dxt -> mcpb rename itself. Removing to keep the rename commit focused on just the naming changes.
2025-08-22 13:08:57 -07:00
Joan Xie
0b2658f5b0
lint 2025-08-21 15:28:01 -07:00
Joan Xie
e1938b9933
rename dxt -> mcpb 2025-08-21 14:56:54 -07:00
Felix Rieseberg
bf01918080
fix: allow repeat runs of "dxt clean" (#83) 2025-07-31 13:07:28 -07:00
Jacob
b062c0efad
fix: missing extension directory prefix in 'mcp_config' of python (#80) 2025-07-23 09:55:54 -07:00
Felix Rieseberg
4fbb2aed2c
chore: bump version to 0.2.6 (#76) 2025-07-20 14:08:24 -07:00
Felix Rieseberg
7c9d61d9e6
chore: A round of "yarn fix" for everyone (#75) 2025-07-18 10:09:52 -07:00
David Dworken
08b34f4f76
fix: prevent zip slip attacks in DXT unpack function (#74)
* fix: prevent zip slip attacks in DXT unpack function

Add path validation to prevent directory traversal attacks when unpacking DXT files.
The fix validates that extracted file paths remain within the intended output directory
before writing files to disk.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: make zip slip protection cross-platform compatible

Use path.sep instead of hardcoded '/' separator to ensure path validation
works correctly on both Windows and Unix systems. This fixes failing tests
on Windows while maintaining security protection against directory traversal.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-07-18 09:35:32 -07:00
Felix Rieseberg
a3ba5fc984
v0.2.5 (#69) 2025-07-13 14:31:02 -07:00
Samuel Attard
505c81a258
feat: add clean command to clean manifest and trip dev deps for node (#67)
* feat: add clean command to clean manifest and trip dev deps for node

* fix: lazy import no loop

* Update src/cli/cli.ts

Co-authored-by: Felix Rieseberg <f@anthropic.com>

---------

Co-authored-by: Felix Rieseberg <f@anthropic.com>
2025-07-11 15:30:08 -07:00
Samuel Attard
9523b5af19
fix: strictly validate manifests (#66)
* fix: strictly validate manifests

* spec: align tests with strict schema
2025-07-11 14:36:52 -07:00
Felix Rieseberg
641213ad47
chore: v0.2.4 (#62) 2025-07-10 16:12:59 -07:00
Samuel Attard
2dcc7efe6f
fix: handle invalid values in arrays (#61) 2025-07-10 16:10:48 -07:00
Felix Rieseberg
6f4ed9d662
0.2.3 (#60)
* fix: Go back to zod/v3

* chore: v0.2.3
2025-07-10 15:32:56 -07:00
Felix Rieseberg
e2a87144e9
fix: Go back to zod/v3 (#59) 2025-07-10 15:31:26 -07:00
Felix Rieseberg
a9544e29a7
chore: v0.2.2 (#58) 2025-07-10 09:46:50 -07:00
Erik Brakke
83b5a773ae
fix: preserve file permissions during unpack operation (#43)
- Parse ZIP central directory to extract Unix file permissions
- Restore executable permissions using chmodSync after unpacking files
- Skip permission restoration on Windows (Unix-only feature)
- Add comprehensive test to verify executable and regular file permissions are preserved
- Fix test setup to use npm instead of yarn for consistent build process

Fixes issue where executable files lose their execute permissions after being packed and unpacked, which is critical for extensions containing binary executables or shell scripts.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-07-10 09:09:07 -07:00
85 changed files with 14026 additions and 5033 deletions

View file

@ -34,8 +34,37 @@ jobs:
node-version: "${{ matrix.node-version }}"
cache: "yarn"
- name: Install dependencies
run: yarn install --frozen-lockfile
run: yarn install --immutable
- name: Build
run: yarn build
- name: Test
run: yarn lint && yarn test
validate-schemas:
name: Validate JSON Schemas
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "22.17.x"
cache: "yarn"
- name: Install dependencies
run: yarn install --immutable
- name: Build code (required for schema generation)
run: yarn build:code
- name: Generate schemas
run: yarn build:schema
- name: Check for schema changes
run: |
if ! git diff --exit-code schemas/; then
echo "Error: JSON schemas in schemas/ directory are out of sync!"
echo "Please run 'yarn build:schema' and commit the changes."
echo ""
echo "Changes detected:"
git diff schemas/
exit 1
fi
echo "✓ All schemas are up to date"

12
.gitignore vendored
View file

@ -88,6 +88,8 @@ typings/
# Claude files
.claude.json
.claude/
CLAUDE.md
PROJECT_STATUS.md
# Vite
.vite/
@ -103,6 +105,12 @@ _out/
dist
self-signed-cert.pem
self-signed-key.pem
*.dxt
*.mcpb
invalid-json.json
**/server/lib/**
**/server/lib/**
# Rust example build artifacts
examples/calculator-rust/target/
examples/calculator-rust/server/
.yarn/install-state.gz

View file

@ -6,5 +6,6 @@
"eslint.validate": ["typescript"],
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
}
},
"typescript.tsdk": "node_modules/typescript/lib"
}

942
.yarn/releases/yarn-4.10.3.cjs vendored Executable file

File diff suppressed because one or more lines are too long

3
.yarnrc.yml Normal file
View file

@ -0,0 +1,3 @@
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.10.3.cjs

137
CLI.md
View file

@ -1,45 +1,45 @@
# DXT CLI Documentation
# MCPB CLI Documentation
The DXT CLI provides tools for building Desktop Extensions.
The MCPB CLI provides tools for building MCP Bundles.
## Installation
```bash
npm install -g @anthropic-ai/dxt
npm install -g @anthropic-ai/mcpb
```
```
Usage: dxt [options] [command]
Usage: mcpb [options] [command]
Tools for building Desktop Extensions
Tools for building MCP Bundles
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
init [directory] Create a new DXT extension manifest
validate <manifest> Validate a DXT manifest file
pack <directory> [output] Pack a directory into a DXT extension
sign [options] <dxt-file> Sign a DXT extension file
verify <dxt-file> Verify the signature of a DXT extension file
info <dxt-file> Display information about a DXT extension file
unsign <dxt-file> Remove signature from a DXT extension file
init [directory] Create a new MCPB extension manifest
validate <manifest> Validate a MCPB manifest file
pack <directory> [output] Pack a directory into a MCPB extension
sign [options] <mcpb-file> Sign a MCPB extension file
verify <mcpb-file> Verify the signature of a MCPB extension file
info <mcpb-file> Display information about a MCPB extension file
unsign <mcpb-file> Remove signature from a MCPB extension file
help [command] display help for command
```
## Commands
### `dxt init [directory]`
### `mcpb init [directory]`
Creates a new DXT extension manifest interactively.
Creates a new MCPB extension manifest interactively.
```bash
# Initialize in current directory
dxt init
mcpb init
# Initialize in a specific directory
dxt init my-extension/
mcpb init my-extension/
```
The command will prompt you for:
@ -58,53 +58,53 @@ The command will prompt you for:
After creating the manifest, it provides helpful next steps based on your server type.
### `dxt validate <path>`
### `mcpb validate <path>`
Validates a DXT manifest file against the schema. You can provide either a direct path to a manifest.json file or a directory containing one.
Validates a MCPB manifest file against the schema. You can provide either a direct path to a manifest.json file or a directory containing one.
```bash
# Validate specific manifest file
dxt validate manifest.json
mcpb validate manifest.json
# Validate manifest in directory
dxt validate ./my-extension
dxt validate .
mcpb validate ./my-extension
mcpb validate .
```
### `dxt pack <directory> [output]`
### `mcpb pack <directory> [output]`
Packs a directory into a DXT extension file.
Packs a directory into a MCPB extension file.
```bash
# Pack current directory into extension.dxt
dxt pack .
# Pack current directory into extension.mcpb
mcpb pack .
# Pack with custom output filename
dxt pack my-extension/ my-extension-v1.0.dxt
mcpb pack my-extension/ my-extension-v1.0.mcpb
```
The command automatically:
- Validates the manifest.json
- Excludes common development files (.git, node_modules/.cache, .DS_Store, etc.)
- Creates a compressed .dxt file (ZIP with maximum compression)
- Creates a compressed .mcpb file (ZIP with maximum compression)
### `dxt sign <dxt-file>`
### `mcpb sign <mcpb-file>`
Signs a DXT extension file with a certificate.
Signs a MCPB extension file with a certificate.
```bash
# Sign with default certificate paths
dxt sign my-extension.dxt
mcpb sign my-extension.mcpb
# Sign with custom certificate and key
dxt sign my-extension.dxt --cert /path/to/cert.pem --key /path/to/key.pem
mcpb sign my-extension.mcpb --cert /path/to/cert.pem --key /path/to/key.pem
# Sign with intermediate certificates
dxt sign my-extension.dxt --cert cert.pem --key key.pem --intermediate intermediate1.pem intermediate2.pem
mcpb sign my-extension.mcpb --cert cert.pem --key key.pem --intermediate intermediate1.pem intermediate2.pem
# Create and use a self-signed certificate
dxt sign my-extension.dxt --self-signed
mcpb sign my-extension.mcpb --self-signed
```
Options:
@ -114,12 +114,12 @@ Options:
- `--intermediate, -i`: Paths to intermediate certificate files
- `--self-signed`: Create a self-signed certificate if none exists
### `dxt verify <dxt-file>`
### `mcpb verify <mcpb-file>`
Verifies the signature of a signed DXT extension file.
Verifies the signature of a signed MCPB extension file.
```bash
dxt verify my-extension.dxt
mcpb verify my-extension.mcpb
```
Output includes:
@ -130,12 +130,12 @@ Output includes:
- Certificate fingerprint
- Warning if self-signed
### `dxt info <dxt-file>`
### `mcpb info <mcpb-file>`
Displays information about a DXT extension file.
Displays information about a MCPB extension file.
```bash
dxt info my-extension.dxt
mcpb info my-extension.mcpb
```
Shows:
@ -144,12 +144,12 @@ Shows:
- Signature status
- Certificate details (if signed)
### `dxt unsign <dxt-file>`
### `mcpb unsign <mcpb-file>`
Removes the signature from a DXT extension file (for development/testing).
Removes the signature from a MCPB extension file (for development/testing).
```bash
dxt unsign my-extension.dxt
mcpb unsign my-extension.mcpb
```
## Certificate Requirements
@ -176,7 +176,7 @@ mkdir my-awesome-extension
cd my-awesome-extension
# 2. Initialize the extension
dxt init
mcpb init
# 3. Follow the prompts to configure your extension
# The tool will create a manifest.json with all necessary fields
@ -184,10 +184,10 @@ dxt init
# 4. Create your server implementation based on the entry point you specified
# 5. Pack the extension
dxt pack .
mcpb pack .
# 6. (Optional) Sign the extension
dxt sign my-awesome-extension.dxt --self-signed
mcpb sign my-awesome-extension.mcpb --self-signed
```
### Development Workflow
@ -197,8 +197,8 @@ dxt sign my-awesome-extension.dxt --self-signed
mkdir my-extension
cd my-extension
# 2. Initialize with dxt init or create manifest.json manually
dxt init
# 2. Initialize with mcpb init or create manifest.json manually
mcpb init
# 3. Implement your server
# For Node.js: create server/index.js
@ -206,35 +206,35 @@ dxt init
# For Binary: add your executable
# 4. Validate manifest
dxt validate manifest.json
mcpb validate manifest.json
# 5. Pack extension
dxt pack . my-extension.dxt
mcpb pack . my-extension.mcpb
# 6. (Optional) Sign for testing
dxt sign my-extension.dxt --self-signed
mcpb sign my-extension.mcpb --self-signed
# 7. Verify signature
dxt verify my-extension.dxt
mcpb verify my-extension.mcpb
# 8. Check extension info
dxt info my-extension.dxt
mcpb info my-extension.mcpb
```
### Production Workflow
```bash
# 1. Pack your extension
dxt pack my-extension/
mcpb pack my-extension/
# 2. Sign with production certificate
dxt sign my-extension.dxt \
mcpb sign my-extension.mcpb \
--cert production-cert.pem \
--key production-key.pem \
--intermediate intermediate-ca.pem root-ca.pem
# 3. Verify before distribution
dxt verify my-extension.dxt
mcpb verify my-extension.mcpb
```
## Excluded Files
@ -250,12 +250,12 @@ When packing an extension, the following files/patterns are automatically exclud
- `.env.local`, `.env.*.local`
- `package-lock.json`, `yarn.lock`
### Custom Exclusions with .dxtignore
### Custom Exclusions with .mcpbignore
You can create a `.dxtignore` file in your extension directory to specify additional files and patterns to exclude during packing. This works similar to `.npmignore` or `.gitignore`:
You can create a `.mcpbignore` file in your extension directory to specify additional files and patterns to exclude during packing. This works similar to `.npmignore` or `.gitignore`:
```
# .dxtignore example
# .mcpbignore example
# Comments start with #
*.test.js
src/**/*.test.ts
@ -266,7 +266,7 @@ temp/
docs/
```
The `.dxtignore` file supports:
The `.mcpbignore` file supports:
- **Exact matches**: `filename.txt`
- **Simple globs**: `*.log`, `temp/*`
@ -274,30 +274,31 @@ The `.dxtignore` file supports:
- **Comments**: Lines starting with `#` are ignored
- **Empty lines**: Blank lines are ignored
When a `.dxtignore` file is found, the CLI will display the number of additional patterns being applied. These patterns are combined with the default exclusion list.
When a `.mcpbignore` file is found, the CLI will display the number of additional patterns being applied. These patterns are combined with the default exclusion list.
## Technical Details
### Signature Format
DXT uses PKCS#7 (Cryptographic Message Syntax) for digital signatures:
MCPB uses PKCS#7 (Cryptographic Message Syntax) for digital signatures:
- Signatures are stored in DER-encoded PKCS#7 SignedData format
- The signature is appended to the DXT file with markers (`DXT_SIG_V1` and `DXT_SIG_END`)
- The entire DXT content (excluding the signature block) is signed
- The signature is appended to the MCPB file with markers (`MCPB_SIG_V1` and `MCPB_SIG_END`)
- The entire MCPB content (excluding the signature block) is signed
- Detached signature format - the original ZIP content remains unmodified
### Signature Structure
```
[Original DXT ZIP content]
DXT_SIG_V1
[Base64-encoded PKCS#7 signature]
DXT_SIG_END
[Original MCPB ZIP content]
MCPB_SIG_V1
[4-byte little-endian length prefix]
[DER-encoded PKCS#7 signature]
MCPB_SIG_END
```
This approach allows:
- Backward compatibility (unsigned DXT files are valid ZIP files)
- Backward compatibility (unsigned MCPB files are valid ZIP files)
- Easy signature verification and removal
- Support for certificate chains with intermediate certificates

85
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,85 @@
# Contributing to MCPB
Thank you for your interest in contributing to MCPB! We welcome contributions from the community.
## Getting Started
1. Fork the repository
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/mcpb.git`
3. Install dependencies: `yarn`
4. Build the project: `yarn build`
5. Run tests: `yarn test`
## Development Workflow
1. Create a new branch for your feature or bugfix: `git checkout -b feature/your-feature-name`
2. Make your changes
3. Run linting: `yarn lint`
4. Run tests to ensure everything passes: `yarn test`
5. Commit your changes with a clear, descriptive commit message (all commits must be signed - see [Commit Signing](#commit-signing))
6. Push to your fork and submit a pull request
## Code Standards
- **TypeScript**: All code should be written in TypeScript with proper type definitions
- **Linting**: Run `yarn lint` before committing. Use `yarn fix` to auto-fix formatting issues
- **Testing**: Add tests for new features and bug fixes
- **Documentation**: Update relevant documentation (README.md, MANIFEST.md, etc.) when adding or changing functionality
## Commit Signing
**All commits must be signed.** This helps verify the authenticity of contributions.
To set up commit signing, see [GitHub's documentation on commit signature verification](https://docs.github.com/en/authentication/managing-commit-signature-verification).
## Pull Request Process
1. Ensure your PR description clearly describes the problem and solution
2. Reference any related issues in your PR description
3. Make sure all tests pass and linting is clean
4. Verify that all commits are signed
5. Update documentation as needed
6. Wait for review from maintainers
## Types of Contributions
### Bug Reports
When filing a bug report, please include:
- Clear description of the issue
- Steps to reproduce
- Expected vs actual behavior
- Version information (`mcpb --version`)
- Relevant logs or error messages
### Feature Requests
We welcome feature suggestions! Please:
- Clearly describe the feature and use case
- Explain why this would be valuable to users
- Consider if it aligns with the project's goals
### Code Contributions
We especially welcome:
- Bug fixes
- Documentation improvements
- Test coverage improvements
- New features (please discuss in an issue first for large changes)
## Testing
- Write unit tests for new functionality
- Ensure existing tests still pass
- Test manually with real MCP bundles when applicable
## Questions?
Feel free to open an issue for questions about contributing or the project in general.
## License
By contributing to MCPB, you agree that your contributions will be licensed under the MIT License.

216
LICENSE Normal file
View file

@ -0,0 +1,216 @@
The MCP project is undergoing a licensing transition from the MIT License to the Apache License, Version 2.0 ("Apache-2.0"). All new code and specification contributions to the project are licensed under Apache-2.0. Documentation contributions (excluding specifications) are licensed under CC-BY-4.0.
Contributions for which relicensing consent has been obtained are licensed under Apache-2.0. Contributions made by authors who originally licensed their work under the MIT License and who have not yet granted explicit permission to relicense remain licensed under the MIT License.
No rights beyond those granted by the applicable original license are conveyed for such contributions.
---
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright
owner or by an individual or Legal Entity authorized to submit on behalf
of the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
---
MIT License
Copyright (c) 2024-2025 Model Context Protocol a Series of LF Projects, LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
Creative Commons Attribution 4.0 International (CC-BY-4.0)
Documentation in this project (excluding specifications) is licensed under
CC-BY-4.0. See https://creativecommons.org/licenses/by/4.0/legalcode for
the full license text.

View file

@ -1,7 +0,0 @@
Copyright 2025 Anthropic, PBC.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,7 +1,7 @@
# DXT Manifest.json Spec
# MCPB Manifest.json Spec
Current version: `0.1`
Last updated: 2025-06-17
Current version: `0.3`
Last updated: 2025-12-02
## Manifest Schema
@ -9,15 +9,15 @@ The `manifest.json` file contains all extension metadata and configuration. Most
A basic `manifest.json` with just the required fields looks like this:
```json
```jsonc
{
"dxt_version": "0.1", // DXT spec version this manifest conforms to
"manifest_version": "0.3", // Manifest spec version this manifest conforms to
"name": "my-extension", // Machine-readable name (used for CLI, APIs)
"version": "1.0.0", // Semantic version of your extension
"description": "A simple MCP extension", // Brief description of what the extension does
"author": {
// Author information (required)
"name": "Extension Author" // Author's name (required field)
"name": "Extension Author", // Author's name (required field)
},
"server": {
// Server configuration (required)
@ -28,16 +28,16 @@ A basic `manifest.json` with just the required fields looks like this:
"command": "node", // Command to run the server
"args": [
// Arguments passed to the command
"${__dirname}/server/index.js" // ${__dirname} is replaced with the extension's directory
]
}
}
"${__dirname}/server/index.js", // ${__dirname} is replaced with the extension's directory
],
},
},
}
```
```json
{
"dxt_version": "0.1",
"manifest_version": "0.3",
"name": "my-extension",
"version": "1.0.0",
"description": "A simple MCP extension",
@ -71,7 +71,7 @@ A full `manifest.json` with most of the optional fields looks like this:
```json
{
"dxt_version": "0.1",
"manifest_version": "0.3",
"name": "My MCP Extension",
"display_name": "My Awesome MCP Extension",
"version": "1.0.0",
@ -84,16 +84,32 @@ A full `manifest.json` with most of the optional fields looks like this:
},
"repository": {
"type": "git",
"url": "https://github.com/your-username/my-mcp-extension"
"url": "https://github.com/your-username/my-mcp-extension.git"
},
"homepage": "https://example.com/my-extension",
"documentation": "https://docs.example.com/my-extension",
"support": "https://github.com/your-username/my-extension/issues",
"icon": "icon.png",
"icons": [
{
"src": "assets/icons/icon-16-light.png",
"size": "16x16",
"theme": "light"
},
{
"src": "assets/icons/icon-16-dark.png",
"size": "16x16",
"theme": "dark"
}
],
"screenshots": [
"assets/screenshots/screenshot1.png",
"assets/screenshots/screenshot2.png"
],
"localization": {
"resources": "custom-directory-for-mcpb-resources/${locale}.json",
"default_locale": "en-US"
},
"server": {
"type": "node",
"entry_point": "server/index.js",
@ -122,6 +138,7 @@ A full `manifest.json` with most of the optional fields looks like this:
"tools_generated": true,
"keywords": ["api", "automation", "productivity"],
"license": "MIT",
"privacy_policies": ["https://example.com/privacy"],
"compatibility": {
"claude_desktop": ">=1.0.0",
"platforms": ["darwin", "win32", "linux"],
@ -154,6 +171,54 @@ A full `manifest.json` with most of the optional fields looks like this:
"min": 1,
"max": 100
}
},
"_meta": {
"com.microsoft.windows": {
"package_family_name": "MyMcpMSIXPackage_51g09708xawrw",
"static_responses": {
"initialize": {
"capabilities": {},
"instructions": "When the user wants to search files, use the search_files tool but only after asking them whether the files are local.",
"protocolVersion": "2025-06-18",
"serverInfo": {
"name": "MyMCPExtension",
"title": "My MCP Extension - Pro Edition",
"version": "1.0.0"
}
},
"tools/list": {
"tools": [
{
"name": "search_files",
"title": "File search",
"description": "Search for files in a directory",
"inputSchema": {
"type": "object",
"properties": {
"fileSpec": {
"type": "string",
"description": "The file name to search for. Wildcards are supported"
}
},
"required": ["fileSpec"]
},
"outputSchema": {
"type": "object",
"properties": {
"searchResults": {
"type": "array",
"description": "The list of file paths that were found",
"items": {
"type": "string"
}
}
}
}
}
]
}
}
}
}
}
```
@ -162,35 +227,79 @@ A full `manifest.json` with most of the optional fields looks like this:
### Required Fields
- **dxt_version**: Specification version this extension conforms to
- **manifest_version**: Specification version this extension conforms to
- **name**: Machine-readable name (used for CLI, APIs)
- **version**: Semantic version (semver)
- **description**: Brief description
- **author**: Author information object with name (required), email (optional), and url (optional)
- 🌎 **description**: Brief description. This field is localizable.
- 🌎 **author**: Author information object with name (required, localizable), email (optional), and url (optional)
- **server**: Server configuration object
### Optional Fields
- **icon**: Path to a png icon file, either relative in the package or a https:// url.
- **display_name**: Human-friendly name for UI display
- **long_description**: Detailed description for extension stores, markdown
- **repository**: Source code repository information (type and url)
- **homepage**: Extension homepage URL
- **documentation**: Documentation URL
- **support**: Support/issues URL
- **screenshots**: Array of screenshot paths
- **tools**: Array of tools the extension provides
- **tools_generated**: Boolean indicating the server generates additional tools at runtime (default: false)
- **prompts**: Array of prompts the extension provides
- **prompts_generated**: Boolean indicating the server generates additional prompts at runtime (default: false)
- **keywords**: Search keywords
- **license**: License identifier
- **compatibility**: Compatibility requirements (client app version, platforms, and runtime versions)
- **user_config**: User-configurable options for the extension (see User Configuration section)
- **icon**: Path to a png icon file, either relative in the package or a `https://` url.
- **icons**: Array of icon descriptors (`src`, `size`, optional `theme`) for light/dark or size-specific assets.
- 🌎 **display_name**: Human-friendly name for UI display. This field is localizable.
- 🌎 **long_description**: Detailed description for extension stores, markdown. This field is localizable.
- **repository**: Source code repository information (type and url).
- **homepage**: Extension homepage URL.
- **documentation**: Documentation URL.
- **support**: Support/issues URL.
- **screenshots**: Array of screenshot paths.
- 🌎 **tools**: Array of tools the extension provides. This field is localizable.
- **tools_generated**: Boolean indicating the server generates additional tools at runtime (default: false).
- 🌎 **prompts**: Array of prompts the extension provides. This field is localizable.
- **prompts_generated**: Boolean indicating the server generates additional prompts at runtime (default: false).
- 🌎 **keywords**: Search keywords. This field is localizable.
- **license**: License identifier.
- **privacy_policies**: Array of URLs to privacy policies for external services that handle user data. Required when the extension connects to external services (first- or third-party) that process user data. Each URL should link to the respective service's privacy policy document.
- **compatibility**: Compatibility requirements (client app version, platforms, and runtime versions).
- **user_config**: User-configurable options for the extension (see User Configuration section).
- **\_meta**: Platform-specific client integration metadata (e.g., Windows `package_family_name`, macOS bundle identifiers) enabling tighter OS/app store integration. The keys in the `_meta` object are reverse-DNS namespaced, and the values are a dictionary of platform-specific metadata.
- **localization**: Location of translated strings for user-facing fields (`resources` path containing a `${locale}` placeholder and `default_locale`).
### Localization
Provide localized strings without bloating the manifest by pointing to external per-locale resource files. A localization entry looks like this:
```jsonc
"localization": {
"resources": "relative-path-to-resources/${locale}.json",
"default_locale": "en-US"
}
```
- `resources` must include a `${locale}` placeholder. Clients resolve it relative to the server install directory.
- This property is optional, and its default value is **`mcpb-resources/${locale}.json`**.
- `default_locale` must be a valid [BCP 47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt) identifier such as `en-US` or `zh-Hans`.
- This property is optional, and its default value is `en-US`.
- Values for the default locale stay in the main manifest; localized files only need to contain overrides.
For tools and prompts, the descriptions are also localizable.
#### Client guidelines
- if a client wants to show tool or prompt descriptions in their UI, the client should look for the locale-specific description override in the corresponding per-locale file.
- clients should only look for tools/prompts present in the manifest.json, i.e. prompts and tools that only exist in the per-locale file should be ignored.
- Clients should apply locale fallbacks if the client/user locale is not represented by the server. For example, if the user is in the `es-UY` locale but the server does not include that per-locale file, the client should look for an approrpiate fallback, e.g. `es-MX` or `es-ES`, or fall back to the values in the manifest.
### Icons
Use the `icons` array when you need multiple icon variants (different sizes or themes):
```json
"icons": [
{ "src": "assets/icons/icon-16-light.png", "size": "16x16", "theme": "light" },
{ "src": "assets/icons/icon-16-dark.png", "size": "16x16", "theme": "dark" }
]
```
- `size` must be in `WIDTHxHEIGHT` form (e.g., `128x128`).
- `theme` is optional; use values like `light`, `dark`, or platform-specific labels (e.g., `high-contrast`).
- The legacy `icon` field remains supported for single assets—clients use it when `icons` is omitted.
## Compatibility
The `compatibility` object specifies all requirements for running the extension. All fields, including the `compatibility` field itself, are optional. If you specify nothing, clients implementing DXT are encouraged to run the extension on any system.
The `compatibility` object specifies all requirements for running the extension. All fields, including the `compatibility` field itself, are optional. If you specify nothing, clients implementing MCPB are encouraged to run the extension on any system.
```json
{
@ -289,9 +398,56 @@ The `server` object defines how to run the MCP server:
### Server Types
Four server types are supported:
- **`node`**: Node.js server with bundled dependencies
- **`python`**: Python server with bundled dependencies
- **`binary`**: Compiled executable
- **`uv`**: Python server using UV runtime (v0.4+)
### UV Runtime (v0.4+)
The `uv` server type enables cross-platform Python extensions without bundling dependencies. Instead, dependencies are declared in `pyproject.toml` and installed by the host application using UV.
**Benefits:**
- Cross-platform support (Windows, macOS, Linux; Intel, ARM)
- Small bundle size (~100 KB vs 5-10 MB)
- Handles compiled dependencies (pydantic, numpy, etc.)
- No user Python installation required
**Example:**
```json
{
"manifest_version": "0.4",
"server": {
"type": "uv",
"entry_point": "src/server.py"
}
}
```
**Requirements:**
- Must include `pyproject.toml` with dependencies
- Must NOT include `server/lib/` or `server/venv/`
- `mcp_config` is optional (host manages execution)
**Package structure:**
```
extension.mcpb
├── manifest.json # server.type = "uv"
├── pyproject.toml # Dependencies
├── .mcpbignore # Exclude .venv, server/lib
└── src/
└── server.py
```
See `examples/hello-world-uv` for a complete example.
### Node, Python, and Binary Types
1. **Python**: `server.type = "python"`
- Requires `entry_point` to Python file
- All dependencies must be bundled in the DXT
- All dependencies must be bundled in the MCPB
- Can use `server/lib` for packages or `server/venv` for full virtual environment
- Python runtime version specified in `compatibility.runtimes.python`
@ -315,9 +471,9 @@ The `mcp_config` object in the server configuration defines how the implementing
```json
"mcp_config": {
"command": "python",
"args": ["server/main.py"],
"args": ["${__dirname}/server/main.py"],
"env": {
"PYTHONPATH": "server/lib"
"PYTHONPATH": "${__dirname}/server/lib"
}
}
```
@ -555,9 +711,9 @@ For servers with a fixed set of capabilities, list them in arrays.
Each prompt in the `prompts` array must include:
- **name**: The identifier for the prompt
- **description** (optional): Explanation of what the prompt does
- 🌎 **description** (optional): Explanation of what the prompt does
- **arguments** (optional): Array of argument names that can be used in the prompt text
- **text**: The actual prompt text that uses template variables like `${arguments.topic}` or `${arguments.aspect}` as placeholders for MCP Client-supplied arguments. If your argument is named `language`, you'd add `${arguments.language} where you expect it to show up in the prompt.
- 🌎 **text**: The actual prompt text that uses template variables like `${arguments.topic}` or `${arguments.aspect}` as placeholders for MCP Client-supplied arguments. If your argument is named `language`, you'd add `${arguments.language}` where you expect it to show up in the prompt.
Example:

130
README.md
View file

@ -1,118 +1,172 @@
# Desktop Extensions (DXT)
# MCP Bundles (MCPB)
Desktop Extensions (`.dxt`) are zip archives containing a local MCP server and a `manifest.json` that describes the server and its capabilities. The format is spiritually similar to Chrome extensions (`.crx`) or VS Code extensions (`.vsix`), enabling end users to install local MCP servers with a single click.
> **⚠️ IMPORTANT NOTICE: This project is being renamed from DXT (Desktop Extensions) to MCPB (MCP Bundles)**
>
> If you're looking for the DXT tools, they have been renamed to MCPB. Please update your dependencies and tooling:
>
> - `dxt` CLI is now `mcpb`
> - `.dxt` files are now `.mcpb` files
> - `@anthropic-ai/dxt` package will be moved to `@anthropic-ai/mcpb`
This repository provides three components: The extension specification in [MANIFEST.md](MANIFEST.md), a CLI tool for creating extensions (see [CLI.md](CLI.md)), and the code used by Claude for macOS and Windows to load and verify DXT extensions ([src/index.ts](src/index.ts)).
MCP Bundles (`.mcpb`) are zip archives containing a local MCP server and a `manifest.json` that describes the server and its capabilities. The format is spiritually similar to Chrome extensions (`.crx`) or VS Code extensions (`.vsix`), enabling end users to install local MCP servers with a single click.
This repository provides three components: The bundle specification in [MANIFEST.md](MANIFEST.md), a CLI tool for creating bundles (see [CLI.md](CLI.md)), and the code used by Claude for macOS and Windows to load and verify MCPB bundles ([src/index.ts](src/index.ts)).
- For developers of local MCP servers, we aim to make distribution and installation of said servers convenient
- For developers of apps supporting local MCP servers, we aim to make it easy to add support for DXT extensions
- For developers of apps supporting local MCP servers, we aim to make it easy to add support for MCPB bundles
Claude for macOS and Windows uses the code in this repository to enable single-click installation of local MCP servers, including a number of end user-friendly features - such as automatic updates, easy configuration of MCP servers and the variables and parameters they need, and a curated directory. We are committed to the open ecosystem around MCP servers and believe that its ability to be universally adopted by multiple applications and services has benefits developers aiming to connect AI tools to other apps and services. Consequently, we’re open-sourcing the Desktop Extension specification, toolchain, and the schemas and key functions used by Claude for macOS and Windows to implement its own support of Desktop Extensions. It is our hope that the `dxt` format doesn’t just make local MCP servers more portable for Claude, but other AI desktop applications, too.
Claude for macOS and Windows uses the code in this repository to enable single-click installation of local MCP servers, including a number of end user-friendly features - such as automatic updates, easy configuration of MCP servers and the variables and parameters they need, and a curated directory. We are committed to the open ecosystem around MCP servers and believe that its ability to be universally adopted by multiple applications and services has benefits developers aiming to connect AI tools to other apps and services. Consequently, we're open-sourcing the MCP Bundle specification, toolchain, and the schemas and key functions used by Claude for macOS and Windows to implement its own support of MCP Bundles. It is our hope that the `mcpb` format doesn't just make local MCP servers more portable for Claude, but other AI desktop applications, too.
# For Extension Developers
# For Bundle Developers
At the core, DXT are simple zip files containing your entire MCP server and a `manifest.json`. Consequently, turning a local MCP server into an extension is straightforward: You just have to put all your required files in a folder, create a `manifest.json`, and then create an archive.
At the core, MCPB are simple zip files containing your entire MCP server and a `manifest.json`. Consequently, turning a local MCP server into a bundle is straightforward: You just have to put all your required files in a folder, create a `manifest.json`, and then create an archive.
To make this process easier, this package offers a CLI that helps you with the creation of both the `manifest.json` and the final `.dxt` file. To install it, run:
To make this process easier, this package offers a CLI that helps you with the creation of both the `manifest.json` and the final `.mcpb` file. To install it, run:
```sh
npm install -g @anthropic-ai/dxt
npm install -g @anthropic-ai/mcpb
```
1. In a folder containing your local MCP server, run `dxt init`. This command will guide you through the creation of a `manifest.json`.
2. Run `dxt pack` to create a `dxt` file.
3. Now, any app implementing support for DXT can run your local MCP server. As an example, open the file with Claude for macOS and Windows to show an installation dialog.
1. In a folder containing your local MCP server, run `mcpb init`. This command will guide you through the creation of a `manifest.json`.
2. Run `mcpb pack` to create a `mcpb` file.
3. Now, any app implementing support for MCPB can run your local MCP server. As an example, open the file with Claude for macOS and Windows to show an installation dialog.
You can find the full spec for the `manifest.json` and all its mandatory and optional fields in [MANIFEST.md](MANIFEST.md). Examples for extensions can be found in [examples](./examples/).
You can find the full spec for the `manifest.json` and all its mandatory and optional fields in [MANIFEST.md](MANIFEST.md). Examples for bundles can be found in [examples](./examples/).
## Prompt Template for AI Tools
AI tools like Claude Code are particularly good at creating desktop extensions when informed about the spec. When prompting an AI coding tool to build an extension, briefly explain what your extension aims to do - then add the following context to your instructions.
AI tools like Claude Code are particularly good at creating MCP bundles when informed about the spec. When prompting an AI coding tool to build a bundle, briefly explain what your bundle aims to do - then add the following context to your instructions.
> I want to build this as a Desktop Extension, abbreviated as "DXT". Please follow these steps:
> I want to build this as a MCP Bundle, abbreviated as "MCPB". Please follow these steps:
>
> 1. **Read the specifications thoroughly:**
> - https://github.com/anthropics/dxt/blob/main/README.md - DXT architecture overview, capabilities, and integration
> - https://github.com/anthropics/mcpb/blob/main/README.md - MCPB architecture overview, capabilities, and integration
> patterns
> - https://github.com/anthropics/dxt/blob/main/MANIFEST.md - Complete extension manifest structure and field definitions
> - https://github.com/anthropics/dxt/tree/main/examples - Reference implementations including a "Hello World" example
> 2. **Create a proper extension structure:**
> - https://github.com/anthropics/mcpb/blob/main/MANIFEST.md - Complete bundle manifest structure and field definitions
> - https://github.com/anthropics/mcpb/tree/main/examples - Reference implementations including a "Hello World" example
> 2. **Create a proper bundle structure:**
> - Generate a valid manifest.json following the MANIFEST.md spec
> - Implement an MCP server using @modelcontextprotocol/sdk with proper tool definitions
> - Include proper error handling, security measures, and timeout management
> 3. **Follow best development practices:**
> - Implement proper MCP protocol communication via stdio transport
> - Structure tools with clear schemas, validation, and consistent JSON responses
> - Make use of the fact that this extension will be running locally
> - Make use of the fact that this bundle will be running locally
> - Add appropriate logging and debugging capabilities
> - Include proper documentation and setup instructions
> 4. **Test considerations:**
> - Validate that all tool calls return properly structured responses
> - Verify manifest loads correctly and host integration works
>
> Generate complete, production-ready code that can be immediately tested. Focus on defensive programming, clear error messages, and following the exact DXT specifications to ensure compatibility with the ecosystem.
> Generate complete, production-ready code that can be immediately tested. Focus on defensive programming, clear error messages, and following the exact MCPB specifications to ensure compatibility with the ecosystem.
## Directory Structures
### Minimal Extension
### Minimal Bundle
A `manifest.json` is the only required file.
### Example: Node.js Extension
### Example: Node.js Bundle
```
extension.dxt (ZIP file)
├── manifest.json # Required: Extension metadata and configuration
bundle.mcpb (ZIP file)
├── manifest.json # Required: Bundle metadata and configuration
├── server/ # Server files
│ └── index.js # Main entry point
├── node_modules/ # Bundled dependencies
├── package.json # Optional: NPM package definition
├── icon.png # Optional: Extension icon
├── icon.png # Optional: Bundle icon
└── assets/ # Optional: Additional assets
```
### Example: Python Extension
### Example: Python Bundle
```
extension.dxt (ZIP file)
├── manifest.json # Required: Extension metadata and configuration
bundle.mcpb (ZIP file)
├── manifest.json # Required: Bundle metadata and configuration
├── server/ # Server files
│ ├── main.py # Main entry point
│ └── utils.py # Additional modules
├── lib/ # Bundled Python packages
├── requirements.txt # Optional: Python dependencies list
└── icon.png # Optional: Extension icon
└── icon.png # Optional: Bundle icon
```
### Example: Binary Extension
### Example: Binary Bundle
```
extension.dxt (ZIP file)
├── manifest.json # Required: Extension metadata and configuration
bundle.mcpb (ZIP file)
├── manifest.json # Required: Bundle metadata and configuration
├── server/ # Server files
│ ├── my-server # Unix executable
│ ├── my-server.exe # Windows executable
└── icon.png # Optional: Extension icon
└── icon.png # Optional: Bundle icon
```
### Language Choice Recommendation
**We recommend implementing MCP servers in Node.js** rather than Python to reduce installation friction. Node.js ships with Claude for macOS and Windows, which means your bundle will work out-of-the-box for users without requiring them to install additional Python runtimes (or you to package them manually).
### Bundling Dependencies
**Python Extensions:**
**UV Runtime (v0.4+):**
- Use `server.type = "uv"` in manifest
- Include `pyproject.toml` with dependencies (no bundled packages needed)
- Host application manages Python and dependencies automatically
- Works cross-platform without user Python installation
- See `examples/hello-world-uv`
**Python Bundles (Traditional):**
- Use `server.type = "python"` in manifest
- Bundle all required packages in `server/lib/` directory
- OR bundle a complete virtual environment in `server/venv/`
- Use tools like `pip-tools`, `poetry`, or `pipenv` to create reproducible bundles
- Set `PYTHONPATH` to include bundled packages via `mcp_config.env`
- **Limitation**: Cannot portably bundle compiled dependencies (e.g., pydantic, which the MCP Python SDK requires)
**Node.js Extensions:**
**Node.js Bundles:**
- Run `npm install --production` to create `node_modules`
- Bundle the entire `node_modules` directory with your extension
- Bundle the entire `node_modules` directory with your bundle
- Use `npm ci` or `yarn install --frozen-lockfile` for reproducible builds
- Server entry point specified in manifest.json's `server.entry_point`
**Binary Extensions:**
**Binary Bundles:**
- Static linking preferred for maximum compatibility
- Include all required shared libraries if dynamic linking used
- Test on clean systems without development tools
# Contributing
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
## Development Setup
```sh
# Clone the repository
git clone https://github.com/anthropics/mcpb.git
cd mcpb
# Install dependencies
yarn
# Build the project
yarn build
# Run tests
yarn test
```
## Release Process
1. Update version in `package.json`
2. Create a pull request with version bump
3. After merge, create a GitHub release
4. Package will be automatically published to npm
# License
This project is licensed under the Apache License 2.0 for new contributions, with existing code under MIT - see the [LICENSE](LICENSE) file for details.

View file

@ -1,12 +1,12 @@
# DXT Examples
# MCPB Examples
This directory contains example Desktop Extensions that demonstrate the DXT format and manifest structure. These are **reference implementations** designed to illustrate how to build DXT extensions.
This directory contains example MCP Bundles that demonstrate the MCPB format and manifest structure. These are **reference implementations** designed to illustrate how to build MCPB extensions.
## ⚠️ Not Production Ready
**Important:** These examples are **NOT intended for production use**. They serve as:
- Demonstrations of the DXT manifest format
- Demonstrations of the MCPB manifest format
- Templates for building your own extensions
- Simple MCP server implementations for testing
@ -14,11 +14,12 @@ But, the MCP servers themselves are not robust secure production ready servers a
## Examples Included
| Example | Type | Demonstrates |
| --------------------- | ------- | ---------------------------------------- |
| `hello-world-node` | Node.js | Basic MCP server with simple time tool |
| `chrome-applescript` | Node.js | Browser automation via AppleScript |
| `file-manager-python` | Python | File system operations and path handling |
| Example | Type | Demonstrates |
| --------------------- | ------- | ------------------------------------------- |
| `hello-world-node` | Node.js | Basic MCP server with simple time tool |
| `chrome-applescript` | Node.js | Browser automation via AppleScript |
| `file-manager-python` | Python | File system operations and path handling |
| `calculator-rust` | Binary | Compiled Rust binary as MCP Bundle |
## Usage

View file

@ -0,0 +1,5 @@
Cargo.toml
Cargo.lock
src/
target/
README.md

View file

@ -0,0 +1,18 @@
[package]
name = "mcp-calculator"
version = "1.0.0"
edition = "2024"
[dependencies]
rmcp = { version = "1.2.0", features = ["server", "macros", "transport-io", "schemars"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "io-std"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
anyhow = "1.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "std", "fmt"] }
schemars = "1.0"
[profile.release]
strip = true
lto = true

View file

@ -0,0 +1,73 @@
# Calculator Rust Binary Example
Demonstrates packaging a compiled Rust binary as an MCP Bundle using the `binary` server type. Based on the [official Rust MCP SDK calculator example](https://github.com/modelcontextprotocol/rust-sdk/tree/main/examples/servers).
## What is Binary Server Type?
Unlike `node` or `uv` server types where the source code is bundled and executed by a runtime, the `binary` server type packages a pre-compiled native executable. This is useful for:
- Rust, Go, C/C++ MCP servers
- Performance-sensitive workloads
- Servers with no runtime dependencies
The tradeoff is that binaries are platform-specific — you need a separate build for each target OS/architecture.
## Structure
```
calculator-rust/
├── manifest.json # server.type = "binary"
├── Cargo.toml # Rust project
├── .mcpbignore # Exclude source from bundle
└── src/
└── main.rs # Calculator MCP server (~80 LOC)
```
After building, the `server/` directory is created with the compiled binary.
## Building
Requires [Rust](https://rustup.rs/) 1.85+.
```bash
cd examples/calculator-rust
cargo build --release
mkdir -p server
cp target/release/mcp-calculator server/
```
## Packing
```bash
mcpb pack examples/calculator-rust
```
The `.mcpbignore` file excludes source code and build artifacts — only `manifest.json` and `server/mcp-calculator` end up in the bundle.
## Testing
```bash
# MCP protocol handshake
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' \
| ./server/mcp-calculator
# Tool call
(printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}\n'
printf '{"jsonrpc":"2.0","method":"notifications/initialized"}\n'
printf '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"sum","arguments":{"a":3,"b":4}}}\n'
sleep 1) | ./server/mcp-calculator
```
Expected: `sum(3, 4)` returns `{"text":"7"}`.
## Tools
- **sum** — Calculate the sum of two numbers
- **sub** — Calculate the difference of two numbers
## Notes
- Binary size: ~2.5 MB (stripped, LTO enabled)
- The `Cargo.toml` uses `edition = "2024"` (Rust 1.85+)
- Logs are written to stderr via `tracing`, so they don't interfere with MCP's stdio transport
- Uses the [rmcp](https://crates.io/crates/rmcp) crate (official Rust MCP SDK)

View file

@ -0,0 +1,36 @@
{
"$schema": "../../dist/mcpb-manifest.schema.json",
"manifest_version": "0.3",
"name": "calculator-rust",
"display_name": "Calculator (Rust Binary)",
"version": "1.0.0",
"description": "A simple calculator MCP server compiled from Rust",
"long_description": "Demonstrates packaging a compiled Rust binary as an MCP Bundle using the binary server type. The server provides sum and sub tools for basic arithmetic. Based on the official Rust MCP SDK calculator example.",
"author": {
"name": "Model Context Protocol"
},
"server": {
"type": "binary",
"entry_point": "server/mcp-calculator",
"mcp_config": {
"command": "${__dirname}/server/mcp-calculator",
"args": [],
"env": {}
}
},
"tools": [
{
"name": "sum",
"description": "Calculate the sum of two numbers"
},
{
"name": "sub",
"description": "Calculate the difference of two numbers"
}
],
"keywords": ["calculator", "rust", "binary", "example"],
"license": "Apache-2.0",
"compatibility": {
"platforms": ["darwin", "linux"]
}
}

View file

@ -0,0 +1,80 @@
use anyhow::Result;
use rmcp::{
ServerHandler, ServiceExt,
handler::server::{router::tool::ToolRouter, wrapper::Parameters},
model::{ServerCapabilities, ServerInfo},
schemars, tool, tool_handler, tool_router,
transport::stdio,
};
use tracing_subscriber::{self, EnvFilter};
// --- Calculator types ---
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct SumRequest {
#[schemars(description = "the left hand side number")]
pub a: i32,
pub b: i32,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct SubRequest {
#[schemars(description = "the left hand side number")]
pub a: i32,
#[schemars(description = "the right hand side number")]
pub b: i32,
}
// --- Calculator server ---
#[derive(Debug, Clone)]
pub struct Calculator {
tool_router: ToolRouter<Self>,
}
#[tool_router]
impl Calculator {
pub fn new() -> Self {
Self {
tool_router: Self::tool_router(),
}
}
#[tool(description = "Calculate the sum of two numbers")]
fn sum(&self, Parameters(SumRequest { a, b }): Parameters<SumRequest>) -> String {
(a + b).to_string()
}
#[tool(description = "Calculate the difference of two numbers")]
fn sub(&self, Parameters(SubRequest { a, b }): Parameters<SubRequest>) -> String {
(a - b).to_string()
}
}
#[tool_handler]
impl ServerHandler for Calculator {
fn get_info(&self) -> ServerInfo {
ServerInfo::new(ServerCapabilities::builder().enable_tools().build())
.with_instructions("A simple calculator".to_string())
}
}
// --- Main ---
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env().add_directive(tracing::Level::DEBUG.into()))
.with_writer(std::io::stderr)
.with_ansi(false)
.init();
tracing::info!("Starting Calculator MCP server");
let service = Calculator::new().serve(stdio()).await.inspect_err(|e| {
tracing::error!("serving error: {:?}", e);
})?;
service.waiting().await?;
Ok(())
}

View file

@ -1,11 +1,11 @@
{
"$schema": "../../dist/dxt-manifest.schema.json",
"dxt_version": "0.1",
"$schema": "../../dist/mcpb-manifest.schema.json",
"manifest_version": "0.1",
"name": "chrome-applescript",
"display_name": "Control Chrome with AppleScript",
"version": "0.1.0",
"description": "Control Google Chrome browser tabs, windows, and navigation",
"long_description": "This extension allows you to control Google Chrome browser tabs, windows, and navigation through Chrome's official AppleScript API. You can open URLs, manage tabs, execute JavaScript, and retrieve page content.\n\nThis extension is meant to be a demonstration of Desktop Extensions.\n\nThis extension is not affiliated with Google or Chrome.",
"long_description": "This extension allows you to control Google Chrome browser tabs, windows, and navigation through Chrome's official AppleScript API. You can open URLs, manage tabs, execute JavaScript, and retrieve page content.\n\nThis extension is meant to be a demonstration of MCP Bundles.\n\nThis extension is not affiliated with Google or Chrome.",
"author": {
"name": "Anthropic",
"email": "support@anthropic.com",
@ -70,5 +70,6 @@
"platforms": ["darwin"]
},
"keywords": ["chrome", "browser", "remote"],
"license": "MIT"
"license": "MIT",
"privacy_policies": []
}

View file

@ -33,17 +33,6 @@ class ChromeControlServer {
this.setupHandlers();
}
// Helper methods
escapeForAppleScript(str) {
if (typeof str !== "string") return str;
// Basic AppleScript string escaping
return str
.replace(/\\/g, "\\\\") // Escape backslashes first
.replace(/"/g, '\\"') // Then escape double quotes
.replace(/\n/g, "\\n") // Escape newlines
.replace(/\r/g, "\\r"); // Escape carriage returns
}
async checkChromeAvailable() {
try {
const script = 'tell application "Google Chrome" to return "available"';
@ -82,12 +71,28 @@ class ChromeControlServer {
}
}
// Coerce tab_id to a safe numeric value before interpolating into
// AppleScript. inputSchema type:"number" is advisory — runtime may receive
// a string, which would otherwise be injected into the osascript template.
toSafeTabId(tabId) {
if (tabId === null || tabId === undefined) return null;
const n = Number.parseInt(tabId, 10);
if (Number.isNaN(n)) {
throw new Error("tab_id must be a number");
}
return n;
}
async findTabById(tabId) {
const safeTabId = this.toSafeTabId(tabId);
if (safeTabId === null) {
return { w: null, t: null, found: false };
}
const script = `
tell application "Google Chrome"
repeat with w in windows
repeat with t in tabs of w
if (id of t as string) is "${tabId}" then
if (id of t as string) is "${safeTabId}" then
return {w, t, true}
end if
end repeat
@ -103,7 +108,8 @@ class ChromeControlServer {
operation,
successMessage = "Operation completed",
) {
if (!tabId) {
const safeTabId = this.toSafeTabId(tabId);
if (safeTabId === null) {
// No tab ID, execute on active tab
return this.executeAppleScript(operation.activeScript);
}
@ -112,7 +118,7 @@ class ChromeControlServer {
tell application "Google Chrome"
repeat with w in windows
repeat with t in tabs of w
if (id of t as string) is "${tabId}" then
if (id of t as string) is "${safeTabId}" then
${operation.tabScript}
return "${successMessage}"
end if
@ -272,10 +278,23 @@ class ChromeControlServer {
throw new Error("URL is required and must be a string");
}
const escapedUrl = this.escapeForAppleScript(url);
try {
new URL(url);
} catch (error) {
return {
content: [
{
type: "text",
text: `Error: url is not a valid url - ${error.message}`,
},
],
isError: true,
};
}
const script = new_tab
? `tell application "Google Chrome" to open location "${escapedUrl}"`
: `tell application "Google Chrome" to set URL of active tab of front window to "${escapedUrl}"`;
? `tell application "Google Chrome" to open location ${JSON.stringify(url)}`
: `tell application "Google Chrome" to set URL of active tab of front window to ${JSON.stringify(url)}`;
await this.executeAppleScript(script);
return {
@ -551,6 +570,7 @@ class ChromeControlServer {
"JavaScript code is required and must be a string",
);
}
const safeTabId = this.toSafeTabId(tab_id);
// Wrap the code to capture console.log outputs
const wrappedCode = `
@ -626,15 +646,14 @@ class ChromeControlServer {
})();
`;
const escapedCode = this.escapeForAppleScript(wrappedCode);
const script = tab_id
? `
const script =
safeTabId != null
? `
tell application "Google Chrome"
repeat with w in windows
repeat with t in tabs of w
if (id of t as string) is "${tab_id}" then
set result to execute t javascript "${escapedCode}"
if (id of t as string) is "${safeTabId}" then
set result to execute t javascript ${JSON.stringify(wrappedCode)}
return result
end if
end repeat
@ -642,9 +661,9 @@ class ChromeControlServer {
return "Tab not found"
end tell
`
: `
: `
tell application "Google Chrome"
execute active tab of front window javascript "${escapedCode}"
execute active tab of front window javascript ${JSON.stringify(wrappedCode)}
end tell
`;
@ -695,14 +714,16 @@ class ChromeControlServer {
case "get_page_content": {
const { tab_id } = args;
const safeTabId = this.toSafeTabId(tab_id);
const jsCode = "document.body.innerText";
const script = tab_id
? `
const script =
safeTabId != null
? `
tell application "Google Chrome"
repeat with w in windows
repeat with t in tabs of w
if (id of t as string) is "${tab_id}" then
if (id of t as string) is "${safeTabId}" then
set pageContent to execute t javascript "${jsCode}"
return pageContent
end if
@ -711,7 +732,7 @@ class ChromeControlServer {
return "Tab not found"
end tell
`
: `
: `
tell application "Google Chrome"
execute active tab of front window javascript "${jsCode}"
end tell

View file

@ -0,0 +1,7 @@
.venv/
__pycache__/
*.pyc
.pytest_cache/
.mypy_cache/
*.egg-info/
uv.lock

Some files were not shown because too many files have changed in this diff Show more