sandbox-mcp exposes the sandbox surface as Model Context Protocol tools
over stdio, so MCP clients — Claude Code, Cursor, agent frameworks — drive
real microVM sandboxes with no glue code.
// .mcp.json (Claude Code) / mcp.json (Cursor)
{
"mcpServers": {
"sandbox": {
"command": "/usr/local/bin/sandbox-mcp",
"args": ["-addr", "10.0.0.5:7777", "-token", "...",
"-template", "ghcr.io/cocoonstack/sandbox/rt:24.04"]
}
}
}
Flags fall back to SANDBOXD_ADDR, SANDBOXD_TOKEN, SANDBOXD_TEMPLATE,
then to 127.0.0.1:7777 and rt:24.04. Build: cd mcp && go build -o
sandbox-mcp .
Every tool call is capped at 5 minutes; an exec that hits the cap is killed
in the guest, which can hold its reply up to 5 s past the cap.
| tool | what it does |
|---|---|
create_sandbox |
claim a microVM and return its id plus deadline; optional template, net (none default, or egress), size (small default, medium, large, xlarge, 2xlarge) and ttl_seconds (0 means one hour); warm claims take milliseconds, nothing renews the deadline |
exec |
run a shell command to completion; returns stdout, stderr and the exit code, each stream keeping its first 1 MiB with truncated set past that; a cut-off or dropped run returns the output collected so far next to an error field; a hibernated sandbox wakes transparently |
spawn |
start a command detached and return its pid; output goes to a 256 KiB ring buffer that logs replays |
ps |
list tracked processes (exec, spawn, pty) with state, exit code and start time |
logs |
replay the newest 256 KiB of a tracked process’s stdout/stderr (+ exit code once ended); an exited process is forgotten after 5 minutes |
kill |
signal a tracked process (0 = SIGKILL); an exited process is a no-op success |
write_file / read_file / list_dir |
atomic whole-file write (parent must exist); whole-file text read of a regular file up to 1 MiB (a larger file, a directory or a device is an error, invalid UTF-8 replaced, missing path is an error); one-level listing of {name, kind, size} entries |
fork |
clone into N children (1 to the node’s max_fork_count, default 16) carrying exact memory + disk state, all-or-nothing; the parent keeps running and each child lives one hour |
checkpoint |
capture full state without stopping; returns a checkpoint_id that can be branched repeatedly |
branch_checkpoint |
claim a fresh sandbox from a checkpoint’s captured moment; it lives one hour |
list_checkpoints / delete_checkpoint |
checkpoint lifecycle |
hibernate |
snapshot + stop, freeing memory while keeping id, files and processes; the next call that reaches the guest wakes it |
promote |
publish the sandbox as a named template on its node; re-promoting replaces it |
release |
destroy the sandbox and its files; the session forgets the id, so a second release is rejected as unknown |
node_info |
warm pools, promoted templates, live claims, drain state, capacity and mesh peers; needs the operator token |
Sandbox handles (and their tokens) are held by the server process for the
session, and released with it: when the MCP client disconnects or the server
is signalled, it destroys every sandbox that session claimed, whatever
ttl_seconds asked for; a claim still in flight at the signal is left to its
lease (one hour unless ttl_seconds says otherwise). checkpoint first if the
state must survive.
Checkpoints outlive sessions: branch_checkpoint accepts any known
id without a listing round-trip. If the connected node does not hold it, the
claim follows a live owner probe and redirect, or heals the checkpoint locally
when peer healing is enabled. delete_checkpoint is different: it acts on the
node bound to the handle, so deleting an id recovered in a later session needs
the MCP server pointed at a node that holds it.