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 and an agent is granted that server through its mcp_bundles (see Per-agent server scoping below). 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.
Per-agent server scoping (mcp_bundles)
A [[mcp.servers]] entry only defines a server. Which servers an agent actually connects to is decided by that agent’s agents.<alias>.mcp_bundles, and the model is secure by default: omission is not a grant.
- An agent with no
mcp_bundlesconnects to no MCP servers, even whenmcp.serversis non-empty. - A bundle
[mcp_bundles.<alias>]names the servers it grants by theirmcp.serversname, with an optionalexcludelist. An agent’s grant is the union of the servers across every bundle it references, minus any name excluded by any of those bundles (deny wins). - An unknown bundle alias, or a bundle server name that matches no configured server, grants nothing. Both fail closed and are reported as non-fatal warnings by config validation, so a typo narrows an agent’s access instead of widening it.
[[mcp.servers]]
name = "filesystem"
command = "npx"
[mcp_bundles.files]
servers = ["filesystem"]
[agents.assistant]
mcp_bundles = ["files"] # connects to `filesystem`; an agent without this gets no MCP servers
- Bundle changes take effect on session restart. The resolver (
Config::mcp_servers_for_agent) runs at session/agent construction time; editing[mcp_bundles.*]oragents.<alias>.mcp_bundleswhile a session is live does not change that session’s connected servers. End and restart the affected sessions to pick up new grants.
This is the connection boundary (which servers an agent talks to at all). The allowed_tools / excluded_tools controls below are the per-tool capability boundary applied on top of whatever a granted server exposes.
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.
Example: Parallel Search
Parallel Search MCP
provides public web search and page extraction without a Parallel account or API
key. Free access is rate limited. Its Streamable HTTP endpoint uses ZeroClaw’s
http transport:
[[mcp.servers]]
name = "parallel"
transport = "http"
url = "https://search.parallel.ai/mcp"
headers = { "User-Agent" = "ZeroClaw" }
[mcp_bundles.web]
servers = ["parallel"]
[agents.assistant]
mcp_bundles = ["web"]
The User-Agent identifies ZeroClaw project-wide so Parallel can measure
aggregate integration usage to understand adoption and support it. Keep this
header on HTTP requests if the transport changes. Preserve existing headers;
if you already set a User-Agent, append ZeroClaw to its existing project and
HTTP client tokens instead of replacing them.
Merge these entries into your existing config.toml, using the alias of the
agent you want to grant access. Add "web" to that agent’s existing
mcp_bundles list rather than replacing its other grants. If the web bundle
already exists, add "parallel" to its servers list. Keep mcp.enabled = true
and restart the affected session after changing grants.
The agent can then use parallel__web_search and parallel__web_fetch, subject
to its normal tool authorization and approval policy. Calls send queries,
requested URLs, and any supplied objective or context to Parallel. Once granted
access, the agent may choose these tools during its work. To revoke access,
remove "parallel" from every bundle granted to that agent, or add it to a
granted bundle’s exclude list, then restart the session.
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 (Config -> MCP servers -> a server): the same per-field surface as the TUI, one form per server.
env and headers are key/value maps, so both UIs show them as a container row followed by one row per entry (env.GITHUB_TOKEN, headers.Authorization, …):
- Add an entry: in zerocode, select the
env(orheaders) row showing[+ Add entry], press Enter, type the name, press Enter, then type the value (input hidden) and press Enter. In the dashboard, use the name/value inputs and Add entry under the map. The entry is saved immediately and encrypted at rest. - Change a value: edit the entry’s own row like any other secret.
- Remove an entry: delete the entry’s row (zerocode’s delete-row key, or the dashboard trash button and then Save).
Values are never displayed; the container row lists only entry names. From the CLI, zeroclaw config set mcp.servers.<name>.env.<KEY> adds or replaces an entry, and setting it to an empty value removes it. The bare map path (mcp.servers.<name>.env) cannot be set directly. The same editor applies to every secret key/value map in the config (for example provider extra_headers).
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.<KEY> # masked input, stored encrypted
zeroclaw config set mcp.servers.env.<KEY> "" # empty value removes the entry
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.<KEY> # masked input, stored encrypted
zeroclaw config set mcp.servers.headers.<KEY> "" # empty value removes the entry
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=
max_response_bytes
Maximum bytes accepted for a single HTTP/SSE JSON-RPC response body, enforced at read time before the body is parsed or any embedded resource is materialized. A compromised or misbehaving server cannot force an unbounded response-body allocation. This is the encoded wire cap, not the decoded materialization budget: None/0 uses the built-in default of 16,078,168 bytes, sized so a full 10 MiB decoded embedded-resource blob (its base64 expansion plus JSON-RPC envelope headroom) still fits. The separate 10 MiB figure is the decoded aggregate blob budget applied after parsing, not this wire cap.
Set it on any surface:
Gateway dashboard
Open /config/mcp.servers and set the mcp.servers.max_response_bytes field.
zerocode
In the Config pane, set the mcp.servers.max_response_bytes field.
zeroclaw config
zeroclaw config set mcp.servers.max_response_bytes <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__max_response_bytes=
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=
pinned_resources
Resource URIs to read once at agent startup and inject into the system prompt as untrusted, server-origin context. Each is read via resources/read on this server; pins on a server that does not advertise resources, or that the agent’s tool policy denies, are skipped with a warning. Read once per run (not refreshed; no subscriptions).
Set it on any surface:
Gateway dashboard
Open /config/mcp.servers and set the mcp.servers.pinned_resources field.
zerocode
In the Config pane, set the mcp.servers.pinned_resources field.
zeroclaw config
zeroclaw config set mcp.servers.pinned_resources <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__pinned_resources=
tls_ca_cert_path
Absolute path to a PEM-encoded CA certificate or bundle to trust in addition to the default roots for this server’s HTTP/SSE transport. Certificate and hostname verification remain enabled. The path must name a regular file no larger than 1 MiB; a missing, unreadable, empty, oversized, non-regular, or invalid file is a hard connection error rather than a fallback to the default trust store. When set, the configured URL and any advertised SSE message endpoint must use HTTPS; plaintext URLs and downgrade redirects are rejected. Ignored by stdio.
Set it on any surface:
Gateway dashboard
Open /config/mcp.servers and set the mcp.servers.tls_ca_cert_path field.
zerocode
In the Config pane, set the mcp.servers.tls_ca_cert_path field.
zeroclaw config
zeroclaw config set mcp.servers.tls_ca_cert_path <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__tls_ca_cert_path=
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.
Custom CA trust
For an HTTP or SSE server whose certificate is issued by a private CA, set
tls_ca_cert_path to an absolute path containing one or more PEM-encoded CA
certificates. The configured certificates are added to the default trust store;
certificate-chain, expiry, and hostname verification remain enabled.
A relative, missing, unreadable, empty, oversized, non-regular, or invalid CA
file is a hard connection error for that server. The path must resolve to a
regular file no larger than 1 MiB. Symlinks are followed, so certificate
rotation and mounted-secret layouts that publish the bundle through a symlink
work as configured; the resolved file is validated after it is opened, and a
symlink that resolves to a directory, device, or FIFO is rejected. ZeroClaw
never disables verification or silently
falls back when this field is set. The configured server URL and any message
endpoint advertised by an SSE server must use https://; plaintext URLs and
downgrade redirects are rejected before request headers or content are sent.
The value is applied when the MCP session starts; restart the affected session
after changing it. Remove the field and restart the session to return to the
default trust store. Stdio servers ignore it.
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, uncovered tool calls do not prompt (MCP tools included). A name (or"*") inalways_askstill prompts, including under Full. - 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_approveand Full autonomy.
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 omitted or empty, no authorization constraint applies; every discovered tool (MCP or built-in) is reachable; an empty list is the legacy unrestricted state, not deny-all. For an explicit deny-all gate, set the siblingdeny_all_tools = true: it denies MCP tools too (there is no__auto-admit under deny-all) and cannot be combined with a nonemptyallowed_tools. - 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.
MCP Resources and Prompts
In addition to MCP tools, ZeroClaw exposes MCP resources and prompts from connected servers.
Tools
Two built-in tools are available (subject to your agent’s tool access policy):
mcp_resources:action: "list"(optionalserver,cursor) lists resources;action: "read"withuri(prefixed<server>__<uri>) returns contents.mcp_prompts:action: "list"lists prompts;action: "get"withname(prefixed<server>__<name>) and optionalargumentsreturns the rendered prompt messages.
Servers that do not advertise resource/prompt capabilities are skipped, and calls against them return a clear “does not support” error.
Pinning resources into context
Each MCP server entry accepts an optional pinned_resources field: a list of
resource URIs to read once at startup and inject into the system prompt. Set it
through the same config surfaces used to define the server (the gateway, zerocode,
or zeroclaw config set, as shown under Configure MCP), naming
the resources you want the agent to always have on hand. The field defaults to
empty, so servers without it are unaffected.
Pinned content is read once per run (no live refresh) and is labeled
trust="untrusted-external" so the model treats it as data, not instructions.
Embedded resource blobs in tool results
When an MCP tools/call result includes a content item shaped as
type: "resource" with a nested blob (base64), ZeroClaw does not dump that
base64 into the model context. Instead it materializes the bytes under the
session workspace uploads/ directory (same shared helper and 10 MB limit as
ACP inbound resource.blob) and redacts the blob from the model-facing tool output, replacing it
with a materialized reference: a [Document: …] marker for
non-image mimes, or the plain saved path for image mimes, with the
image declared as an attachment on the tool result rather than
written into the text as a marker. This is
gated by content shape, not by tool name. Materialization does not auto-deliver
the file to ACP clients; the agent still calls deliver_file when outbound
delivery is needed. See ACP session/prompt blob intake.
The two other binary MCP content shapes are mapped as follows. A type: "image"
item (base64 data + mimeType) is materialized the same way and its content
item is rewritten to a text item carrying the plain saved path,
with the image declared as an attachment on the tool result, which the
multimodal pipeline lifts into a native provider image part; the item’s
annotations/_meta and other non-binary fields are preserved. Only the raster
formats the vision pipeline accepts are materialized: PNG, JPEG, WebP, and GIF.
The on-disk extension is derived from the declared mimeType (canonicalized to
its case-insensitive essence, parameters dropped) when it names one of those
types, otherwise from sniffing the decoded bytes; the extension must match the
bytes because the loader prefers a path’s extension over its magic. An image
whose type is neither a supported declared type nor a recognized supported
signature degrades to [attachment unavailable: …] and is not written. A
type: "audio" item is not materialized in this path, because no provider
resolves an audio path into content parts today, so its data is stripped to a
non-materializing [audio attachment: <mime>] placeholder. In every case the raw base64 never
reaches the model, including for a malformed image/audio item whose data is
empty or not a string.
Because the result comes from an untrusted server, two per-call bounds are
enforced before any payload is decoded, hashed, or written: at most 64
materializable binary items (resource blobs plus valid image items) per
tools/call result, and an estimated aggregate decoded size of at most 10 MiB
across all of them. A result that exceeds either bound has every such item
degraded to an [attachment unavailable: …] marker and writes nothing to disk,
so an array of many empty or tiny items cannot force per-item work. Each
individual payload is still bounded by the same 10 MB per-file limit.
Separate from these decoded budgets, each HTTP/SSE MCP server also has a
transport-level response-body cap, max_response_bytes, enforced on the raw
encoded wire bytes before the body is parsed so a server cannot force an
unbounded read. It is not the 10 MiB decoded limit above: it defaults to
16,078,168 bytes, the base64 expansion of the 10 MiB decoded aggregate plus
JSON-RPC envelope headroom, so a valid near-limit blob still reaches
materialization. Set max_response_bytes on a server to override it; 0 or
leaving it unset uses that default.
Security
Resource and prompt content originates from the configured MCP server and is
treated as untrusted: it is provenance-wrapped, secret-scrubbed, and
length-bounded before entering context. Access to mcp_resources / mcp_prompts
and to specific servers is governed by your agent’s tool access policy (risk
profile), and narrows correctly when delegating to subagents.
Example: Build Remote Agent (gbr)
Build Remote Agent is a pairing device: a phone
app spectates (and can inject into) this ZeroClaw host through free MIT
gbr-agent. Protocol gbr/1. Independent product by Linespotting AB. Not
affiliated with xAI or SpaceX.
Run gbr-agent on the host. Do not copy it into a sandbox. Attach only
loopback Bot API http://127.0.0.1:8788 or stdio gbr-mcp. Phone is spectator
and veto. Never paste mailbox keys as plaintext in config.toml. ZeroClaw chat
channels are not gbr/1.
Loopback limits network exposure. It is not process authentication.
Another local process can call :8788 unless you set GBR_BOT_REQUIRE_KEY=1
and give gbr-mcp the matching mailbox key through ZeroClaw secret-managed
MCP env (not a plaintext mailbox key in config.toml).
gbr-mcp logs tool-call arguments to ~/.gbr/logs/gbr-mcp-YYYY-MM-DD.jsonl
at info, default retention 7 days. Secret redaction does not strip ordinary
inject text. For the safe baseline set GBR_MCP_LOG_BODIES=0 on the gbr
server env in ZeroCode Config. Delete or disable those logs if you do not
want a second persistence surface outside ZeroClaw history.
Omission of mcp_bundles is not a grant: define the server and grant it.
Need Node.js 20+ (mcp/gbr-mcp engines.node >=20). Pin GitHub Release
v0.6.2 (checksum the installer, then the binary). Do not paste live
website curl | bash. See
PINNED-INSTALL.md.
Terminal 1 (leave this process running):
gbr-agent version # need v0.6.2
export GBR_BOT_REQUIRE_KEY=1
gbr-agent pair
gbr-agent run
After pairing, obtain the mailbox key from the phone (Settings -> Bot API) or
from the host pairing file ~/.gbr/device.json (mailbox_key). The pinned
gbr-mcp client reads GBR_MAILBOX_KEY from its options or process
environment; it does not load that pairing file. With GBR_BOT_REQUIRE_KEY=1,
a fresh shell that omits the key makes unauthorized Bot API requests.
Terminal 2 (MCP install and diagnose; gbr-agent run must already be up).
Paste the key into a silent prompt so the value is not stored in shell history:
git clone --branch v0.6.2 --depth 1 https://github.com/LinespottingOrg/GrokBuildRemote-Agents.git
cd GrokBuildRemote-Agents/mcp/gbr-mcp
node -v # v20+
npm install --ignore-scripts
IFS= read -rs GBR_MAILBOX_KEY # paste key, Enter; no echo, no history
export GBR_MAILBOX_KEY
export GBR_MCP_LOG_BODIES=0
node bin/gbr-mcp.js --diagnose
The source tag is pinned, but this release has no npm lockfile, so dependency versions are resolved at install time. --ignore-scripts prevents dependency lifecycle scripts from running during installation; it does not make the downloaded dependencies trusted or prevent their code from running when the MCP server starts.
The export lines above apply only to this diagnostic shell. They do not
configure the ZeroClaw-spawned gbr server. Define the server and grant it:
[[mcp.servers]]
name = "gbr"
command = "node"
args = ["/absolute/path/to/GrokBuildRemote-Agents/mcp/gbr-mcp/bin/gbr-mcp.js"]
[mcp_bundles.gbr]
servers = ["gbr"]
[agents.assistant]
mcp_bundles = ["gbr"]
Then set both GBR_MAILBOX_KEY and GBR_MCP_LOG_BODIES=0 on that server’s
env through ZeroCode Config (/config -> mcp.servers -> gbr -> env).
The mailbox key is a secret field: use the masked prompt (encrypted secrets
store) or a 1Password op://vault/item/field reference. Do not put the raw
key in config.toml. The CLI equivalent is:
zeroclaw config set mcp.servers.gbr.env.GBR_MAILBOX_KEY
zeroclaw config set mcp.servers.gbr.env.GBR_MCP_LOG_BODIES 0
All MCP environment values use ZeroClaw’s masked secret prompt, so the
trailing 0 is not consumed as the value. Enter 0 at that prompt.
Restart the affected session after changing bundles or env. HTTP without MCP,
after gbr-agent run with GBR_BOT_REQUIRE_KEY=1:
IFS= read -rs GBR_MAILBOX_KEY
export GBR_MAILBOX_KEY
curl -sS -H "X-GBR-Key: $GBR_MAILBOX_KEY" http://127.0.0.1:8788/health
curl -sS -H "X-GBR-Key: $GBR_MAILBOX_KEY" http://127.0.0.1:8788/v1/sessions
Docs: BOT-API.md