An MCP-capable agent can call the sandbox's built-in tools directly for file, command, code, and browser work.
Connect an MCP client to POST /mcp. Each tool still needs the plane it drives.
Read the available capabilities from capabilities in GET /v2/sandbox.
Read the available capabilities from GET /v1/capabilities.
With AIO_API_KEY set, send the key as Authorization: Bearer <key>; the endpoint is not public and answers 401 without it.
Use tools/list to get the current tool list.
The built-in set is compiled into the binary, in that order:
| Tool | What it does |
|---|---|
sandbox_execute_bash | Runs a shell command in a managed session |
sandbox_execute_code | Runs Python or JavaScript |
sandbox_file_operations | read, write, replace, search, find, list, grep, glob |
sandbox_str_replace_editor | view, create, str_replace, insert, undo_edit |
sandbox_get_context | Sandbox version and home directory |
sandbox_get_packages | Installed Python or Node packages |
sandbox_load_skill | Loads one skill, or lists them all |
browser_get_info | CDP url, viewport size, and the rest |
browser_gui_screenshot | Screenshot of the whole display |
browser_gui_execute_action | One GUI action on the display |
Anything beyond these came from a registered MCP server, so read the list rather than a count. Each entry carries its own JSON Schema:
The four JSON requests below write the numbers, count the lines, sum them in Python, and read the result back.
All four steps share one filesystem, so the command and code can read the file written in step 1.
Every result has a content list; a failed call sets isError to true. The text inside is what the model reads — the file tool's JSON, the command's output, or the interpreter's stdout. In full, step 1:
sandbox_execute_bash runs in one shared session unless new_session is set, and its result reports the cwd the session ended in. Pass that back on the next call and the agent's idea of the working directory stays in step with the shell's.
There are two failure shapes, depending on whether the tool ran. The requests below show an unknown tool and a missing file:
An unknown tool name, a missing tool name, or an unknown method is a JSON-RPC error. It still arrives on HTTP 200; the error object is what an MCP client parses:
A tool that ran and failed comes back as an ordinary result with isError: true. The text carries the reason, and the file plane passes its structured error straight through:
A missing argument is this second kind, not the first: sandbox_execute_bash without cmd answers isError: true and the text cmd is required. So do browser_gui_screenshot and browser_gui_execute_action with no computer-use worker, browser_get_info with no reachable CDP port, and any call to a registered MCP server that is down.
EXTRA_MCP_SERVERS (or --mcp-servers) registers other MCP servers as {"name": {"url": ..., "prefix": ...}}. Their tools join the same catalogue, and a call to one is forwarded and its answer passed back unedited. Any stateless MCP server on loopback will do, so a second daemon is the cheapest way to see it work:
The rules behind that run:
http:// on 127.0.0.1, localhost or [::1] is accepted. Remote and command (stdio) entries are skipped with a warning at startup.tools/list.prefix, tools are published as <prefix>_<tool> and the prefix comes off again on the way out. Without one, the server's own names must already start with <name>_; the rest are dropped, because nothing would say where to route them.On the AIO image mcp-server-browser is registered exactly this way, which is where the page-level browser_* navigation tools in that image's list come from.
Any client that supports streamable-HTTP MCP can connect to http://127.0.0.1:18091/mcp, or to the gateway's /mcp on the prebuilt images. With a key set, send it as a bearer header.
isError, and the status codes