MCP server¶
rayito.mcp (Python) and the rayito-mcp executable of the npm package
(TypeScript) are a Model Context Protocol
server with the same six tools, the same environment variables and the same
behavior (the tools' contract is in testdata/mcp/tools.json, and both test
suites check it). It gives any MCP host (Claude Code, Claude Desktop, Cursor, VS
Code, the Inspector) a Rayito sandbox with one start command and one
environment variable. Each server process owns one sandbox: it is
created on the first tool that needs it, AWS suspends it when
RAYITO_MCP_IDLE_SECONDS pass without traffic (the next call resumes it
on its own) and it is destroyed (terminate-microvm) when the host closes
the server. The cost is that of a running MicroVM while it is in use and
that of a snapshot per suspension cycle (cost model); nothing
stays alive beyond RAYITO_MCP_TIMEOUT_SECONDS.
For frameworks that talk to their own tools and not to MCP (LangChain, Vercel AI SDK) there are two fifty-line adapters: LangChain and Vercel AI.
This page is the reverse case of
Agent in the sandbox: here the agent lives
outside (your MCP host) and uses the sandbox as a tool. To give MCP servers
to an agent that runs inside the sandbox (sbx.agent), use
AgentSpec(mcp={"name": McpLocal(...) | McpRemote(...)})
(Subagents, MCP servers and permissions).
Installation¶
pip install "rayito[mcp]" # or: uv add "rayito[mcp]"
python -m rayito.mcp --help # equivalent to the rayito-mcp script
The extra installs the official mcp 2.x SDK (pip install "rayito[mcp]",
the package is on PyPI). From a repository checkout:
Without the extra, rayito-mcp and python -m rayito.mcp print a
one-line notice with the install command and exit with 2 (no traceback),
just like the rayito CLI without rayito[cli]; import rayito does not
change. Accessing a rayito.mcp name directly (McpSettings,
build_server, …) without the extra fails with a ModuleNotFoundError
that gives the same command.
The rayito-mcp executable ships in the rayito package. The official MCP
SDK (@modelcontextprotocol/server) and zod are optional peers: they
are not installed with rayito, just like Python's mcp extra. Without
installing anything:
Or in a project:
If either peer is missing, rayito-mcp prints the exact npx command above
and exits with 2, with no traceback; import "rayito" does not change.
Environment variables¶
All configuration goes through the environment (MCP hosts configure servers
with an env block); no command-line flag duplicates it.
| Variable | Meaning | Default / validation |
|---|---|---|
RAYITO_TEMPLATE |
Image name or ARN (the same variable Sandbox.create reads) |
Required for the tools that touch the sandbox; not validated at startup, the first call that needs it returns an error that names it |
RAYITO_TEMPLATE_VERSION |
Image version | Latest ACTIVE |
RAYITO_EXECUTION_ROLE_ARN |
The MicroVM's execution role; with a role, logging="cloudwatch" |
Without a role → logging="disabled" |
AWS_REGION / AWS_PROFILE and the credential variables |
The SDK's region and credentials (AWS_REGION; if missing, AWS_DEFAULT_REGION or the profile); the server passes no region or session of its own |
boto3 defaults |
RAYITO_MCP_TIMEOUT_SECONDS |
Maximum lifetime of the sandbox (running + suspended) | 3600; integer in 60..=28800, otherwise the server exits with code 2 |
RAYITO_MCP_IDLE_SECONDS |
Seconds without traffic before AWS suspends the sandbox; 0 turns auto-suspend off |
300; 0 or an integer >= 60 and less than RAYITO_MCP_TIMEOUT_SECONDS (with a timeout below 300 s you have to lower the idle or set it to 0), otherwise the server exits with code 2 |
RAYITO_MCP_LOG_LEVEL |
Log level (always on stderr) | INFO; one of DEBUG INFO WARNING ERROR CRITICAL |
Tools¶
Tool and argument names are in English and stable; descriptions are in
Spanish. Text outputs are cut at 100,000 characters with the suffix
… [truncado: <n> caracteres más] (that is, "truncated: n more
characters") and truncated: true.
| Tool | Arguments | Returns |
|---|---|---|
run_code |
code: str (Python), timeout: int = 300 (1-3600 s) |
Content blocks: a JSON text (below), then one image per png/jpeg and one embedded resource per svg |
run_command |
cmd: str (/bin/sh -c as the sandbox user), timeout: int = 60, cwd: str \| None |
{stdout, stderr, exit_code, truncated}; a non-zero exit code is data, not an error |
read_file |
path: str |
{path, content, size, truncated} (UTF-8 text) |
write_file |
path: str, content: str |
{path, size}; overwrites |
list_files |
path: str = "/home/user", depth: int = 1 (1-5) |
{path, entries: [{name, path, type, size, modified_time}]} |
list_sandboxes |
— | {sandboxes: [{sandbox_id, state, template, template_version, started_at, current}]}; never creates a sandbox |
The first block of run_code is always a JSON with this shape:
{
"text": "42",
"stdout": "hello\n",
"stderr": "",
"error": null,
"execution_count": 3,
"results": [{"index": 0, "mime_types": ["text/plain"]}],
"truncated": false
}
text is the text/plain of the main result (null if there is none);
error is {"name", "value", "traceback"} when the cell raised an
exception (or ExecutionTimeout when the agent interrupted it) and arrives
with is_error: false: the cell ran and the model needs the traceback.
results lists the mime types of each result even when they are not
attached (text/html, e2b/chart...); only PNG, JPEG and SVG travel as
blocks.
Failures the model can fix arrive as a tool error (is_error: true) with a
message in Spanish: RAYITO_TEMPLATE undefined, a failed create (no se
pudo crear el sandbox: ...; the next call retries), a run_command
timeout, a file that does not exist, a sandbox in the middle of suspending
or resuming (está en transición ...; reintenta en unos segundos: the
sandbox is still the same one) and a sandbox that expired (ya no existe
...; la siguiente llamada crea uno nuevo).
Claude Code¶
Claude Desktop¶
claude_desktop_config.json (~/Library/Application Support/Claude/ on
macOS, %APPDATA%\Claude\ on Windows):
Claude Desktop only rereads the file at startup: quit it completely (not just the window) and open it again. The sandbox is destroyed when Claude Desktop closes the server.
Cursor and VS Code¶
Cursor, .cursor/mcp.json:
VS Code, .vscode/mcp.json:
HTTP mode¶
It serves streamable HTTP for hosts and tools that only speak HTTP (the Inspector in URL mode, Cursor's or Claude Code's remote entries):
No authentication
HTTP mode authenticates no one. Listening on loopback does not
prevent a browser from reaching the server: a web page can resolve its
own domain to 127.0.0.x and talk to it (DNS rebinding), so the server
always requires Host and Origin to be exactly the host:port it
started with: connect with the same spelling you passed in --host
(127.0.0.1:8000, not localhost:8000). All clients that reach the
process share the same sandbox. That is why --host has to be the
specific address clients arrive at: a wildcard (0.0.0.0, ::) binds
all interfaces but is not what anyone types in Host, so it is rejected
with a usage error (exit 2). With a --host that is not loopback (a
specific IP on your network) the server warns (sin autenticación:
cualquier cliente que alcance <host>:<port> controla el sandbox, that
is, "no authentication: any client that reaches
Inspector¶
The six tools appear in the Tools tab; run_command with echo hello
creates the sandbox (the first call takes as long as the MicroVM startup
takes) and run_code with
import matplotlib.pyplot as plt; plt.plot([1, 2, 3]); plt.show() returns
the JSON and the rendered PNG. When you close the Inspector the sandbox is
destroyed. In URL mode, start python -m rayito.mcp --http (or rayito-mcp --http) and connect the
Inspector to http://127.0.0.1:8000/mcp.
Costs and limits¶
- One sandbox per process. Over stdio each host connection is a process, so "one sandbox per session" holds exactly; over HTTP all the clients of a process share the sandbox.
- Default
timeout3600 s. If the host kills the process without closing it (SIGKILL, forced close), the shutdown'sterminate-microvmdoes not run and the MicroVM keeps billing untilRAYITO_MCP_TIMEOUT_SECONDS. To find and kill it:list_sandboxesfrom any server with the same image,Sandbox.kill(sandbox_id)(Sandbox.kill(sandboxId)in TypeScript), oraws lambda-microvms terminate-microvm --microvm-identifier <id>. - Outputs truncated at 100,000 characters (
stdout,stderr,content,text), withtruncated: true; images travel as the sidecar delivered them (which discards values over 8 MiB). - Suspension mid-cell. Inactivity counts bytes that cross the endpoint:
a cell that prints nothing for
RAYITO_MCP_IDLE_SECONDScan be suspended in the middle of running; the SDK waits for the resume and reattaches, but if your cells are long and silent raise the value or turn it off withRAYITO_MCP_IDLE_SECONDS=0. - No authentication on HTTP, no per-client sandboxes, no pools or persistence: each process starts empty and ends by destroying its sandbox.
See also¶
- Agent in the sandbox: the agent loop running inside the sandbox, instead of on your MCP host
- LangChain and Vercel AI