Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70fe3b34cd |
||
|
|
b4acc3f730 |
||
|
|
0817c20eb3 |
||
|
|
5161613c79 |
||
|
|
f9a551bf47 |
||
|
|
73f8475a80 |
||
|
|
e2d6196a39 |
||
|
|
dace08d31f |
||
|
|
a3a662451e |
||
|
|
e54083549b |
||
|
|
a2c331b513 |
||
|
|
a3bd97131e |
||
|
|
7f4596d8c8 |
||
|
|
cf1f956935 |
||
|
|
122ef0e9e9 |
||
|
|
cb052a20e5 |
||
|
|
8f5f2104df |
||
|
|
f14863bcdc |
||
|
|
f4671638a2 |
||
|
|
a907aead99 |
||
|
|
cc4aa751b6 |
||
|
|
a5d9ae8ed2 |
||
|
|
bb676eb17d |
||
|
|
1dca91e2be |
||
|
|
19afbcdc18 |
||
|
|
24aa4efc88 |
||
|
|
27083dcf93 |
||
|
|
163fa29a1c |
||
|
|
2a788100a6 |
||
|
|
1dbbffc972 |
||
|
|
761e834ba8 |
||
|
|
3635e20ca8 |
||
|
|
7c7f4b6af0 |
||
|
|
2ed5481016 |
||
|
|
be3b8f2561 |
||
|
|
9c22416146 |
||
|
|
2ab44ffa5b |
||
|
|
970f2d5e5d |
||
|
|
ca4a8819a0 |
||
|
|
d90365e626 |
||
|
|
dd9502e8ec |
||
|
|
349b0ceb47 |
||
|
|
00e4bb9d10 |
||
|
|
671d3d6f2d |
||
|
|
29d23abfe6 |
||
|
|
dc7e1514ce |
||
|
|
d2826644b6 |
||
|
|
5079fcfe30 |
||
|
|
5f6b15bc81 |
||
|
|
5f87ea58d6 |
||
|
|
e4f1236bf2 |
||
|
|
08cb52bc86 |
||
|
|
e59797f9ce |
||
|
|
07b77432a6 |
||
|
|
3a9ee6e007 |
||
|
|
21c9710584 |
||
|
|
8018a9a2e0 |
||
|
|
3fffc30560 |
||
|
|
70c3615fc9 |
||
|
|
efe9e3345d |
||
|
|
30a3b8e779 |
||
|
|
d7f76fc02d |
||
|
|
e7d6ea3e68 |
||
|
|
7f40d5be42 |
||
|
|
753f27e1ba |
||
|
|
3538bd4f3b |
||
|
|
2d6dd39b3e |
||
|
|
05187d7235 |
||
|
|
c137df512d |
||
|
|
2d76201204 |
||
|
|
5fb25a253e |
||
|
|
86166630b4 |
||
|
|
f3ac79afda |
||
|
|
98fc900d5a |
||
|
|
b75f8a67f9 |
||
|
|
98126b777e |
||
|
|
ce8a5aec4a |
||
|
|
8c543a32f6 |
||
|
|
bc2d083d18 |
||
|
|
86e641c0b5 |
||
|
|
257af30812 |
||
|
|
406e7bb5bd |
||
|
|
82b12a406e |
||
|
|
7ecb050280 |
||
|
|
ba74af5217 |
||
|
|
8bea47f0b7 |
||
|
|
a2bb7589b6 |
||
|
|
184173e342 |
||
|
|
ddad8064ef |
||
|
|
55e3c3cfd8 |
||
|
|
11d1397ee8 |
||
|
|
c29d1000f3 |
||
|
|
1660697588 |
||
|
|
789b37087c |
||
|
|
db5d6be33c |
||
|
|
ae3d9614e2 |
||
|
|
48232bf64e |
||
|
|
e7282946b6 |
||
|
|
eeb9dca819 |
||
|
|
b5fa7df6eb |
||
|
|
faafd4523a |
||
|
|
67938cdab9 |
||
|
|
7961b32cfc |
||
|
|
f37496928b |
||
|
|
ccf9470979 |
||
|
|
49c68b0452 |
||
|
|
55154fa6fb |
||
|
|
d929b8c33c |
||
|
|
ef6908e612 |
||
|
|
18d096526e |
||
|
|
bdcfeadac5 |
||
|
|
1640adefe8 |
||
|
|
2a0ba89918 |
||
|
|
d595dd66dc |
||
|
|
f7efd3a444 |
||
|
|
143aa9a63c |
||
|
|
2b193ac391 |
||
|
|
0496e93851 |
||
|
|
ec05e897c7 |
||
|
|
e2d6836622 |
||
|
|
d12057eefd |
||
|
|
443d849420 |
||
|
|
caa61bcc49 |
||
|
|
90c18ca9fb |
||
|
|
e9aa4d0029 |
||
|
|
6c05338904 |
||
|
|
4c100e26da |
||
|
|
412b124b96 |
||
|
|
c4a9500c84 |
||
|
|
fefd9e1d21 |
||
|
|
ccb19277c4 |
||
|
|
76b79551ab |
||
|
|
3a0d4a8635 |
||
|
|
fe733e3450 |
||
|
|
6bfd100b60 |
||
|
|
336e878252 |
||
|
|
9f078c6163 |
||
|
|
16f173824c |
||
|
|
3d9c966951 |
||
|
|
2e9e70c5ff |
||
|
|
8e2ec66564 |
||
|
|
a43769d94b |
||
|
|
9ac5d8806c |
||
|
|
f2284f6681 |
||
|
|
8c231cfbdb |
||
|
|
454b0be584 |
||
|
|
c2d42b3e0a |
||
|
|
b7a2acb969 |
||
|
|
e772ed753d |
||
|
|
232e6b3f91 |
||
|
|
16e569a337 |
||
|
|
f92fe4ab69 |
||
|
|
39fe803479 |
||
|
|
9fce5b58d9 |
||
|
|
8ce2cc3840 |
||
|
|
2825da1d6a |
||
|
|
a65e7d0c59 |
||
|
|
b991c5fcfc |
||
|
|
bc129a7223 |
||
|
|
9d62ba5d50 |
||
|
|
bd7fdf7e3c |
||
|
|
a48002ec69 |
||
|
|
241c65be00 |
||
|
|
841698fbe2 |
||
|
|
5a46a05108 |
||
|
|
1de373a9c9 |
||
|
|
7997e72758 |
||
|
|
cd922a0704 |
||
|
|
76949836e0 |
||
|
|
cc7b6cde44 |
||
|
|
0b2658f5b0 |
||
|
|
e1938b9933 |
||
|
|
bf01918080 |
||
|
|
b062c0efad |
||
|
|
4fbb2aed2c |
||
|
|
7c9d61d9e6 |
||
|
|
08b34f4f76 |
||
|
|
a3ba5fc984 |
||
|
|
505c81a258 |
||
|
|
9523b5af19 |
||
|
|
641213ad47 |
||
|
|
2dcc7efe6f |
||
|
|
6f4ed9d662 |
||
|
|
e2a87144e9 |
||
|
|
a9544e29a7 |
||
|
|
83b5a773ae |
85 changed files with 14026 additions and 5033 deletions
31
.github/workflows/test.yml
vendored
31
.github/workflows/test.yml
vendored
|
|
@ -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
12
.gitignore
vendored
|
|
@ -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
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -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
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
3
.yarnrc.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.10.3.cjs
|
||||
137
CLI.md
137
CLI.md
|
|
@ -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
85
CONTRIBUTING.md
Normal 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
216
LICENSE
Normal 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.
|
||||
|
|
@ -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.
|
||||
232
MANIFEST.md
232
MANIFEST.md
|
|
@ -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
130
README.md
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
5
examples/calculator-rust/.mcpbignore
Normal file
5
examples/calculator-rust/.mcpbignore
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Cargo.toml
|
||||
Cargo.lock
|
||||
src/
|
||||
target/
|
||||
README.md
|
||||
18
examples/calculator-rust/Cargo.toml
Normal file
18
examples/calculator-rust/Cargo.toml
Normal 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
|
||||
73
examples/calculator-rust/README.md
Normal file
73
examples/calculator-rust/README.md
Normal 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)
|
||||
36
examples/calculator-rust/manifest.json
Normal file
36
examples/calculator-rust/manifest.json
Normal 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"]
|
||||
}
|
||||
}
|
||||
80
examples/calculator-rust/src/main.rs
Normal file
80
examples/calculator-rust/src/main.rs
Normal 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(())
|
||||
}
|
||||
|
|
@ -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": []
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
7
examples/file-manager-python/.mcpbignore
Normal file
7
examples/file-manager-python/.mcpbignore
Normal 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
Loading…
Reference in a new issue