Tools

agent_toolset_20260401 is the hosted toolset. An agent that carries it gets a persistent bash shell and a filesystem, inside its session's own container, and can search and fetch the web. An agent without it can only write messages. A tool set to enabled: false is never offered to the model.

ToolWhat it does
bashRuns a shell command in the sandbox.
readReads a file.
writeWrites a file, creating the parent directories.
editReplaces a string in a file.
globFinds files by pattern.
grepSearches file contents.
web_searchSearches the web and returns results with excerpts.
web_fetchFetches a URL and returns its text, or the PDF it serves.

The shell

The bash session persists across calls and across turns. The working directory, the exported variables and the background processes survive to the next command. A command times out after five minutes. Run long work in the background and poll it.

The tool writes output over 100,000 characters to a file in the sandbox and gives the model a preview naming it. Reading the rest is another tool call, not a download.

The shell is lost when the container stops after a quiet session. The filesystem is not.

The web

Each web tool takes its own config beside its name. A page comes back as a document block and a search as search_result blocks, as the Managed Agents API returns them.

FieldWhat it does
allowed_domainsBoth tools. Only these domains and their subdomains; web_search also takes a path, as example.com/docs. Up to 64.
blocked_domainsBoth tools. Never these. One of the two lists, not both.
max_content_tokensweb_fetch. Cuts the page's text to about this many tokens.
user_locationweb_search. Its country biases the results.

web_fetch honours robots.txt, never dials a private address, and checks every redirect hop against the same rules. A refusal is a tool result the model reads, not a failed turn.

Permission policies

The toolset entry carries a default in default_config and an entry per tool in configs, each with enabled and a policy. A tool under always_ask does not run until you answer.

JSON
{
  "type": "agent_toolset_20260401",
  "default_config": { "permission_policy": { "type": "always_allow" } },
  "configs": [
    {
      "name": "bash",
      "permission_policy": { "type": "always_ask" }
    }
  ]
}
PolicyEffect
always_allowThe tool runs. This is the default.
always_askThe turn stops and waits for your answer before the call runs.

Answering a tool

When a tool asks, the turn ends with session.status_idle and a stop reason of requires_action, which names the agent.tool_use event ids that are waiting. Answer each one with a user.tool_confirmation.

await client.beta.sessions.events.send(session.id, {
  events: [
    {
      type: "user.tool_confirmation",
      tool_use_id: "sevt_...",
      result: "deny",
      deny_message: "Do not touch the release branch.",
    },
  ],
});

A denial carries an optional message, which the agent reads as the tool's result. Every agent.tool_use event also carries evaluated_permission, what the policy decided, and evaluation, the policy that decided it. A call under auto runs: coreloop makes no call of its own on it.

MCP servers

An agent's mcp_servers are connected the first time a turn needs its tools, and their tools are offered beside the sandbox's. An mcp_toolset defaults to always_ask, so a call waits for a user.tool_confirmation unless the toolset or the tool allows it. A call is an agent.mcp_tool_use, named by the server's own tool name and mcp_server_name; its result is an agent.mcp_tool_result that names it by mcp_tool_use_id. In mcp_server_name, every character but letters, digits, _ and - reads as _: mcp.deepwiki.com is mcp_deepwiki_com.

A server that cannot be reached is reported as a session.error of type mcp_connection_failed_error or mcp_authentication_failed_error, and the turn runs without its tools. It is tried again on the next turn.

A server that needs a token finds it in a vault the session names in vault_ids: the credential whose mcp_server_url is the server's URL, sent as a bearer. The first vault in vault_ids that holds the URL wins. A refused mcp_oauth token is refreshed once and the connect tried again.

Custom tools

A tools entry of type custom is a tool your client runs. It carries a name, a description and an input_schema. A call is an agent.custom_tool_use with the name and the input, and the turn ends with session.status_idle and a stop reason of requires_action that names it. The session waits until you send the result as a user.custom_tool_result.

await client.beta.sessions.events.send(session.id, {
  events: [
    {
      type: "user.custom_tool_result",
      custom_tool_use_id: "sevt_...",
      content: [{ type: "text", text: "status: shipped" }],
    },
  ],
});

The result takes text, image, document and search_result blocks, read as a message's images and documents are. A custom tool cannot share a name with another tool of the agent.

A model message can call a custom tool and a sandbox tool together. The sandbox tool runs once every custom call of the message has its result.

Not yet

The Managed Agents API also takes web_fetch's url_sources. coreloop refuses a url_sources value.

Soon: url_sources.