Fork of Rust MCP SDK optimized for Rust integration with WebAssembly runtime support
Quick Start | FAQ | Documentation | Releases | Contributing | Discord
Warning
Early Development: This repository is not production ready yet. It is in early development and may change significantly.
This fork provides a Rust-native MCP SDK with:
- Multiple WASM Runtime Support: Both WASI (wasm32-wasip2) and WasmEdge runtimes
- Tokio 1.36: Downgraded from 1.40+ for broader compatibility
- Portable Tool Development: Build once, run anywhere with WebAssembly
See the examples directory for working implementations.
This fork enables portable MCP tools through WebAssembly, supporting multiple runtimes for different use cases:
- WASI (wasm32-wasip2): Standard WebAssembly System Interface for general-purpose tools
- WasmEdge: Extended runtime with PostgreSQL and HTTP client support for full-stack applications
| Problem | Wasmtime | WasmEdge |
|---|---|---|
| Outbound TCP/HTTP | ✗ Pre-opened FDs only | ✓ Full sockets |
| Inbound TCP (servers) | ⚠ Awkward | ✓ Native |
| Database connections | ✗ | ✓ Postgres, MySQL |
| LLM inference (GGML) | ✗ | ✓ |
| Whisper/audio | ✗ | ✓ |
| TensorFlow/PyTorch | ⚠ OpenVINO only | ✓ Multiple backends |
| Docker Desktop | ✓ | ✓ (ships built-in) |
| Edge K8s (KubeEdge, etc.) | ⚠ | ✓ First-class |
| Plugin system | ✗ | ✓ |
| TLS built-in | ⚠ | ✓ |
Current MCP ecosystem suffers from massive duplication - everyone writes the same tools. These tools are:
- Deterministic and non-differentiating
- Expensive to maintain relative to value
- Perfect candidates for community reuse
WebAssembly provides:
- Portability: Compile once, run on any runtime
- Security: Sandboxed execution with explicit capabilities
- Simplicity: Standard interfaces, no FFI complexity
- Reproducibility: Same tool version = same behavior
- Distribution: Share tools as binaries, not services
| Feature | mcpkit-rs | Wassette |
|---|---|---|
| Primary Focus | Fast development with more features out-of-box | Enterprise-focused with minimal feature set |
| Architecture | MCP SDK that compiles to WASM | Bridge between WASM Components and MCP |
| Language | Rust | Rust |
| MCP Implementation | Full MCP SDK (client/server) | MCP server only |
| WASM Runtime Support | Wasmtime + WasmEdge | Wasmtime only |
| Component Model | Direct WASM compilation | WASM Components (WIT) |
| Database Support | ✓ (via WasmEdge) | ✗ |
| HTTP Client | ✓ (via WasmEdge) | ✗ (pre-opened FDs only) |
| LLM/ML Support | ✓ (via WasmEdge) | ✗ |
| Permission System | Fine-grained config.yaml | Fine-grained policy.yaml |
| OCI Registry Support | ✓ | ✓ |
| Security Model | Runtime sandboxing | Capability-based + interactive |
| Network Hosting | ✗ | ✓ (planned) |
| Development Model | Write MCP tools in any WASM language | Write generic WASM Components |
| Tool Distribution | Binary/source/OCI registry | OCI registry |
| Zero Dependencies | ✗ (requires WASI runtime) | ✗ (requires WASI runtime) |
| Supported Languages | JavaScript, Go, Python, Rust | JS, Python, Rust, Go |
Choose mcpkit-rs when:
- Building MCP tools that need database or HTTP access
- Requiring ML/AI inference capabilities in tools
- Needing both MCP client and server functionality
- Wanting direct control over MCP implementation
- Needing flexibility to choose between multiple WASM runtimes
Choose Wassette when:
- Building language-agnostic WASM Components
- Requiring fine-grained security policies
- Distributing tools via OCI registries
- Needing network-hosted MCP servers
- Working with existing WASM Components
mcpkit-rs supports distributing MCP tools as OCI bundles, similar to Wassette. This enables sharing compiled WASM tools through container registries like Docker Hub or GitHub Container Registry.
Bundle your WASM binary and configuration into an OCI artifact, push it to any OCI-compliant registry, and pull it on any system with mcpkit-rs installed.
# Project structure
$ tree .
.
├── config.yaml # MCP tool configuration
├── target/
│ └── wasm32-wasip1/
│ └── release/
│ └── my-tool.wasm # Compiled WASM binary
└── Cargo.toml
# Build the bundle
$ mcpk bundle build --config config.yaml --wasm target/wasm32-wasip1/release/my-tool.wasm --output my-tool-bundle.tar
✓ Bundle created: my-tool-bundle.tar (2.3 MB)
# Push to OCI registry
$ mcpk bundle push --bundle my-tool-bundle.tar --uri oci://ghcr.io/myorg/my-tool:v1.0.0
✓ Pushed to ghcr.io/myorg/my-tool:v1.0.0
Digest: sha256:abc123...
# Pull and run on another system
$ mcpk bundle pull --uri oci://ghcr.io/myorg/my-tool:v1.0.0
✓ Downloaded my-tool:v1.0.0
Extracted to: ~/.mcpkit/tools/my-tool/- Rust 1.75+
- Tokio 1.36 (included in dependencies)
- WebAssembly runtime (choose based on your needs):
- WASI/Wasmtime: For standard WASI tools
- WasmEdge: For tools requiring PostgreSQL or HTTP client
# Install wasmtime
$ curl https://wasmtime.dev/install.sh -sSf | bash
# Add WASI compilation target
$ rustup target add wasm32-wasip2# Install WasmEdge with plugins
$ curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- --plugins wasmedge_rustls
# Add WasmEdge compilation target (uses wasm32-wasip1)
$ rustup target add wasm32-wasip1rmcp = { version = "0.13.0", features = ["server"] }
# For WASI compilation
[target.wasm32-wasip2.dependencies]
rmcp = { version = "0.13.0", features = ["server", "wasi"] }
# For WasmEdge compilation
[target.wasm32-wasip1.dependencies]
rmcp = { version = "0.13.0", features = ["server", "wasmedge"] }MCPKit ships MCP servers as OCI artifacts - WebAssembly modules bundled with configuration, pushed to any OCI registry. Similar to Microsoft's Wazero approach for portable WASM distribution.
$ echo "Building WASM module..."
$ cargo build --target wasm32-wasip1 --release
Finished release [optimized] target(s) in 0.12s
$ mcpk bundle push \
--wasm target/wasm32-wasip1/release/calculator.wasm \
--config config.yaml \
--uri oci://ghcr.io/myorg/calculator:v1.0.0
Creating bundle...
✓ Added module.wasm (2.1 MB)
✓ Added config.yaml (512 B)
✓ Generated manifest.json
Pushing to oci://ghcr.io/myorg/calculator:v1.0.0...
✓ Layer sha256:a3ed95ca... (2.1 MB)
✓ Layer sha256:b4d3f2c8... (1.0 KB)
✓ Manifest sha256:7f8a9b2c...
✓ Push complete: ghcr.io/myorg/calculator:v1.0.0
$ mcpk bundle pull oci://ghcr.io/myorg/calculator:v1.0.0 --output ./dist
Pulling from oci://ghcr.io/myorg/calculator:v1.0.0...
✓ Downloaded sha256:a3ed95ca... (2.1 MB)
✓ Downloaded sha256:b4d3f2c8... (1.0 KB)
✓ Extracted to ./dist
✓ Pull complete: 2 files
$ ls ./dist
module.wasm config.yaml manifest.jsonAuthenticate with GITHUB_USER and GITHUB_TOKEN environment variables. See examples/wasm/wasmtime/calculator for a complete implementation.
What's sandboxed: MCP tools (WASM modules) are sandboxed from the host system and each other.
Sandbox boundaries:
- Memory isolation: Each WASM instance has its own linear memory, no shared memory between modules
- Capability-based access: No syscalls without explicit grants via WASI capabilities
- Resource limits: CPU, memory, and execution time enforced by runtime
Protects against:
- Malicious MCP tools accessing host filesystem outside allowed paths
- Network exfiltration from calculator tools that shouldn't have network access
- Resource exhaustion (CPU/memory DoS)
- Cross-tool contamination (tools cannot access each other's memory/state)
- Unauthorized tool invocation (policy filters which tools are exposed)
Does NOT protect against:
- Malicious MCP clients (clients are trusted)
- Side-channel attacks (timing, cache)
- Supply chain attacks (you must trust the WASM binary source)
- Bugs in the WASM runtime itself (Wasmtime/WasmEdge)
- Policy misconfiguration (overly permissive policies)
Data IN: MCP JSON-RPC requests → Policy enforcement → WASM module via function imports
Data OUT: WASM return values → Policy enforcement → MCP JSON-RPC responses
Example enforcement:
# config.yaml policy section
policy:
core:
network:
deny: ["*"] # No network access
storage:
allow:
- uri: "fs:///tmp/**" # Only /tmp access
access: ["read", "write"]
mcp:
tools:
allow: ["add", "subtract"] # Only these tools exposed
deny: ["*"] # Hide all othersRuntime enforcement happens at WASI call boundaries - the WASM module literally cannot make syscalls that weren't pre-approved in the policy.