Everything else the agent can do — shell, reading and writing files, starting
services, publishing a preview, committing to a repository — is always present
and is not configured here. You are choosing what it can reach outside the
workspace, not what it can do inside one.
All three are set with one call, which replaces the whole configuration:
Built-in tools
The sandbox already has these. Naming one is the whole request — they take no other field:
Naming any of them narrows the session to exactly those. Say nothing and the
session gets whatever this deployment allows, which is what every session got
before you could choose. Say
"tools": [] and it gets none of them — no way
out to the network at all, which is the shape for running code you have not
read.
You can only narrow. A tool the deployment has turned off does not come back
by being named in a request body. If it did, the operator switch would be
decoration, and the one thing it exists for — running untrusted work with no
route to the internet — is exactly what it could no longer guarantee.
So the list you get is the intersection, and reading the configuration back
tells you what you actually have rather than what you asked for.
Function tools
You declare the shape; the agent calls it; the turn stops until you answer.run-session.ts.
A turn waiting on you is still in flight. The workspace is not reclaimed
out from under it, however long you take. There is no deadline on the answer
unless you set one — timeout_seconds on the tool, see
required-actions.md — and the only ceiling either way is
the workspace’s two hours, in limits.md.
MCP servers
Exactly one ofurl or command:
url— a server already running, which the sandbox connects out to.command— a process started inside the sandbox, spoken to over stdio.
The connection is made from the sandbox, not from us. Your tool traffic does
not pass through our control plane — which is what lets an MCP server on your
private network be reachable at all, and keeps our egress out of your blast
radius. A server reachable only from your VPC works if the sandbox is in it;
one behind your office firewall does not.
When a server cannot be reached
By default it is skipped, and the agent simply has fewer tools. Nothing fails. The agent will usually say it cannot do the thing you asked — which looks like the model being unhelpful, when the real cause is a server that never answered. That default is deliberate: one optional server being down should not destroy a session that could still do most of its work. But it is only right when the server really is optional. You will be told, though. A skipped server produces anmcp_unavailable
item in the session’s transcript and an mcp.unavailable event on the stream:
required: true the session fails loudly instead of running crippled, and
you get an error rather than a confused answer. It arrives on the first call
that needs the workspace — sending a message, writing a file — and it names the
server and what went wrong:
invalid_request rather than a retryable code, deliberately: waiting will not
make the server reachable. This is a configuration to change, not a state to
wait out.
Choose deliberately.required: falseand a broken URL is the one combination that produces no signal anywhere a caller can see it. If you are not sure,required: trueis the safer default for anything the task actually depends on.
required must be true or false. A string — "required": "yes" — is
refused rather than read as false, because false is a real choice here and
not one you would have made by writing the word required.
Reading the configuration back
tools array, each entry
carrying its type. The same shape goes back to PUT.
Secrets are not returned. authorization and every header value are held
back, and redacted names what was withheld — so a server with credentials
configured is distinguishable from one without, which an omission alone would
not tell you.
redacted is not a request field. If you read the configuration, change
something and PUT it back, you get a 400 naming redacted rather than a
success that quietly replaced your credentials with nothing. Re-send the
secrets, or build the body from your own source.
Refusals
Every refusal carries
{ error: { code, message, request_id } } — see
errors.md.
Next
- required actions — answer a call the agent makes
- extracting structured data — shape what comes back