Home / Docs / For agents · also: Quickstart · Coding agents in the sandbox

For agents

Three ways for an agent to get a sandbox: the MCP server, the plugin with its skill, or the sbx CLI. All three use your tenant API key. Section 4 has one copy-paste setup per client. Each smoke command below was run against production on 2026-10-11; the output shown is what came back. (This page is about agents that use sandboxes. For agent CLIs that run inside one, see coding agents in the sandbox.)

1. MCP server

One remote MCP server, ten tools: sandboxes_list, sandbox_templates, sandbox_create, sandbox_exec, sandbox_exec_output, sandbox_files_read, sandbox_files_write, sandbox_preview_url, sandbox_workspace, sandbox_kill. URL: https://api.sbx.agent-next.com/mcp/v1. Auth is the key in an X-API-Key header (or Authorization: Bearer).

Per-client setup (config, verify command and status for each client) is in section 4. Any client that supports a remote (streamable HTTP) MCP server with a custom header can use the URL and header above.

GPU sandboxes work through these tools too: sandbox_create with a GPU template, driven with sandbox_exec and sandbox_kill. Pause and resume, files, billing and errors are in the GPU sandboxes guide.

The snippets on this page read the key from SBX_API_KEY — the same tenant key the quickstart exports as E2B_API_KEY. Export whichever name the snippet you follow reads (export SBX_API_KEY="$E2B_API_KEY" bridges them); the plugin's bundled config reads ${SBX_API_KEY}.

Smoke command (lists the tools):

curl -s https://api.sbx.agent-next.com/mcp/v1 \
  -H "X-API-Key: $SBX_API_KEY" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
  | python3 -c "import json,sys;print([t['name'] for t in json.load(sys.stdin)['result']['tools']])"

Output:

['sandboxes_list', 'sandbox_templates', 'sandbox_create', 'sandbox_exec', 'sandbox_exec_output', 'sandbox_files_read', 'sandbox_files_write', 'sandbox_preview_url', 'sandbox_kill']

2. Plugin and skill

The agent-next-sandbox plugin bundles the MCP server above with a use-sandbox skill that tells the agent when to use a sandbox and the limits below. Installing it needs access to the source repository for now. There is no public install command and no public marketplace yet.

With repo access, from a checkout (Claude Code):

export SBX_API_KEY=<your key>
claude plugin marketplace add ./integrations/plugins
claude plugin install agent-next-sandbox@agent-next

Smoke command (checks the plugin and marketplace manifests; it does not call the network):

claude plugin validate integrations/plugins/agent-next-sandbox

Output:

Validating plugin manifest: integrations/plugins/agent-next-sandbox/.claude-plugin/plugin.json

✔ Validation passed

3. CLI (sbx)

sbx is the sandbox kit's command-line client: create, exec, list, templates, kill. Install it from the public kit repository:

python3 -m venv .venv
. .venv/bin/activate
pip install "git+https://github.com/agent-next/sandbox#subdirectory=cli"
export E2B_DOMAIN=sbx.agent-next.com
export E2B_API_KEY=<your key>

Smoke command (lists every live sandbox of this key; a key with none prints no sandboxes):

sbx --version && sbx list

Output:

0.0.4
no sandboxes

4. By client

One section per client: the sign-in paths it supports, a config to copy, one command to verify it, and its status. A client is marked Verified working only after its end-to-end run (create, exec, files, preview, kill, nothing left behind) passes. Until then its config is shown as Being verified: it follows the client's own documentation but has not passed that run, so check it with the verify command. Replace <your key> with your tenant API key (the value of E2B_API_KEY). The machine-readable status is clients.json, last updated 2026-10-12.

ClientSign-inStatus
Claude CodeX-API-Key header (verified), OAuth (not yet verified)Verified working
CodexBearer token, OAuthBeing verified
zcodeX-API-Key headerVerified working
CursorX-API-Key header (verified), OAuth (not yet verified)Verified working
Gemini CLIX-API-Key header (verified), OAuth (not yet verified)Verified working
OpenCodeX-API-Key header (verified), OAuth (not yet verified)Verified working
droidX-API-Key header (verified), OAuth (not yet verified)Verified working
devinX-API-Key header (verified), OAuth (not yet verified)Verified working
Claude web and desktopX-API-Key header, OAuthBeing verified
ChatGPT developer modeOAuthBeing verified
Personal agents templateSDK key (verified)Verified working
OpenClaw-style MCP and CLI agentsX-API-Key header (verified), OAuth and CLI (not yet verified)Verified working

