MCP server

Give an MCP-capable agent its own disposable machine. The MCP server exposes the same create / execute / destroy operations as the REST API, as tools the model can call directly.

What MCP is

The Model Context Protocol is a standard way for an AI application to connect a model to external tools. The client (Claude Code, Claude Desktop, or any other MCP client) starts a server process, discovers the tools it offers, and lets the model call them. Our server is a small stdio process that turns those tool calls into API requests with your key — so the agent gets a sandbox without you writing any integration glue.

Install

The server runs through npx; there is nothing to install ahead of time. It needs Node.js 18 or newer and an API key from Dashboard → API keys.

Claude Code

claude mcp add sandbox \
  --env AAS_API_KEY=aas_sk_your_key_here \
  -- npx -y https://sandbox-as-a-service.com/mcp.tgz

Then check it is connected:

claude mcp list

Claude Desktop

Edit the MCP config file (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows) and restart the app:

{
  "mcpServers": {
    "sandbox": {
      "command": "npx",
      "args": ["-y", "https://sandbox-as-a-service.com/mcp.tgz"],
      "env": {
        "AAS_API_KEY": "aas_sk_your_key_here"
      }
    }
  }
}

Other MCP clients

Any client that can launch a stdio server works. The contract is: run npx -y https://sandbox-as-a-service.com/mcp.tgz with AAS_API_KEY in the environment. The server reads the key at startup and exits with an error if it is missing.

AAS_API_KEY=aas_sk_your_key_here npx -y https://sandbox-as-a-service.com/mcp.tgz

Tools

ToolArgumentsWhat it does
create_sandboxsize (small | medium | large, default small), name, timeout_minutes (1–1440, default 15)Creates a sandbox and returns its id once it is ready. Blocks until then.
run_commandsandbox_id (required), command (required), timeout_ms, cwd, envRuns a shell command as the unprivileged sandbox user and returns exit code, stdout and stderr.
write_filesandbox_id (required), path (required), content (required), encodingWrites a file into the sandbox. Content is transferred out of band, so quotes, backticks and binary data survive intact.
read_filesandbox_id (required), path (required), encodingReads a file back out — how the agent gets at whatever its code produced.
list_filessandbox_id (required), pathLists a directory recursively, with types and sizes. Lets the agent discover what a run produced rather than guessing.
get_sandboxsandbox_id (required)Returns status, size, and the expiry timestamp.
list_sandboxeslimit, include_deletedLists your sandboxes, newest first — useful for finding strays.
extend_sandboxsandbox_id (required), additional_minutes (required)Pushes the expiry out, up to the 1440-minute ceiling, when a job outgrows its timeout.
destroy_sandboxsandbox_id (required)Destroys the sandbox and stops billing for it.
get_usagenoneReports the remaining credit balance and recent usage, so the agent can see what it is spending.

The filesystem tools are what make the difference between an agent that can run a command and an agent that can do a piece of work: it writes a script, runs it, lists the directory to see what appeared, and reads the result back. Before those existed it had to build heredocs by hand, and generated code containing a quote would break the command that was supposed to write it.

The tools enforce exactly the same limits as the REST API — 20 concurrent sandboxes, the 24 hours lifetime ceiling, 1 MiB of captured output per stream — and surface the same errors, so an agent that hits quota_exceeded gets a message telling it to destroy a sandbox first.

Agent workflows

1. Run generated code before trusting it

The most useful thing an agent can do with a sandbox is check its own work. Instead of asking you to run a script it just wrote, it runs it somewhere disposable and reads the traceback.

You: Write a script that de-duplicates this CSV by email, keeping the newest row.
      Verify it works on a sample before showing it to me.

Agent: create_sandbox { "name": "csv-dedupe", "timeout_minutes": 15 }
       -> sbx_9f2c4a1b8d3e6f0a12

       write_file  { "sandbox_id": "sbx_...", "path": "sample.csv",
                     "content": "email,updated_at\n..." }

       write_file  { "sandbox_id": "sbx_...", "path": "dedupe.py",
                     "content": "import csv, sys\n..." }

       run_command { "sandbox_id": "sbx_...",
                     "command": "python3 /workspace/dedupe.py sample.csv" }
       -> exit_code 1, stderr: KeyError: 'Email'

       (fixes the case-sensitivity bug, re-runs)
       -> exit_code 0, stdout: 412 rows -> 388 rows

       destroy_sandbox { "sandbox_id": "sbx_..." }

2. Reproduce a bug in a clean checkout

"Works on my machine" stops being a question when the agent can build a fresh machine. Nothing from your laptop — no stale cache, no half-installed dependency, no local env var — is in the picture.

You: Issue #412 says the test suite fails on a fresh clone. Confirm it, and find out why.

Agent: create_sandbox { "size": "medium", "timeout_minutes": 60 }

       run_command { "command": "git clone --depth 1 https://github.com/acme/widget.git /workspace/w",
                     "timeout_ms": 180000 }

       run_command { "cwd": "/workspace/w",
                     "command": "python3 -m venv .venv && .venv/bin/pip install -q -e '.[test]'",
                     "timeout_ms": 300000 }

       run_command { "cwd": "/workspace/w",
                     "command": ".venv/bin/pytest -x -q 2>&1 | tail -c 20000",
                     "timeout_ms": 600000 }
       -> reproduces: the suite assumes a TZ env var that CI sets and a clean box does not

       destroy_sandbox { "sandbox_id": "sbx_..." }

3. Try a risky change without touching anything you own

Dependency bumps, migration scripts and "let's see what this does" commands belong on a machine whose worst case is a wasted few cents.

You: Does upgrading to pandas 3 break our ETL? Don't touch my working copy.

Agent: create_sandbox { "size": "medium", "name": "pandas-3-trial", "timeout_minutes": 45 }

       run_command { "command": "git clone --depth 1 https://github.com/acme/etl.git /workspace/etl",
                     "timeout_ms": 180000 }
       run_command { "cwd": "/workspace/etl",
                     "command": "python3 -m venv .venv && .venv/bin/pip install -q -r requirements.txt",
                     "timeout_ms": 300000 }
       run_command { "cwd": "/workspace/etl",
                     "command": ".venv/bin/pip install -q 'pandas>=3' && .venv/bin/pytest -q 2>&1 | tail -c 20000",
                     "timeout_ms": 600000 }
       -> 3 failures, all in the groupby-apply path; reports the diff needed

       destroy_sandbox { "sandbox_id": "sbx_..." }

Operating notes

  • Agents forget to clean up. Sandboxes expire on their own, but until then they bill. Ask the agent to destroy sandboxes when it is done, keep timeout_minutes short, and run list_sandboxes occasionally to catch strays.
  • Keep the key out of the sandbox. AAS_API_KEY belongs in the MCP server's environment, never in an env passed to run_command — code inside a sandbox that has your key can spend your balance.
  • Nothing survives. When the sandbox is destroyed its disk is destroyed. Have the agent copy results out — into its reply, into a git remote, or into your own storage — before it destroys the machine.
  • The concurrency limit is shared. 20 sandboxes per account, counting whatever your other integrations are running.