Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MCP

ZeroClaw is an MCP client: it connects to external Model Context Protocol servers and exposes their tools to the agent. Each MCP tool is namespaced as <server>__<tool> (for example filesystem__read_file), so tools from different servers never collide.

Configure MCP

MCP support is enabled by default, but no external MCP tools are exposed until at least one server is configured under mcp.servers. Configure through the gateway, zerocode, or zeroclaw config set:

zeroclaw config set mcp.servers.filesystem.command npx

Set mcp.enabled = false to disable MCP tool loading without removing server definitions.

Transports

A server is reached over one of three transports (the transport field):

TransportWhen to useRequired fields
stdio (default)A local process you spawn (a Node.js or Python MCP server)command, optional args, env
httpA remote server speaking MCP over HTTP POSTurl, optional headers
sseA remote server speaking MCP over HTTP + Server-Sent Eventsurl, optional headers

env (stdio) and headers (http/sse) are stored as secrets; headers commonly carries the Authorization: Bearer … token for the upstream server.

Add a server through the gateway, zerocode, or zeroclaw config set (for example zeroclaw config set mcp.servers.filesystem.command npx). A stdio server needs command plus optional args/env; an http/sse server needs url plus optional headers. The per-field commands are in the field table below.

Editing servers

Three surfaces edit the same [[mcp.servers]] table:

  • config.toml: hand-edit the keys documented below. The full table is round-tripped on save.
  • zerocode TUI (/config -> mcp.servers): first-class per-field editor. The section shows one row per server, labeled with the server’s name; enter a row to edit transport, command / url, headers, env, and tool_timeout_secs as individual fields. + Add creates a new entry seeded with the name you supply; deleting from the alias list removes the entry. The name field is not edited inline because renaming the natural key mid-edit would invalidate in-flight references; use the dashboard or hand-edit config.toml to rename for now.
  • Web dashboard: currently renders mcp.servers through a JSON-array editor. A migration to the same per-field surface the TUI uses is planned; until then the dashboard remains a usable but coarser editor.

Server fields

Per-server fields ([[mcp.servers]]), generated from the schema:

args string[] · default []

Command arguments for stdio transport.

Set it on any surface:

Gateway dashboard

Open /config/mcp.servers and set the mcp.servers.args field.

zerocode

In the Config pane, set the mcp.servers.args field.

zeroclaw config

zeroclaw config set mcp.servers.args <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_mcp__servers__args=
command string · default ""

Executable to spawn for stdio transport.

Set it on any surface:

Gateway dashboard

Open /config/mcp.servers and set the mcp.servers.command field.

zerocode

In the Config pane, set the mcp.servers.command field.

zeroclaw config

zeroclaw config set mcp.servers.command <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_mcp__servers__command=
env 🔑 secret · default {}

Optional environment variables for stdio transport.

Set it on any surface:

Gateway dashboard

Open /config/mcp.servers and set the mcp.servers.env field.

zerocode

In the Config pane, set the mcp.servers.env field.

zeroclaw config

zeroclaw config set mcp.servers.env    # masked input, stored encrypted

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_mcp__servers__env=
headers 🔑 secret · default {}

Optional HTTP headers for HTTP/SSE transports. Treated as secret: the values commonly carry Bearer tokens for the upstream MCP server.

Set it on any surface:

Gateway dashboard

Open /config/mcp.servers and set the mcp.servers.headers field.

zerocode

In the Config pane, set the mcp.servers.headers field.

zeroclaw config

zeroclaw config set mcp.servers.headers    # masked input, stored encrypted

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_mcp__servers__headers=
name string · default ""

Display name used as a tool prefix (<server>__<tool>). Filled in from the supplied map_key when the entry is created via create_map_key("mcp.servers", "<name>"); #[serde(default)] lets the macro default-construct from {} before the name gets injected.

Set it on any surface:

Gateway dashboard

Open /config/mcp.servers and set the mcp.servers.name field.

zerocode

In the Config pane, set the mcp.servers.name field.

zeroclaw config

zeroclaw config set mcp.servers.name <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_mcp__servers__name=
tool_timeout_secs integer? · default null

Optional per-call timeout in seconds (hard capped in validation).

Set it on any surface:

Gateway dashboard

Open /config/mcp.servers and set the mcp.servers.tool_timeout_secs field.

zerocode

In the Config pane, set the mcp.servers.tool_timeout_secs field.

zeroclaw config

zeroclaw config set mcp.servers.tool_timeout_secs <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_mcp__servers__tool_timeout_secs=
transport McpTransport · default "stdio"

Transport type (default: stdio).

Set it on any surface:

Gateway dashboard

Open /config/mcp.servers and set the mcp.servers.transport field.

zerocode

In the Config pane, set the mcp.servers.transport field.

zeroclaw config

zeroclaw config set mcp.servers.transport <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_mcp__servers__transport=
url string? · default null

URL for HTTP/SSE transports.

Set it on any surface:

Gateway dashboard

Open /config/mcp.servers and set the mcp.servers.url field.

zerocode

In the Config pane, set the mcp.servers.url field.

zeroclaw config

zeroclaw config set mcp.servers.url <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_mcp__servers__url=

tool_timeout_secs is an optional per-call timeout; it must be greater than 0 and is capped at 600 seconds.

Top-level fields

deferred_loading bool · default false

Load MCP tool schemas on-demand via tool_search instead of eagerly including them in the LLM context window. When enabled, only tool names are listed in the system prompt; the LLM must call tool_search to fetch full schemas before invoking a deferred tool.