Claude Code

Verified working X-API-Key header path: run end to end on 2026-10-12 as a new user in a fresh sandbox (create, exec, files, preview, kill, nothing left behind). Receipt. The OAuth path needs your browser once and has not been run end to end.

Auth: X-API-Key header (headless), or OAuth (one browser sign-in).

Config (X-API-Key header):

export SBX_API_KEY=<your key>
claude mcp add --transport http sandbox https://api.sbx.agent-next.com/mcp/v1 \
  --header 'X-API-Key: ${SBX_API_KEY}'

Config (OAuth instead):

claude mcp add --transport http sandbox https://mcp.agent-next.com/mcp
claude   # then /mcp, pick sandbox, Authenticate

Claude Code keeps copies of its config in $HOME/.claude/backups, and claude mcp remove sandbox does not touch them. With the single-quoted variable form above they hold only the variable name. The Claude Code page has the install, model setup and uninstall steps, including how to delete a backup that holds a key.

Verify:

claude mcp list

Codex

Being verified Not yet run end to end from a clean install. Use the config as a starting point.

Auth: Bearer token from an environment variable (the same key), or OAuth.

Config (~/.codex/config.toml, key from the environment):

[mcp_servers.sandbox]
url = "https://api.sbx.agent-next.com/mcp/v1"
bearer_token_env_var = "SBX_API_KEY"   # export SBX_API_KEY=<your key>

Config (OAuth instead):

[mcp_servers.sandbox]
url = "https://mcp.agent-next.com/mcp"   # then: codex mcp login sandbox

Verify:

codex mcp list

zcode

Verified working X-API-Key header path: run end to end on 2026-10-12 in a fresh sandbox (create, exec, files, preview, kill, nothing left behind) with the engine bundled in the official Linux app; the desktop window and its Settings form were not run. Receipt.

Auth: X-API-Key header.

Config ($HOME/.zcode/cli/config.json, or Settings > MCP Servers > New MCP Server with type HTTP; merge into the file if it already exists):

{
  "mcp": {
    "servers": {
      "agent-next-sandbox": {
        "type": "http",
        "url": "https://api.sbx.agent-next.com/mcp/v1",
        "headers": { "X-API-Key": "<your key>" }
      }
    }
  }
}

zcode is a desktop app with no MCP list command, so the verify command checks the URL and key you pasted. Then ask zcode to create a sandbox and run echo ok in it. To remove it, delete the agent-next-sandbox entry from the config file.

Verify:

curl -s https://api.sbx.agent-next.com/mcp/v1 \
  -H "X-API-Key: <your key>" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
  | python3 -c "import json,sys;print([t['name'] for t in json.load(sys.stdin)['result']['tools']])"

Cursor

Verified working X-API-Key header path: run end to end on 2026-10-12 as a new user on a workstation (cursor-agent is not in the sandbox template and needs your Cursor login) (create, exec, files, preview, kill, nothing left behind). The OAuth path needs your browser once and has not been run end to end. Receipt.

Auth: X-API-Key header, or OAuth.

Config ($HOME/.cursor/mcp.json, or .cursor/mcp.json in a project):

{
  "mcpServers": {
    "sandbox": {
      "url": "https://api.sbx.agent-next.com/mcp/v1",
      "headers": { "X-API-Key": "<your key>" }
    }
  }
}

Config (OAuth instead):

{
  "mcpServers": {
    "sandbox": { "url": "https://mcp.agent-next.com/mcp" }
  }
}

Then run cursor-agent mcp login sandbox and finish the sign-in in the browser.

Cursor does not load a new server until you approve it: the verify command does that first. For a non-interactive run add --trust --approve-mcps, for example cursor-agent --print --trust --force --approve-mcps "<prompt>". cursor-agent needs your Cursor sign-in and is not in the sandbox template.

Verify:

cursor-agent mcp enable sandbox && cursor-agent mcp list-tools sandbox

Gemini CLI

