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):
| Transport | When to use | Required fields |
|---|---|---|
stdio (default) | A local process you spawn (a Node.js or Python MCP server) | command, optional args, env |
http | A remote server speaking MCP over HTTP POST | url, optional headers |
sse | A remote server speaking MCP over HTTP + Server-Sent Events | url, 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’sname; enter a row to edittransport,command/url,headers,env, andtool_timeout_secsas individual fields.+ Addcreates a new entry seeded with the name you supply; deleting from the alias list removes the entry. Thenamefield is not edited inline because renaming the natural key mid-edit would invalidate in-flight references; use the dashboard or hand-editconfig.tomlto rename for now. - Web dashboard: currently renders
mcp.serversthrough 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
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
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 🔑
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 🔑
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
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
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
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
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
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
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’sauto_approvelist.auto_approve = ["*"]approves everything; an exact entry likeauto_approve = ["filesystem__read_file"]approves just that tool. always_askis the inverse: a name (or"*") there always prompts, overridingauto_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:
| Control | Scope | Use it for |
|---|---|---|
tool_filter_groups | Prompt/context exposure | Decide which MCP tool schemas are visible to the model for a turn. |
auto_approve / always_ask | Approval policy | Decide whether a selected MCP tool call requires operator approval. |
allowed_tools / excluded_tools | Capability policy | Decide 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_toolsis 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 fromallowed_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-runallowed_tools(cron jobs and other narrowers pass that list in directly) or viaexcluded_toolscovering the specific tools you want blocked. - If
allowed_toolsis 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_toolsalways subtracts, including from the auto-admitted MCP set. To block a single MCP tool likefilesystem__write_filewhile keeping the rest of thefilesystemserver reachable, put it inexcluded_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.