magi-code 0.80.2

Repository-aware CLI coding agent for terminal work
Documentation
# MCP stdio and HTTP tools

[Feature docs index](README.md) · [Repository README](../../README.md)

## Purpose

Configure Model Context Protocol (MCP) tool servers so their tools appear beside built-in magi-code tools, then 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`:

```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]`:

```json
{
  "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.

Old MCP definitions in `settings.json` (`capabilities.mcp` or legacy `mcp_servers`) are ignored. There is no automatic migration: move definitions into `.mcp.json` under `mcpServers`, then approve them with `/mcp`.

| Field | Behavior |
| --- | --- |
| `type` | `stdio` (also the default when omitted) or `http`. Legacy `sse` is explicitly rejected. |
| `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`; the old `{env:VAR}` header syntax is not used.

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.

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.json` and `settings.json` non-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:

```sh
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 list` shows 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 `0600` permissions 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 `Authorization` and `Proxy-Authorization` headers 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:

```text
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.

```sh
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.

```sh
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:

- `stdio` transport.
- Streamable HTTP transport with POST JSON-RPC, optional GET SSE notifications, and DELETE session termination.
- `initialize`, `notifications/initialized`, `tools/list`, and `tools/call`.
- HTTP `Mcp-Session-Id` tracking and `MCP-Protocol-Version` headers after initialize.
- SSE parsing for Streamable HTTP responses.

Not supported yet:

- Client Credentials OAuth grant.
- Device Code OAuth grant.
- Legacy pre-2025-03-26 SSE transport.
- WebSocket transport.
- MCP resources, prompts, sampling, elicitation.
- Live `tools/list_changed` route refresh.
- magi-code-as-MCP-server mode.

## Related docs

- [PRD-0077: Mission Control Interactive Startup and Queued Prompts](../prd/0077-mission-control-interactive-startup-and-queued-prompts.md)
- [PRD-0066: MCP Stdio Tools Client Support](../prd/0066-mcp-stdio-tools-client-support.md)
- [PRD-0067: MCP Streamable HTTP Client Support](../prd/0067-mcp-streamable-http-client-support.md)
- [ADR-0045: MCP Stdio Client Tools](../adr/0045-mcp-stdio-client-tools.md)
- [PRD-0068: MCP OAuth HTTP Client Support](../prd/0068-mcp-oauth-http-client-support.md)
- [ADR-0046: MCP OAuth Token Authentication](../adr/0046-mcp-oauth-token-authentication.md)
- [Configuration](configuration.md)
- [Tools and safety model](tools-and-safety.md)

---

[Back to feature docs](README.md) · [Back to repository README](../../README.md)