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
Alexander Sklar
2ed5481016
Bump version and update dependencies in package.json
update filesystem server version
2025-12-03 17:07:25 -08:00
37 changed files with 1552 additions and 155 deletions

6
.gitignore vendored
View file

@ -88,6 +88,8 @@ typings/
# Claude files
.claude.json
.claude/
CLAUDE.md
PROJECT_STATUS.md
# Vite
.vite/
@ -107,4 +109,8 @@ self-signed-key.pem
invalid-json.json
**/server/lib/**
# Rust example build artifacts
examples/calculator-rust/target/
examples/calculator-rust/server/
.yarn/install-state.gz

3
CLI.md
View file

@ -292,7 +292,8 @@ MCPB uses PKCS#7 (Cryptographic Message Syntax) for digital signatures:
```
[Original MCPB ZIP content]
MCPB_SIG_V1
[Base64-encoded PKCS#7 signature]
[4-byte little-endian length prefix]
[DER-encoded PKCS#7 signature]
MCPB_SIG_END
```

217
LICENSE
View file

@ -1,7 +1,216 @@
Copyright 2025 Anthropic, PBC.
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.
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:
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.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
No rights beyond those granted by the applicable original license are conveyed for such contributions.
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.
---
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

@ -403,11 +403,9 @@ 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 (experimental, v0.4+)
- **`uv`**: Python server using UV runtime (v0.4+)
### UV Runtime (Experimental, v0.4+)
> **Note:** UV runtime support is experimental and may change in future versions.
### 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.

View file

@ -109,7 +109,7 @@ bundle.mcpb (ZIP file)
### Bundling Dependencies
**UV Runtime (Experimental - v0.4+):**
**UV Runtime (v0.4+):**
- Use `server.type = "uv"` in manifest
- Include `pyproject.toml` with dependencies (no bundled packages needed)
@ -169,4 +169,4 @@ yarn test
# License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
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

@ -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

@ -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

View file

@ -1,28 +1,28 @@
{
"$schema": "../../dist/mcpb-manifest.schema.json",
"manifest_version": "0.1",
"manifest_version": "0.4",
"name": "file-manager-python",
"display_name": "Python File Manager MCP",
"version": "0.1.0",
"version": "0.2.0",
"description": "A Python MCP server for file operations",
"long_description": "This extension provides file management capabilities through a Python MCP server. It demonstrates Python-based MCP Bundle development, including file operations, directory management, and proper MCP protocol implementation.",
"long_description": "This extension provides file management capabilities through a Python MCP server. It demonstrates Python-based MCP Bundle development using UV runtime, including file operations, directory management, and proper MCP protocol implementation.",
"author": {
"name": "Anthropic",
"email": "support@anthropic.com",
"url": "https://github.com/anthropics"
},
"server": {
"type": "python",
"type": "uv",
"entry_point": "server/main.py",
"mcp_config": {
"command": "python",
"command": "uv",
"args": [
"${__dirname}/server/main.py",
"run",
"--directory", "${__dirname}",
"server/main.py",
"--workspace=${user_config.workspace_directory}"
],
"env": {
"DEBUG": "${user_config.debug_mode}",
"PYTHONPATH": "${__dirname}/server/lib"
"DEBUG": "${user_config.debug_mode}"
}
}
},
@ -62,8 +62,7 @@
"claude_desktop": ">=0.10.0",
"platforms": ["darwin", "win32", "linux"],
"runtimes": {
"python": ">=3.8.0 <4"
"python": ">=3.10.0 <4"
}
},
"privacy_policies": []
}
}

View file

@ -1,31 +1,8 @@
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "file-manager-python"
version = "0.1.0"
version = "0.2.0"
description = "A Python MCP server for file operations"
authors = [
{name = "Anthropic", email = "support@anthropic.com"}
requires-python = ">=3.10"
dependencies = [
"mcp>=1.0.0",
]
license = {text = "MIT"}
classifiers = [
"Private :: Do Not Upload" # Prevents accidental uploads to PyPI
]
[project.dependencies]
mcp = ">=1.0.0"
trio = ">=0.22.0"
[tool.setuptools]
packages = ["server"]
[project.scripts]
bundle-deps = "python:install_deps"
# Custom scripts section for DXT development
[tool.dxt]
bundle = "pip install \"mcp[all]\" --target server/lib --upgrade --force-reinstall"
test = "python server/main.py --debug"
pack = "npx @anthropic-ai/dxt pack"

View file

@ -1,2 +0,0 @@
mcp>=1.0.0
trio>=0.22.0

View file

@ -1,10 +1,10 @@
{
"name": "ant.dir.ant.anthropic.filesystem",
"version": "0.1.3",
"version": "0.1.4",
"type": "module",
"private": true,
"main": "server/index.js",
"dependencies": {
"@modelcontextprotocol/server-filesystem": "2025.1.14"
"@modelcontextprotocol/server-filesystem": "2025.11.25"
}
}

View file

@ -64,7 +64,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
});
// Start the server
const transport = new StdioServerTransport();
server.connect(transport);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Hello World MCP server running...");
}
console.error("Hello World MCP server running...");
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});

View file

@ -1,6 +1,4 @@
# Hello World UV Runtime Example (Experimental)
> **Note:** UV runtime support is experimental and may change in future versions.
# Hello World UV Runtime Example
This example demonstrates a minimal MCP server using **UV runtime**.
@ -28,7 +26,7 @@ hello-world-uv/
**UV Runtime** (this example):
- `server.type = "uv"`
- No bundled dependencies
- No `mcp_config` needed
- `mcp_config` uses `uv run` to auto-resolve deps from `pyproject.toml`
- Small bundle size (~2 KB)
- Works on any platform

View file

@ -10,7 +10,11 @@
"icon": "icon.png",
"server": {
"type": "uv",
"entry_point": "src/server.py"
"entry_point": "src/server.py",
"mcp_config": {
"command": "uv",
"args": ["run", "--directory", "${__dirname}", "src/server.py"]
}
},
"compatibility": {
"platforms": ["darwin", "linux", "win32"],

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