Verified working X-API-Key header path: run end to end on 2026-10-12 as a new user in a fresh sandbox (create, exec, files, preview, kill, nothing left behind). The OAuth path needs a browser and has not been run end to end. Receipt.

Auth: X-API-Key header, or OAuth (needs a browser on the same machine).

Config (writes $HOME/.gemini/settings.json):

gemini mcp add --transport http --scope user --header "X-API-Key: <your key>" sandbox https://api.sbx.agent-next.com/mcp/v1

Config (OAuth instead):

gemini mcp add --transport http --scope user sandbox https://mcp.agent-next.com/mcp
# then, inside gemini: /mcp auth sandbox

Verify:

gemini mcp list

Gemini CLI turns MCP servers off in a folder you have not trusted: the list then shows the server as Disabled. Trust the folder in the interactive app, or set GEMINI_CLI_TRUST_WORKSPACE=true for a headless run. To remove the server run gemini mcp remove --scope user sandbox: without --scope user it looks in the project settings and leaves the key in $HOME/.gemini/settings.json.

OpenCode

Verified working X-API-Key header path: run end to end on 2026-10-12 as a new user in a fresh sandbox (create, exec, files, preview, kill, nothing left behind). The OAuth path needs your browser once and has not been run end to end. Receipt.

Auth: X-API-Key header (key from the environment), or OAuth.

Environment:

export SBX_API_KEY=<your key>

Config (opencode.json in the project or ~/.config/opencode/opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "sandbox": {
      "type": "remote",
      "url": "https://api.sbx.agent-next.com/mcp/v1",
      "oauth": false,
      "headers": { "X-API-Key": "{env:SBX_API_KEY}" }
    }
  }
}

Config (OAuth instead):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "sandbox": { "type": "remote", "url": "https://mcp.agent-next.com/mcp" }
  }
}

Then run opencode mcp auth sandbox and finish the sign-in in the browser.

Verify:

opencode mcp list

If the list shows failed: SSE error: Non-200 status code (405), SBX_API_KEY is not set in that shell (the server answered 401 because no key was sent). The config holds only the variable name, never the key.

droid

Verified working X-API-Key header path: run end to end on 2026-10-12 as a new user in a fresh sandbox (create, exec, files, preview, kill, nothing left behind). The OAuth path needs your browser once and has not been run end to end. Receipt.

Auth: X-API-Key header, or OAuth.

Config:

droid mcp add sandbox https://api.sbx.agent-next.com/mcp/v1 --type http \
  --header "X-API-Key: <your key>" --no-oauth

Config (OAuth instead):

droid mcp add sandbox https://mcp.agent-next.com/mcp --type http
droid mcp auth

Verify:

droid mcp list

The key is stored in $HOME/.factory/mcp.json until you run droid mcp remove sandbox.

devin

Verified working X-API-Key header path: run end to end on 2026-10-12 as a new user in a fresh sandbox (create, exec, files, preview, kill, nothing left behind). The OAuth path needs your browser once and has not been run end to end. Receipt.

Auth: X-API-Key header, or OAuth.

Config (writes $HOME/.config/devin/mcp_config.json):

devin mcp add --transport http --scope user \
  --header "X-API-Key: <your key>" sandbox https://api.sbx.agent-next.com/mcp/v1

The command saves the config, then prints an OAuth sign-in URL and waits. You do not need it for the header path: stop the command with Ctrl-C (in a script, wrap it in timeout 10). The entry is already saved.

Config (OAuth instead):

devin mcp add --transport http --scope user sandbox https://mcp.agent-next.com/mcp
devin mcp login sandbox

Verify:

devin mcp list

For a headless run, devin -p refuses an untrusted folder unless you pass --respect-workspace-trust false, and needs --permission-mode dangerous to call tools unattended. To remove the server run devin mcp remove --scope user sandbox.

Claude web and desktop

Being verified Needs a signed-in account in the app, so it has not been run end to end yet.

Auth: OAuth sign-in, or a custom connector with an X-API-Key header.

Config (Customize > Connectors > Add custom connector, header path):

Name:        agent-next sandbox
URL:         https://api.sbx.agent-next.com/mcp/v1
Auth:        No sign-in
Header:      x-api-key: <your key>

Config (OAuth instead):

Name:        agent-next sandbox
URL:         https://mcp.agent-next.com/mcp
Auth:        Sign in now

