Skip to content
Runtime

How to run an MCP server in a sandbox

Call sbx.mcp.start([{ id: "github" }]). Wait for sbx.mcp.ready(). Then give your agent each server's HTTPS URL and bearer header.

On Runtime a catalog MCP server starts in one call, and its API key never enters the sandbox. A setting that holds a key names a Runtime secret: the server sees only a placeholder, and the egress proxy outside the microVM adds the real value to its HTTPS requests to that secret's own hosts. The catalog has servers for GitHub, Postgres, a Playwright browser, filesystem, fetch, git, time, memory, sequential thinking, Notion, Context7, Brave Search, Exa, Firecrawl and Supabase, all MIT or Apache-2.0. A 2 vCPU, 4 GiB sandbox costs $0.03125 an hour while the servers wait for calls (pricing).

Start servers from the catalog

Store the token once as a secret. Then start the servers by ID:

TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.secrets.set("GITHUB_TOKEN", {  value: process.env.GITHUB_TOKEN ?? "",  hosts: ["api.github.com"],});await using sbx = await runtime.sandboxes.create({ timeoutSeconds: 3600 });await sbx.mcp.start([  { id: "github", secrets: { GITHUB_PERSONAL_ACCESS_TOKEN: "GITHUB_TOKEN" } },  { id: "fetch" },]);const gateway = await sbx.mcp.ready(); // waits until every server is installedfor (const server of gateway.servers) console.log(server.name, server.status, server.url);console.log(gateway.headers); // { Authorization: "Bearer ..." }
Pythonimport osfrom withruntime import Runtimeruntime = Runtime()runtime.secrets.set("GITHUB_TOKEN", value=os.environ.get("GITHUB_TOKEN", ""),                    hosts=["api.github.com"])with runtime.sandboxes.create(timeout_seconds=3600) as sbx:    sbx.mcp.start([        {"id": "github", "secrets": {"GITHUB_PERSONAL_ACCESS_TOKEN": "GITHUB_TOKEN"}},        {"id": "fetch"},    ])    gateway = sbx.mcp.ready()    for server in gateway["servers"]:        print(server["name"], server["url"])    print(gateway["headers"])
Terminalruntime secrets set GITHUB_TOKEN --host api.github.com < token.txtruntime sandboxes mcp "${id}" start github fetch --secret github.GITHUB_PERSONAL_ACCESS_TOKEN=GITHUB_TOKENruntime sandboxes mcp "${id}"         # state, URLs and the header to sendruntime sandboxes mcp "${id}" stop

The CLI's start command also prints a claude mcp add line for each server, so Claude Code can use them immediately. runtime sandboxes mcp catalog (or runtime.mcp.catalog()) lists every server, with its license, pinned version, settings and the hosts it calls.

Connect an agent to the URLs

Each server responds at its own Streamable HTTP URL. That URL is reached through a private preview link. Every request also carries the gateway's bearer token. Any MCP client that supports Streamable HTTP connects with those two values. Under the MCP specification, a client sends each message as an HTTP POST to one endpoint. It accepts either a JSON response or an event stream:

TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create();await sbx.mcp.start([{ id: "time" }]);const gateway = await sbx.mcp.ready();const url = gateway.servers[0]?.url;const reply = await fetch(url!, {  method: "POST",  headers: {    ...gateway.headers,    "content-type": "application/json",    accept: "application/json, text/event-stream",  },  body: JSON.stringify({    jsonrpc: "2.0",    id: 1,    method: "initialize",    params: {      protocolVersion: "2025-06-18",      capabilities: {},      clientInfo: { name: "probe", version: "1.0.0" },    },  }),});console.log(reply.status, reply.headers.get("content-type"));

In practice, pass the URL and header to your agent framework's MCP client instead of writing JSON-RPC by hand.

Run your own stdio server

A server you wrote runs the same way. Upload it, and name its command. The gateway turns its stdio into a URL, as it does for catalog servers:

TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create();await sbx.files.upload("./my-mcp", "/workspace/my-mcp");await sbx.exec("pip install -r my-mcp/requirements.txt", { check: true, timeoutMs: 300_000 });await sbx.mcp.start([{ name: "mine", command: ["python3", "my-mcp/server.py"] }]);console.log((await sbx.mcp.ready()).servers);
Pythonfrom withruntime import Sandboxwith Sandbox.create() as sbx:    sbx.files.upload("./my-mcp", "/workspace/my-mcp")    sbx.exec("pip install -r my-mcp/requirements.txt", check=True, timeout_ms=300_000)    sbx.mcp.start([{"name": "mine", "command": ["python3", "my-mcp/server.py"]}])    print(sbx.mcp.ready()["servers"])

The settings

Field What it does
id A catalog server, such as github, fetch or postgres
secrets Maps a setting that the server reads to a Runtime secret. The server sees a stand-in.
env Plain settings passed as given
options The catalog entry's own options
name and command Your own stdio server, run as the sandbox's user
sbx.mcp.ready() Waits until no server is still installing; status is ready or failed
gateway.headers The Authorization header every request needs
sbx.mcp.stop() Stops the servers; the sandbox keeps running
runtime_sandboxes_mcp (MCP) The same catalog and start, for an agent already connected to Runtime's MCP

Mistakes and how Runtime handles them

  • Putting a token in env. It then sits in the sandbox, where any code there can read it. Put it in secrets instead. Then a prompt injection that dumps the environment finds only a worthless placeholder (secrets).
  • A database password. A database password is not an HTTPS header, so the proxy cannot swap it in on the way out. The Postgres server's DATABASE_URI is passed as given.
  • A host the network rules refuse. The servers run behind the sandbox's own network rules. A catalog host that the rules block returns a warning. Runtime never changes the rules for you.
  • Calling a URL without the header. Every request needs the bearer token as well as the preview link. So a leaked URL alone gets nothing.
  • Confusing two things called MCP. runtime mcp is Runtime's own MCP server. It lets an agent create and control sandboxes (MCP). The servers on this page run inside one sandbox, and they serve your agent's tools.

Where this helps

  • An agent in Claude Code or Codex gets GitHub, browser or database tools without running them on your laptop.
  • Untrusted or third-party servers run in a microVM of their own, away from your machine and network (run untrusted LLM code).
  • What is MCP? explains the protocol.

Start

Terminalnpx withruntime sandboxes run --keep -- echo ready

A new account gets 100 free hours of a 1 GB machine in its first 30 days, with no card. The first run prints a link to approve in your browser.

Sources

Facts on this page were checked on 26 October 2026.

Related.

100 free hoursin your first 30 days.

of a 1 GB machine

  • No credit card
  • Four sandboxes at once, 2 vCPU and 4 GiB each
  • Then prepaid credit from $10, no plan fee
Start free, no card
Start free, no card