# 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.
## Settings
MCP servers live in non-secret `~/.magi-code/settings.json` under `mcp_servers`.
Stdio server:
```json
{
"mcp_servers": {
"filesystem": {
"type": "stdio",
"command": "node",
"args": ["/path/to/server.js"],
"env": { "MCP_ROOT": "/tmp/mcp-root" },
"enabled": true,
"timeout": 30
}
}
}
```
HTTP server with static headers:
```json
{
"mcp_servers": {
"remote_search": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "{env:MCP_REMOTE_SEARCH_TOKEN}",
"X-Team": "platform"
},
"enabled": true,
"timeout": 30
},
"local_dev": {
"type": "http",
"url": "http://localhost:8787/mcp",
"headers": {},
"enabled": true,
"timeout": 15
}
}
}
```
HTTP server with OAuth:
```json
{
"mcp_servers": {
"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"
},
"enabled": true,
"timeout": 30
}
}
}
```
Fields:
| `type` | `stdio` or `http`. |
| `command` / `args` / `env` | Stdio only. Command is spawned directly; `env` is a non-secret child-process map. |
| `url` | HTTP only. Must be `https://...`, except explicit loopback HTTP (`localhost`, `127.0.0.0/8`, or `[::1]`) for local development. URL credentials are rejected. Redirects are never followed. |
| `headers` | HTTP only. Static headers. Sensitive headers must use `{env:VAR_NAME}`. Mutually exclusive with `oauth` for `Authorization` / `Proxy-Authorization`. |
| `oauth.client_id` | HTTP OAuth only. Optional public client id. If omitted, dynamic client registration is used when the server advertises it. |
| `oauth.scopes` | HTTP OAuth only. Optional requested scopes. |
| `oauth.authorization_server` | HTTP OAuth only. Optional authorization-server override. |
| `enabled` | Optional; defaults to `true`. Disabled servers are skipped. |
| `timeout` | Optional seconds per request; defaults to `30`, max `300`. |
Server ids must use ASCII letters, digits, `_`, or `-`, and cannot contain `__`.
## HTTP security rules
- `settings.json` is non-secret. Do not put bearer tokens, API keys, OAuth tokens, or passwords in it.
- 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.
- Sensitive HTTP headers must use `{env:VAR_NAME}`. Sensitive names are `Authorization`, `Proxy-Authorization`, and any header name containing `token`, `secret`, or `api-key` case-insensitively.
- 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`. MCP tool names follow the same safe-name rules and cannot contain `__`.
## Diagnostics
Diagnostics read `MC_HOME` and `settings.json`, do not attach/create sessions, and do not 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.
## 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-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)