MCP stdio and HTTP tools
Feature docs index · Repository README
Configure Model Context Protocol (MCP) servers so their tools appear beside magi-code's built-ins. You can diagnose setup without provider credentials.
Supported transports:
stdio: local child process MCP servers.http: MCP Streamable HTTP endpoints using POST/GET/DELETE.
Configuration and approval
Server definitions use the Claude-style .mcp.json convention, not a universal MCP specification. magi-code loads CONFIG_DIR/.mcp.json, then cwd/.mcp.json; CONFIG_DIR is the resolved MC_HOME (default ~/.magi-code). It does not search parent directories. A project server replaces the entire global definition with the same name, not individual fields.
Example .mcp.json:
{
"mcpServers": {
"filesystem": {
"command": "node",
"args": ["${MCP_SERVER_DIR}/server.js"],
"env": { "MCP_ROOT": "${MCP_ROOT:-/tmp/mcp-root}" }
},
"remote_search": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer ${MCP_REMOTE_SEARCH_TOKEN}",
"X-Team": "platform"
},
"timeout": 30
},
"my_oauth_server": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"oauth": {
"client_id": "your-client-id",
"scopes": ["read", "tools"],
"authorization_server": "https://auth.example.com"
}
}
}
}
All servers are disabled until approved. An enabled field in .mcp.json cannot grant approval. In Mission Control, /mcp lists discovered definitions; Up/Down selects, Enter toggles approval, and Esc closes. Changes apply on the next launch, not immediately or after /new.
Approvals are booleans in global settings.json at capabilities.mcp_approvals[canonical_source_path][name]:
{
"capabilities": {
"mcp_approvals": {
"/absolute/path/to/project/.mcp.json": { "filesystem": true }
}
}
}
Only global settings can approve servers. Project settings cannot approve themselves, and a global definition's approval does not approve a same-name project replacement. Moving a definition to another canonical source path requires approval there.
Approval is tied only to the canonical source path and server name, not a definition fingerprint. Editing a definition at the same path and name retains approval; review those edits before the next launch.
| Field | Behavior |
|---|---|
type | stdio (also the default when omitted) or http. |
command / args / env | Stdio only. Command is spawned directly. The child starts with PATH plus the Windows startup baseline, then receives the explicit env overlay. |
url | HTTP only. HTTPS required except explicit loopback HTTP (localhost, 127.0.0.0/8, or [::1]). URL credentials and redirects are rejected. |
headers | HTTP only. Values support environment expansion. Static Authorization / Proxy-Authorization are mutually exclusive with oauth. |
oauth.client_id | Optional public client id. If omitted, dynamic client registration is used when advertised. |
oauth.scopes | Optional requested scopes. |
oauth.authorization_server | Optional authorization-server override. |
timeout | Optional seconds per request; defaults to 30, max 300. |
Discovery parses every definition's structural fields, including server names, transport types, required fields, and JSON value types. Structural errors can block loading even for disabled servers. Only enabled entries expand environment references and validate runtime fields such as commands, URLs, headers, and timeouts. Missing environment variables in disabled entries do not block loading. Enabling through /mcp expands and validates the selected definition before saving approval; failure leaves the saved approval unchanged.
For enabled entries, ${VAR} and ${VAR:-default} expand once while loading command, each argument, environment values, URL, and header values. A missing variable without a default fails configuration loading. Defaults apply to unset variables; an empty variable stays empty. Expansion is not recursive or shell evaluation. Use environment references rather than storing secrets in .mcp.json.
HTTP timeout bounds each request. Cancellation is checked before and around an HTTP request, but an in-flight blocking POST/body cannot be interrupted; notifications/initialized uses the same path. Stdio and pending-response waits remain cancellation-responsive.
Calls to the same server can overlap, including calls from parallel subagents. Request IDs correlate replies; connection shutdown remains exclusive. Canceling or timing out an admitted request closes the shared connection and fails pending siblings, so later calls need a new connection. A call canceled before admission does not close it. In-flight blocking HTTP POSTs still run until completion or their timeout. OAuth token acquisition/refresh is serialized within the shared provider; tool POSTs are not.
Server and tool name components must each be non-empty and use only ASCII letters, digits, _, or -; neither component may contain __. A server id may not end with _, but a tool name may end with _. Qualified names use exactly mcp__<server>__<tool> and are limited to 64 bytes total. These restrictions keep the server/tool separator unambiguous.
HTTP security rules
- Keep
.mcp.jsonandsettings.jsonnon-secret. Use environment references for credentials. - Remote MCP and OAuth endpoints must use HTTPS. HTTP is accepted only for explicit loopback hosts:
localhost,127.0.0.0/8, and[::1]. - URL userinfo is rejected. Query and fragment data are accepted for endpoint configuration but stripped from metadata/discovery URLs and diagnostics.
- MCP POST, GET/SSE, DELETE, OAuth discovery, registration, and token clients disable redirects. A redirect fails before credentials can reach another origin or downgrade to HTTP.
- Use environment references such as
"Authorization": "Bearer ${MCP_TOKEN}"for sensitive headers. Configuration expands values once; the HTTP runtime accepts the resulting literal values without further expansion. - Non-sensitive headers may use literal values, for example
"X-Team": "platform". - All HTTP header values are redacted in debug output, errors, manager status, CLI diagnostics, sessions, and provider-visible paths.
- Diagnostics display sanitized URLs only: scheme, host, port, and path. Query strings, fragments, and URL credentials are not printed.
- HTTP error bodies are bounded before display.
- Provider auth variables are never copied into MCP HTTP headers automatically.
OAuth HTTP authentication
OAuth is explicit and interactive:
magi-code mcp login my_oauth_server
magi-code mcp logout my_oauth_server
magi-code mcp list
Behavior:
mcp login <server>discovers OAuth metadata, uses Authorization Code + PKCE S256, binds its callback to localhost only, and stores the resulting tokens locally.mcp logout <server>deletes the local token file only; it does not revoke remote tokens.mcp listshows OAuth status: authenticated, not authenticated, expired, refreshable, or invalid.- Normal agent runs never open a browser. If auth is missing or expired without refresh, diagnostics tell you to run
magi-code mcp login <server>.
Token storage:
- Tokens live under
$MC_HOME/mcp-tokens/<server>.json. - Token files are written with
0600permissions on Unix. - Tokens never belong in
settings.json. - Tokens, client secrets, authorization codes, PKCE verifier/state values, and bearer headers are redacted from logs, errors, Debug output, CLI diagnostics, sessions, and provider-visible tool output.
Security and limits:
- OAuth is mutually exclusive with static
AuthorizationandProxy-Authorizationheaders for the same server. - PKCE S256 is used for all login flows.
- The callback listener binds localhost only.
- Client Credentials and Device Code grants are not supported.
- Login is an explicit CLI command, not automatic during agent/tool execution.
Tool names
Discovered MCP tools are namespaced as:
mcp__<server>__<tool>
Example: server filesystem tool read_file becomes mcp__filesystem__read_file. Qualified names must be exactly mcp__<server>__<tool> and no more than 64 bytes total (UTF-8; current safe components are ASCII). Both components must be non-empty and use only ASCII letters/digits/_/-; neither may contain __. Only server names cannot end with _; tool names may end with _. These restrictions keep the server/tool separator unambiguous.
Diagnostics
Diagnostics read the resolved configuration directory, global settings approvals, and both .mcp.json sources. They do not attach/create sessions or require provider auth.
magi-code mcp list
Prints configured servers, type, enabled/disabled state, OAuth auth status when configured, and connection result. Enabled servers are started long enough to run initialize and tools/list; failures are reported with phase diagnostics on stderr. HTTP servers are shown as http <sanitized-url>. The command exits 0 if the list command itself ran, even when individual servers fail.
magi-code mcp test remote_search
Starts only the selected server, runs initialize and tools/list, prints server name/version/protocol plus discovered tool names/descriptions, then shuts down. For HTTP servers, shutdown sends best-effort session DELETE when the server issued an MCP session id. It exits non-zero for missing, disabled, spawn/connect, initialize, or list failures.
Startup policy by interface
magi-code mcp list and magi-code mcp test diagnose servers without opening a conversation. List reports per-server failures without making unrelated servers unusable. Mission Control applies a stricter launch gate: every configured enabled MCP server must connect, initialize, and discover tools before a queued prompt can run. An execution-critical failure restores the terminal, exits nonzero, and never runs that queue. The strict path's first-success/second-canceled stdio cleanup is covered by tests; this interface-specific policy does not change the MCP transport or diagnostic contracts above.
Mission Control requests cancellation before cleanup. Critical/provider worker joins are bounded at 2 s each before detach/error, but an in-flight HTTP POST/body (including notifications/initialized) cannot observe cancellation. The 2 s critical join may detach the worker while it remains subject to that server's configured request timeout (30 s default, 300 s maximum). Terminal restoration happens first. Pre-request cancellation and stdio/pending-response paths remain responsive; detaching a non-cooperative worker does not guarantee that it will have no side effects.
Supported MCP surface
Supported now:
stdiotransport.- Streamable HTTP transport with POST JSON-RPC, optional GET SSE notifications, and DELETE session termination.
initialize,notifications/initialized,tools/list, andtools/call.- HTTP
Mcp-Session-Idtracking andMCP-Protocol-Versionheaders after initialize. - SSE parsing for Streamable HTTP responses.
Not supported yet:
- Client Credentials OAuth grant.
- Device Code OAuth grant.
- SSE transport other than Streamable HTTP response parsing.
- WebSocket transport.
- MCP resources, prompts, sampling, elicitation.
- Live
tools/list_changedroute refresh. - magi-code-as-MCP-server mode.
Related docs
- PRD-0077: Mission Control Interactive Startup and Queued Prompts
- PRD-0066: MCP Stdio Tools Client Support
- PRD-0067: MCP Streamable HTTP Client Support
- ADR-0045: MCP Stdio Client Tools
- PRD-0068: MCP OAuth HTTP Client Support
- ADR-0046: MCP OAuth Token Authentication
- Configuration
- Tools and safety model