tool-sandbox-mcp
v1.1.0
Published
MCP server that provides sandboxed code execution with access to upstream MCP tools via loopback.
Readme
tool-sandbox-mcp
Give your AI agent a single
execute_codetool that can call any of your upstream MCP tools — more efficiently.
When agents call tools directly, every tool definition and intermediate result flows through the context window. As I wrote about in code execution with MCP, this gets expensive fast: hundreds of tool definitions consume tokens upfront, and intermediate results (like full documents being copied between tools) bloat the context further.
tool-sandbox-mcp solves this by exposing a single execute_code tool that runs JavaScript in a sandboxed WASM environment with access to all upstream MCP tools. The agent writes code to call tools, filter data, and compose logic — all without intermediate results passing through the context window. Auth is proxied transparently from the upstream server, so users authenticate once.
MCP Client (Claude, Cursor, etc.)
→ tool-sandbox-mcp (execute_code)
→ runs JS in sandbox
→ calls upstream MCP tools as neededUsage
Set TOOL_SANDBOX_MCP_CONFIG to a JSON config object and run:
TOOL_SANDBOX_MCP_CONFIG='{"upstream": "https://mcp.example.com"}' npx -y tool-sandbox-mcpThis starts an HTTP MCP server on localhost:3000. When a user connects, they authenticate with the upstream server (via proxied OAuth). The server exposes a single execute_code tool — the agent writes JavaScript that can call any tool on the upstream.
In general you'll want to point this at some kind of gateway which aggregates MCP servers. You can use mcp-aggregator for this if you don't already have a gateway. (The selfPrefix config argument can prevent recursive calls if you want).
The env var can also point to a file path:
TOOL_SANDBOX_MCP_CONFIG=/path/to/config.json npx -y tool-sandbox-mcpOr create tool-sandbox-mcp.config.json in the working directory — it's picked up automatically:
npx -y tool-sandbox-mcpConfig
Only upstream is required. Everything else has sensible defaults.
| Field | Required | Description |
|-------|----------|-------------|
| upstream | Yes | URL of the upstream MCP server (e.g. "https://mcp.example.com"). |
| port | No | Port to listen on. Defaults to 3000. |
| host | No | Host to bind to. Defaults to "0.0.0.0". |
| issuerUrl | No | Public URL of this server. Required when behind a reverse proxy. |
| selfPrefix | No | Prefix to filter out from upstream tools to prevent recursion. Defaults to "tool-sandbox". |
| store | No | Enable persistent store across calls via store_id. Requires single-node deployment. Defaults to false. |
A full example:
{
"upstream": "https://gateway.mcp.example.com",
"issuerUrl": "https://tool-sandbox.mcp.example.com",
"selfPrefix": "tool-sandbox-mcp",
"port": 3000,
}How it works
The server proxies the upstream's OAuth — logging in to tool-sandbox-mcp means logging in to the upstream server. When the agent calls execute_code, tool-sandbox-mcp:
- Connects to the upstream MCP server with the user's token
- Fetches available tools (filtering out its own to prevent recursion)
- Runs the agent's JavaScript in a WASM sandbox with those tools available
- Returns the result
Inside the sandbox, the agent can use:
await tool(name, args)to call any upstream toolawait tool('list_tools', {})to discover available toolsawait tool('describe_tool', {name})to get a tool's schemareturn valueto return a result
Contributing
Pull requests are welcomed on GitHub! To get started:
- Install Git and Node.js
- Clone the repository
- Install dependencies with
npm install - Run
npm run testto run tests - Build with
npm run build
Releases
Versions follow the semantic versioning spec.
To release:
- Use
npm version <major | minor | patch>to bump the version - Run
git push --follow-tagsto push with tags - Wait for GitHub Actions to publish to the NPM registry.