For the header path pick No sign-in, not the pre-selected "Sign in now": the header cannot be added to an OAuth connector afterwards. Use one connector or the other, not both. Request headers are a beta that is only available to some organizations: if the connector form has no "Request headers" field, use the OAuth setup, because "No sign-in" alone sends no key.

Verify:

curl -s https://api.sbx.agent-next.com/mcp/v1 \
  -H "X-API-Key: <your key>" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
  | python3 -c "import json,sys;print([t['name'] for t in json.load(sys.stdin)['result']['tools']])"

ChatGPT developer mode

Being verified Needs a signed-in account in the app, so it has not been run end to end yet. Developer mode depends on your ChatGPT plan.

Auth: OAuth only. ChatGPT custom connectors take OAuth or no authentication, not a custom header, so there is no key path here.

Config (Settings > Apps > Advanced settings > Developer mode on, then Create):

Name:   agent-next sandbox
URL:    https://mcp.agent-next.com/mcp
Auth:   OAuth

On the sign-in page, paste your API key (or sign in another way the page offers). The token resolves to the same account as the key. The verify command fetches the OAuth metadata ChatGPT reads; it needs no key.

Verify:

curl -s https://mcp.agent-next.com/.well-known/oauth-protected-resource

Personal agents template

Verified working Run end to end on 2026-10-12 as a new user: create, install OpenClaw, gateway, public URL, pause and resume, kill, nothing left behind. No model key was used. Receipt.

Auth: Your API key through the E2B SDK (E2B_API_KEY). No MCP connection: the agent runs inside the sandbox.

Config (creates the sandbox; steps 2 to 4 of the personal agents page install and start OpenClaw):

export E2B_DOMAIN=sbx.agent-next.com
export E2B_API_KEY=<your key>
python3 - <<'PY'
from e2b import Sandbox
sbx = Sandbox.create(template="agent-full", timeout=3600,
                     lifecycle={"on_timeout": "pause", "auto_resume": True})
print(sbx.sandbox_id)
PY

Replace <sandboxId> below with the id the script printed. The gateway token comes from step 3 of that page. The sandbox user is user, not root, so keep the token file and log under $HOME.

Verify:

curl -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -i https://18789-<sandboxId>.sbx.agent-next.com/health   # HTTP 2xx (200 on OpenClaw 2026.10.2)

OpenClaw-style MCP and CLI agents

Verified working X-API-Key header path: run end to end on 2026-10-12 as a new user in a fresh sandbox (create, exec, files, preview, kill, nothing left behind). The OAuth and CLI paths have not been run end to end. Receipt.

Auth: X-API-Key header or OAuth over MCP, or the CLI path (sbx, section 3) for agents that have a shell.

Config (X-API-Key header):

openclaw mcp set sandbox '{"url":"https://api.sbx.agent-next.com/mcp/v1","transport":"streamable-http",
  "headers":{"X-API-Key":"<your key>"}}'

Config (OAuth instead):

openclaw mcp set sandbox '{"url":"https://mcp.agent-next.com/mcp","transport":"streamable-http",
  "auth":"oauth"}'
openclaw mcp login sandbox

OpenClaw writes these commands to its own config and needs its local gateway stopped while you run them; openclaw mcp doctor warns about a literal key in headers. openclaw mcp unset sandbox removes the server, but OpenClaw keeps copies of its config as $HOME/.openclaw/openclaw.json.bak* that hold the key: delete them. Other agents that speak MCP or run shell commands can use the same URL and header, or the sbx CLI.

Verify:

openclaw mcp probe sandbox

Ownership and cleanup

Whoever creates a sandbox owns it and is responsible for it after use. A leftover nobody can attribute is a leftover nobody can safely clean, so stamp ownership at create and clean up on finish.

Create with ownership metadata and a timeout. Create accepts the E2B-compatible metadata object: the gateway stores it, echoes it on every list and get, and filters lists by it. Set timeout (seconds) to the task's real length plus margin, so a crashed client cannot leave the sandbox behind:

sbx = Sandbox.create(template="agent-full", timeout=3300,
                     metadata={"owner_lane": "ci@builder-1", "task_id": "docs-20261014",
                               "expires_at": "2026-10-14T18:15:00Z"})
