Run any MCP server inside an isolated E2B cloud sandbox instead of on your machine — one command, no code changes on either side.
npx mcp-sandbox run -- npx -y some-mcp-server-from-the-internetTo your MCP client (Claude Code, Claude Desktop, Cursor, …) this is the server: stdio JSON-RPC is bridged transparently. But the server itself executes in a disposable cloud VM with no access to your filesystem, your environment variables, or your network identity.
MCP servers are code you run with your agent's privileges — and most people launch them straight from a registry (npx -y whatever-mcp) without reading a line of it. A malicious or compromised server can read ~/.ssh, your browser profile, and every secret in your environment. Static scanners (like agent-audit) catch risky configuration; mcp-sandbox removes the blast radius: the worst a hostile server can do is trash its own disposable sandbox.
Use it for:
- trying unknown servers from marketplaces before you trust them
- running servers you'll never fully trust (scrapers, converters, community tools)
- observing what a server actually does (
--tracerecords every JSON-RPC message)
-
Get an API key at e2b.dev (free tier is fine) and export it:
export E2B_API_KEY=e2b_… -
Wrap any MCP server command:
npx mcp-sandbox run -- npx -y @modelcontextprotocol/server-sequential-thinking
-
Or register it with Claude Code so the sandboxing is permanent:
claude mcp add seq-thinking -- npx -y mcp-sandbox run -- npx -y @modelcontextprotocol/server-sequential-thinking
The first message from your client flows the moment the sandbox is up (typically ~1–2 s).
npx -y some-server downloads the package on first run. If you use that as the
server command directly, the process re-execs partway through startup and the
client's first initialize can be lost. Pre-install it in --setup and run the
resulting binary instead — startup is then near-instant and stdin is stable:
npx mcp-sandbox run \
--setup "npm install -g @modelcontextprotocol/server-everything" \
-- mcp-server-everythingThe client's initialize is buffered while --setup runs, so as long as your
MCP client's startup timeout covers the install (Claude Code's default is 60 s,
tunable via MCP_TIMEOUT), the handshake completes cleanly. mcp-sandbox prints
a hint if you pass an npx/uvx command without --setup.
| Flag | Meaning |
|---|---|
--env KEY=VALUE |
set an env var for the server (repeatable) |
--env KEY |
forward KEY from your local environment — an explicit allowlist, nothing else crosses |
--fs path[:to] |
copy a local file/directory into the sandbox before start (repeatable, default target /home/user/<basename>) |
--trace file.jsonl |
record all JSON-RPC traffic as JSONL ({ts, dir, msg} per line) |
--ttl seconds |
sandbox lifetime / hard session cap (default 1800) |
--template name |
E2B sandbox template (default base) |
--setup "cmd" |
run a command in the sandbox before the server starts (e.g. installs) |
E2B_API_KEY is read locally and never forwarded into the sandbox.
Some servers need data to work on (a docs folder for a search server, a CSV for
an analysis server). --fs copies it in explicitly:
npx mcp-sandbox run --fs ./docs -- npx -y some-docs-mcp # → /home/user/docs
npx mcp-sandbox run --fs ./data.csv:/srv/input.csv -- … # explicit targetThis is copy-in only — the server works on its own copy, and nothing it
writes ever comes back to your machine. Symlinks are never followed (so a
mounted directory can't smuggle in ~/.ssh through a link), and a mount is
rejected up front if it exceeds 2 000 files or 50 MB, before any sandbox is
created. Files land before --setup runs, so setup can use them
(e.g. --setup "pip install -r /home/user/project/requirements.txt").
- The server process runs in an E2B micro-VM: your files, your env and your local network are unreachable. The sandbox has its own internet access (that's usually what the server needs to be useful) — it acts from a cloud IP, not as you.
- Environment crossing is allowlist-only (
--env), the exact inverse of the usual "inherit everything" default. - The only channel between your machine and the server is the MCP protocol stream itself — and
--tracelets you keep a verbatim record of it. Prompt-injection attempts through tool results still reach your client (sandboxing can't fix that layer); what it removes is arbitrary code execution against your machine. - Sandboxes die at
--ttlno matter what.
MCP client ──stdio──▶ mcp-sandbox ──E2B API──▶ [sandbox: npx some-mcp-server]
JSON-RPC │ line-buffered bridge
└──▶ trace.jsonl (optional)
mcp-sandbox spawns one E2B sandbox per session, starts the server there with stdin: true, and pipes bytes both ways. Server output is line-buffered so your client never sees a partial JSON-RPC frame even when the transport chunks arbitrarily; server stderr is forwarded to your stderr with a [sandbox] prefix, never into the protocol stream.
npm install
npm test # 23 tests — bridge + --fs logic run offline, no E2B needed
npm run buildThe E2B integration lives behind a small SandboxBackend interface (src/types.ts), which is what makes the bridge fully testable offline.
- Trace viewer integration with agent-lens
- Sandbox pooling for faster cold starts
- HTTP/SSE transport bridging for remote-style servers
MIT © Ondřej Úlehla