Paper: "Orchestrating WASM-based MCP Tool Runtimes for AI Agents across Edge-Cloud Continuum" Moohyun Song, Hayoung Kim, Kyoohyun Lee, Jae Gi Son, Kyungyong Lee The 26th IEEE/ACM International Symposium on Cluster, Cloud and Internet Computing (CCGrid 2026)
A framework for building MCP (Model Context Protocol) servers in Rust, compiled to WASM. Supports both Stdio (local) and HTTP (serverless) transports from a single crate. This repository is a submodule of EdgeAgent, providing WASM-based MCP server implementations used for edge-cloud tool orchestration.
Write MCP servers once in Rust, compile to WASM, and run anywhere - locally via wasmtime run
or remotely via wasmtime serve / Knative / serverless platforms.
- Pure WASM: No Python/Node.js dependency - just WASM binaries
- Unified Codebase: Single crate with feature flags for CLI/HTTP builds
- Lightweight: ~300KB-1.3MB binaries (depends on server complexity)
- FastMCP-like DX: Declarative tool registration with
McpServer::builder() - Docker Support: Dockerfiles for both WASM and Python servers
- Deployment Ready: Scripts for ECR, private registry, and container deployment
# Install Rust WASI target
rustup target add wasm32-wasip2
# Install Wasmtime
curl https://wasmtime.dev/install.sh -sSf | bash./scripts/build_all.shThis builds all 9 servers in both CLI and HTTP variants:
mcp_server_*_cli.wasm- forwasmtime run(stdio)mcp_server_*_http.wasm- forwasmtime serve(HTTP)
# Stdio mode (local development)
wasmtime run ./target/wasm32-wasip2/release/mcp_server_time_cli.wasm
# HTTP mode (serverless)
wasmtime serve --addr 127.0.0.1:8000 -S cli=y \
--dir=/tmp/test \
./target/wasm32-wasip2/release/mcp_server_filesystem_http.wasmWasmMCP/
├── wasmmcp/ # Core framework
│ ├── src/
│ │ ├── lib.rs # Public API
│ │ ├── server.rs # McpServer builder
│ │ ├── builder.rs # Server builder implementation
│ │ ├── registry.rs # Tool registry
│ │ ├── timing.rs # Timing utilities
│ │ ├── transport/ # Stdio/HTTP transports
│ │ └── protocol/ # JSON-RPC handling
│
├── wasmmcp-macros/ # export_cli!, export_http! macros
│
├── shared/ # Shared code across servers
│ └── src/
│ └── lib.rs # Common utilities
│
├── servers/ # MCP server implementations
│ ├── wasm_server/ # Rust WASM servers
│ │ ├── time/ # Time tools (timezone conversion)
│ │ ├── filesystem/ # 14 file system tools
│ │ ├── git/ # Git repository tools
│ │ ├── fetch/ # URL fetching (wasi:http)
│ │ ├── summarize/ # LLM-based summarization
│ │ ├── log-parser/ # Log parsing with regex
│ │ ├── data-aggregate/ # Data aggregation tools
│ │ ├── sequential-thinking/ # Structured thinking tool
│ │ └── image-resize/ # Image processing tools
│ │
│ └── python_server/ # Python server implementations
│ ├── data_aggregate_server.py
│ ├── fetch_server.py
│ ├── image_resize_server.py
│ ├── log_parser_server.py
│ └── summarize_server.py
│
├── docker/ # Docker configurations
│ ├── wasm-server/ # WASM server Dockerfiles
│ ├── native-server/ # Python server Dockerfiles
│ └── registry/ # Container registry setup
│
├── scripts/
│ ├── build_all.sh # Build all servers
│ ├── build_server.sh # Build single server
│ └── run_server.sh # Run server
│ ├── push-to-ecr.sh # AWS ECR deployment
│ ├── push-to-registry.sh # Private registry deployment
│ ├── push-wasm-images.sh # WASM image deployment
│ └── cleanup-ecr.sh # ECR cleanup
│
└── tests/
├── compare_*.py # Comparison tests vs Python implementations
├── mcp_comparator.py # Test framework
├── test_http_langchain.py # HTTP transport tests
└── test_langchain_integration.py # LangChain integration tests
use wasmmcp::schemars::JsonSchema;
use wasmmcp::serde::Deserialize;
use wasmmcp::prelude::*;
#[derive(Debug, Deserialize, JsonSchema)]
pub struct GreetParams {
/// Name to greet
pub name: String,
}
pub fn create_server() -> McpServer {
McpServer::builder("my-server")
.version("1.0.0")
.tool::<GreetParams, _>(
"greet",
"Say hello to someone",
|params| Ok(format!("Hello, {}!", params.name))
)
.build()
}
// Export for wasmtime run
#[cfg(feature = "cli-export")]
wasmmcp::export_cli!(create_server);
// Export for wasmtime serve
#[cfg(feature = "http-export")]
wasmmcp::export_http!(create_server);[package]
name = "mcp-server-myserver"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
wasmmcp = { path = "../../../wasmmcp" }
wasi = "0.14"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
schemars = "1"
[features]
default = ["cli-export"]
cli-export = []
http-export = []# CLI version
cargo build --target wasm32-wasip2 --release \
-p mcp-server-myserver --features cli-export --no-default-features
# HTTP version
cargo build --target wasm32-wasip2 --release \
-p mcp-server-myserver --features http-export --no-default-features| Server | Tools | Description |
|---|---|---|
| time | 2 | Timezone conversion (get_current_time, convert_time) |
| filesystem | 14 | File operations (read/write/edit/search/tree) |
| git | 12 | Git repository read operations |
| fetch | 1 | URL fetching with HTML-to-markdown conversion |
| summarize | 3 | LLM-powered text summarization (OpenAI/Upstage) |
| log-parser | 5 | Log parsing, filtering, statistics |
| data-aggregate | 5 | Data aggregation and deduplication |
| sequential-thinking | 1 | Structured problem-solving |
| image-resize | 6 | Image info, resize, hash, batch operations |
┌─────────────────────────────────────────────────────────────┐
│ MCP Server Logic (tools) │
├─────────────────────────────────────────────────────────────┤
│ wasmmcp framework │
│ (McpServer, ToolDef, Protocol) │
├──────────────────────────┬──────────────────────────────────┤
│ export_cli! │ export_http! │
│ (wasi:cli/run) │ (wasi:http/incoming-handler) │
├──────────────────────────┼──────────────────────────────────┤
│ wasmtime run │ wasmtime serve / Knative │
└──────────────────────────┴──────────────────────────────────┘
cli-export: Exportswasi:cli/runfor stdio communicationhttp-export: Exportswasi:http/incoming-handlerfor HTTP requests
Both features share the same create_server() function, eliminating code duplication.
from langchain_mcp_adapters.client import MultiServerMCPClient
mcp_config = {
"wasmmcp": {
"transport": "stdio",
"command": "wasmtime",
"args": ["run", "--dir=/tmp", "./target/wasm32-wasip2/release/mcp_server_filesystem_cli.wasm"],
}
}
client = MultiServerMCPClient(mcp_config)
async with client.session("wasmmcp") as session:
tools = await load_mcp_tools(session)mcp_config = {
"wasmmcp_http": {
"transport": "streamable_http",
"url": "http://localhost:8000",
}
}Each server has corresponding Dockerfiles in docker/wasm-server/ and docker/native-server/:
# Build WASM server image
docker build -f docker/wasm-server/Dockerfile.time -t wasmmcp-time:latest .
# Build Python server image
docker build -f docker/native-server/Dockerfile.time -t python-mcp-time:latest .# Deploy to AWS ECR
./scripts/push-to-ecr.sh <registry-domain>
# Deploy to private registry
./scripts/push-to-registry.sh <registry-domain>
# Deploy WASM images
./scripts/push-wasm-images.sh <registry-domain>
# Cleanup ECR
./scripts/cleanup-ecr.sh <registry-domain>Setup a local or cloud-based private registry:
# Local registry with Docker Compose
cd docker/registry
docker-compose -f docker-compose.registry-local.yml up -d
# HTTPS registry with Let's Encrypt
./setup-https-registry.sh <your-domain>
# HTTPS registry with DNS validation
./setup-https-dns.sh <your-domain>apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: wasmmcp-time
spec:
template:
spec:
runtimeClassName: wasmtime-spin
containers:
- image: your-registry/wasmmcp-time:latest- Knative + containerd (runwasi)
- Docker / Kubernetes
- Private container registries
| Server | CLI | HTTP | Difference |
|---|---|---|---|
| sequential-thinking | 264KB | 276KB | +12KB |
| summarize | 292KB | 300KB | +8KB |
| data-aggregate | 376KB | 388KB | +12KB |
| git | 388KB | 404KB | +16KB |
| filesystem | 436KB | 448KB | +12KB |
| fetch | 528KB | 540KB | +12KB |
| time | 1.2MB | 1.2MB | ~0 |
| log-parser | 1.3MB | 1.3MB | ~0 |
| image-resize | 1.2MB | 1.2MB | ~0 |
[workspace.dependencies]
tokio = { version = "1", default-features = false }
rmcp = { version = "0.10", default-features = false, features = ["server", "macros"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
schemars = "1"
wasi = "0.14"Apache 2.0. See LICENSE for details.
If you use WasmMCP in your research, please cite our paper:
@inproceedings{song2026orchestrating,
title={Orchestrating WASM-based MCP Tool Runtimes for AI Agents across Edge-Cloud Continuum},
author={Song, Moohyun and Kim, Hayoung and Lee, Kyoohyun and Son, Jae Gi and Lee, Kyungyong},
booktitle={The 26th IEEE/ACM International Symposium on Cluster, Cloud and Internet Computing (CCGrid)},
year={2026}
}