<server>__<tool> (for example github__create_issue) and behaves like any built-in
tool. MCP tools cross a trust boundary, so they are high-risk by default — every call
routes through the approval gate unless you explicitly auto-approve it (see
Trust controls).
Servers connect at daemon startup. A server that fails to connect is logged and skipped —
it never blocks startup or the other servers.
Adding a server
CLI
monad mcp is the scriptable surface and needs no restart:
mcp add installs the server as a hot MCP atom under ~/.monad/atoms/mcp/. A server that
needs authentication or trust controls belongs in agents.json instead — see below.
Web UI
Studio → Capabilities → MCP servers lists every configured server with live status (connected, disabled, or failed) and its advertised tools, and adds, edits, enables, authorizes, reconnects, and removes them. It is the same statemonad mcp reads, backed
by /v1/settings/mcp-servers.
agents.json
Add entries to themcpServers array in agents.json. Two transports are supported:
stdio (Monad spawns the server as a subprocess) and http (streamable HTTP to a
remote URL).
name, transport: "stdio", command, plus optional args, env,
cwd, and requestTimeoutMs. HTTP fields: name, transport: "http", url, plus
optional auth, headers, and requestTimeoutMs. Both accept enabled (default
true) and a trust block.
Edits apply live: the daemon diffs the new list against its open connections and only
connects added servers, disconnects removed ones, and reconnects edited ones. Unchanged
servers keep their subprocess and session; the agent sees the updated tool set on its
next turn.
Protocol negotiation and Tasks
Monad probes each configured server for MCP2026-07-28 first and falls back to the
legacy initialize handshake when needed. A single agent can therefore use modern and
legacy stdio or HTTP servers at the same time without per-server protocol flags.
When a modern server advertises io.modelcontextprotocol/tasks, Monad:
- sends a stable invocation id so retry-safe servers can deduplicate the initial tool call;
- persists the returned Task id and correlation metadata under the Monad data directory;
- subscribes to
notifications/taskson HTTP and stdio servers, periodically re-listens after finite streams, and usestasks/getpolling as a fallback; - forwards structured
input_requiredforms to the originating session while preserving string, boolean, number, and integer values and rejecting unsafe property names; - retries transient reads with bounded backoff and propagates session cancellation
through
tasks/cancel; and - resumes observation or a pending cancellation after the MCP connection is rebuilt; and
- bounds each server to eight active and 64 queued Tasks, records recovery/retry counters, honors server TTLs, and removes terminal journal records after seven days.
deliveryPending in the private journal
instead of silently fabricating a continuation of the old model turn.
The Web transcript renders active Tasks as progress cards with a stop-turn action that
propagates cancellation to the remote Task. A completed Task still
appears as the original tool result, with the related Task id retained in result
metadata. MCP App resources use the standard ui/initialize and postMessage data
notifications inside an opaque-origin sandbox; links are validated by the host and
require an explicit user confirmation, while unapproved iframe tool calls are rejected.
Legacy servers and modern servers without the extension continue through the ordinary
synchronous tool-call path.
Secrets
MCP is a Monad-native feature and does not use Agent Runtime Credentials. Store HTTP tokens, headers, OAuth state, and stdio environment values directly on the owning MCP server inagents.json. Settings responses redact these values, but the user is
responsible for protecting the file. ${secret:...} references are rejected.
HTTP authentication
Theauth field on an http server selects one of four modes:
{ "mode": "none" }— no credentials (the default).{ "mode": "bearer", "token": "mcp-token-value" }— sent as anAuthorization: Bearerheader.{ "mode": "headers", "headers": { "x-api-key": "mcp-key-value" } }— arbitrary headers.{ "mode": "oauth" }— the standard MCP OAuth flow, orchestrated by the daemon.
OAuth
Foroauth servers, Monad runs discovery, dynamic client registration, and the
authorization-code + PKCE flow, then stores the tokens beside that server in
agents.json. Trigger it with
the Authorize button in the web UI or monad mcp authorize <name>; Monad opens your
browser and reconnects the server once authorization completes. Optional fields:
clientId (skips dynamic registration), scopes, and flow — "loopback" (browser +
localhost redirect, the default) or "device" (RFC 8628 device code for headless
daemons; requires a preconfigured clientId).
Daemon startup never opens a browser: at boot a stored token is refreshed silently or
the connection fails closed. A token that expires mid-session is re-authorized when an
agent tool call hits it.
Trust controls
Each server takes an optionaltrust block:
autoApproveTools— fully qualified tool names (<server>__<tool>form, e.g.github__get_issue) exempt from the per-call approval gate. Entries that match no advertised tool are logged as inert.pinnedToolHash— locks the server’s advertised tool set. If the tools change after you vetted them (a rug-pull), the daemon refuses to register the server until you re-pin. On connect, an unpinned server’s current hash is printed in the daemon log so you can copy it into config.hostEscape— marks a server whose tools drive your real machine (computer use). Its non-auto-approved tools can be approved for a session but never as a permanent “always allow”.
Browser and computer presets
Settingbrowser.enabled or computer.enabled in agents.json synthesizes an MCP
server named browser or computer — no manual mcpServers entry needed. A
user-defined server of the same name takes precedence and the preset steps aside. See
computer use & browser use.
Troubleshooting
- Check status first.
monad mcp status, the Studio panel, orGET /v1/settings/mcp-servers/statusshow each server as connected, disabled, or failed, with its tool list. - A server failed at boot. The reason is in the daemon log. Fix the config and save
(the edit reconnects it), or force a retry with
monad mcp reconnect <name>. - Connect fails because authentication is missing. Re-enter the token or repeat OAuth authorization on the owning MCP server.
- “tool set changed … refusing to register”. The server’s tools no longer match
trust.pinnedToolHash. Review the change, then update the pin to the new hash from the log. - An
autoApproveToolsentry has no effect. Tool names must use the<server>__<tool>form; the warning in the daemon log lists the advertised names. - Two entries point at the same remote. HTTP servers are deduplicated by normalized URL — the duplicate is skipped and logged.