Set it on any surface:

Gateway dashboard

Open /config/mcp and set the mcp.deferred_loading field.

zerocode

In the Config pane, set the mcp.deferred_loading field.

zeroclaw config

zeroclaw config set mcp.deferred_loading <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_mcp__deferred_loading=
servers McpServerConfig[] · default []

Configured MCP servers. The #[nested] annotation makes the macro expose this as a List section in map_key_sections(), so the dashboard’s + Add MCP server affordance and the POST /api/config/map-key?path=mcp.servers&key=<name> endpoint pick it up automatically (no hand-table on the gateway side). #[natural_key = "name"] opts the Vec into per-element property routing (see route_vec_path and the Configurable derive’s #[natural_key] arm). With it, set_prop("mcp.servers.<name>.url", ...) and get_prop("mcp.servers.<name>.transport") resolve to the matching element’s own set_prop / get_prop, and the mcp.servers section behaves like a HashMap<String, McpServerConfig> from the dashboard / TUI’s point of view. name itself becomes read-only via set_prop; rename goes through rename_map_key which mutates the name field in place.

Set it on any surface:

Gateway dashboard

Open /config/mcp and set the mcp.servers field.

zerocode

In the Config pane, set the mcp.servers field.

zeroclaw config

zeroclaw config set mcp.servers <value>

Environment variable

Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:

export ZEROCLAW_mcp__servers=

Deferred loading

mcp.deferred_loading is false by default, so configured MCP tools are included in the model context eagerly. Set it to true to place only MCP tool names in the system prompt; the LLM calls the built-in tool_search tool to fetch a tool’s full schema before invoking it. This keeps the initial context window small when a server exposes many tools.

Security and approval

MCP tool calls go through the same approval gate as every other tool, governed by the agent’s risk profile (risk_profiles.<alias>). The tool_search discovery step is auto-approved so deferred MCP loading can work in non-interactive sessions, but tools discovered from MCP servers still follow the normal approval policy:

  • At autonomy level = full, no tool call prompts (MCP tools included).
  • Otherwise, an MCP tool call prompts for approval unless its prefixed name (<server>__<tool>) is in the profile’s auto_approve list. auto_approve = ["*"] approves everything; an exact entry like auto_approve = ["filesystem__read_file"] approves just that tool.
  • always_ask is the inverse: a name (or "*") there always prompts, overriding auto_approve.

Authorization: allowed_tools / excluded_tools

Approval gates when a tool call needs a human green-light. Authorization gates whether the agent can call a tool at all. The two are independent.

Keep the three MCP tool controls on their own axes:

ControlScopeUse it for
tool_filter_groupsPrompt/context exposureDecide which MCP tool schemas are visible to the model for a turn.
auto_approve / always_askApproval policyDecide whether a selected MCP tool call requires operator approval.
allowed_tools / excluded_toolsCapability policyDecide which prefixed tool names the risk profile may use at all.

For runtime-discovered MCP tools the capability contract has an MCP-specific exception:

  • If the risk profile’s allowed_tools is empty or omitted, no authorization constraint applies; every discovered tool (MCP or built-in) is reachable. The TOML config does not distinguish an omitted field from allowed_tools = []; both deserialize to the same “no authorization constraint” state at the risk-profile level. If you need an explicit deny-all gate, do it on the caller-supplied per-run allowed_tools (cron jobs and other narrowers pass that list in directly) or via excluded_tools covering the specific tools you want blocked.
  • If allowed_tools is non-empty, any MCP tool whose name contains __ (the <server>__<tool> convention) is auto-admitted into the effective allow-list without being listed there individually. Non-MCP built-ins still need an exact entry.
  • excluded_tools always subtracts, including from the auto-admitted MCP set. To block a single MCP tool like filesystem__write_file while keeping the rest of the filesystem server reachable, put it in excluded_tools.

The rationale: before this exception, every agent that pinned an allowed_tools list to lock down its built-in surface would silently lose every MCP tool, even ones the operator explicitly configured. The cost is that the deny-list is now the operator’s primary lever for blocking destructive MCP capabilities under an allow-list-pinned profile.

If you want the strict pattern from before this change, where you only admit MCP tools you list explicitly with no __ auto-admit, combine an explicit allowed_tools entry with an excluded_tools entry per destructive sibling you need blocked:

[risk_profiles.assistant]
allowed_tools = [
  "file_read",
  "filesystem__read_file",
]
# Block the destructive sibling that would otherwise be auto-admitted via
# the `__` exception above.
excluded_tools = [
  "filesystem__write_file",
]
auto_approve = [
  "filesystem__read_file",
]

The MCP __ auto-admit exception is scoped to the risk profile’s allowed_tools only. Caller-supplied per-run allow-lists, like a cron job allowed_tools or any other narrowed invocation that passes an explicit list into the runtime, are still treated as strict explicit-list intersections, with no __ auto-admit on top. A cron job that narrows itself to allowed_tools = ["cron_add"] will not surface filesystem__write_file to the model even when the agent’s risk profile would otherwise auto-admit it via the __ convention; the per-run narrowing remains a reliable capability boundary regardless of how many MCP servers are configured.

auto_approve alone does not hide a tool from the model; it only answers the approval question after the model selects that tool. Use tool_filter_groups to reduce prompt noise and allowed_tools / excluded_tools to enforce a capability boundary.

See Autonomy levels for the full per-profile field surface, and the Config reference for every MCP field and default.