# ... work ...
sbx.kill()   # kill on finish: the creator cleans up its own sandbox

List what you own. The list takes a metadata filter of url-encoded k=v pairs, matched against the stored create metadata:

curl -s "https://api.sbx.agent-next.com/sandboxes?metadata=owner_lane%3Dci%40builder-1" \
  -H "X-API-Key: $SBX_API_KEY"

A sandbox you must keep after its run (a failed push, work not yet recovered) gets a tag, not silence: PUT /sandboxes/<sandboxId>/metadata merges {"kept_reason": "...", "kept_until": "..."} into the stored metadata — gateway-local, works on a paused sandbox, never replaces the create copy. Fleets should automate this cleanup: list your key's sandboxes, kill only the ones your lane created whose task finished or whose expires_at passed, leave sandboxes without metadata alone (report them to their owner), and never kill a kept sandbox until its work is recovered (a verified bundle of committed, dirty and untracked files) or pushed.

Limits an agent should plan around

ItemWhat to expect
Concurrent sandboxesPer key. Free and trial keys run 2 to 3 at once. Your key's real limit is limits.max_concurrent in GET /v0/account. A create over it is refused with limit N reached and a retry in Ns hint; list with sandboxes_list and kill finished sandboxes first.
timeout_minA keep-alive (CPU templates). After that many idle minutes (default 5, max 1440; never shorter than the gateway's idle floor, 5 minutes by default) the sandbox auto-pauses and keeps its files; the next exec or files call resumes it, and activity restarts the idle clock. A GPU sandbox idle-pauses on its own timer instead (accel.idle_timeout_s, 600 s by default for a transparent template; the next exec thaws it), so timeout_min is not applied (the create replies timeout_min_applied false) and the lease stays until sandbox_kill or its lease end_at.
Memory and diskThe default template has 2 vCPU, about 3.8 GiB RAM, no swap and about 50 GiB disk. There is no memory cgroup: a process past roughly 3.5 GiB is OOM-killed (exit 137) and its unflushed output is lost.
Size classesTemplate-level, not a sandbox_create argument: small 2 vCPU / 8 GiB, standard 4 / 16, large 8 / 32, xlarge 16 / 64 (both off by default).
GPU memoryGPU sandboxes are a separate lease with a hard VRAM slice from 0.5 GiB up to the card's live admission ceiling (vram_gb; over REST accel.vram_gb — the API accepts up to 32 GiB, and nothing above the card's max_admit_gib is seated, so larger slices are refused until a bigger card joins the fleet). They are created through the MCP tools too (template gpu, gpu-lease-v06, mujoco, browser or any other name in REST GET /gpu/templates, optional vram_gb) and driven with sandbox_exec and sandbox_kill only. CUDA allocations past the slice fail with an out-of-memory error; graphics memory past it kills the job. A browser WebGPU template is operator-registered only, not live by default: discover with REST GET /gpu/templates, then use REST POST /sandboxes with {"accel":{"template":"browser","vram_gb":2,"reserve":"exec"}} and send examples/gpu/browser_webgpu_smoke.py as Python code to the lease exec endpoint. The operator-only GATEWAY_GPU_TEMPLATES.browser.worker_reserve="cuda" selects a torch-free reserve backend and requires the hard cap plus a host NVML watchdog; Vulkan allocations may bypass CUDA hooks. The GPU sandboxes guide has the lifecycle, billing and error reference.
Preview URLsPublic by default: anyone with https://<port>-<sandbox-id>.sbx.agent-next.com can reach the port, with no sign-in. To restrict it, create the sandbox over REST with network.allowPublicTraffic=false or register the port public:false.
Background processesRedirect their output (nohup server > log 2>&1 &). Read the log with the files tools. If the main command exits while a child still holds the output pipe, sandbox_exec waits about 2 seconds for the pipe to drain, then returns without the child.
Exit codessandbox_exec returns exited and the exit code (0 included) when the command ends within wait_s (default and max 45). A command that outlives its timeout_s is killed and returns timeout with exit_code 124 and timed_out true. A running result has exit_code null: poll sandbox_exec_output with the same job_id while the status is running.
NetworkOutbound SMTP (25, 465, 587) is blocked. IPv4 only.

Next: quickstart · GPU sandboxes · limits and network policy · templates · coding agents in the sandbox