-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
Summary
Spec-level RFC proposing autoConnect: false for mcp-config.json / .mcp.json to enable true lazy/deferred server registration — resolving context window token exhaustion, 400 Bad Request errors under Sonnet 4.6, and the inability to hot-reload .mcp.json in active sessions.
Consolidates upstream issues: anthropics/claude-code#6638, #11364, #11370, #14879, #16826, #18497
Problem Statement
MCP server lifecycle has one mode: eager connect at session init. All configured servers run initialize → tools/list before the first prompt regardless of need. Three bugs compound this:
/mcp disabledoes not evict schemas — tools hidden from selector but schemas remain serialized in context. Token cost paid regardless. ([Bug] Disabled MCP servers still load tool definitions into Claude's context anthropics/claude-code#11370)/mcp addpermanently mutatesmcp-config.json— no session-scoped lazy injection without global config mutation. (Add dynamic loading/unloading of MCP servers during active sessions anthropics/claude-code#6638).mcp.jsondisk changes invisible to active session — no reload, sync, or watch mechanism. (Add dynamic loading/unloading of MCP servers during active sessions anthropics/claude-code#6638, #14879)
Measured impact: 10-server unoptimized setup = ~75,000 tokens consumed at session start before any user prompt. Directly causes 400 Bad Request at Sonnet 4.6 serialization ceiling.
Proposed Config Schema
Add autoConnect (boolean, default true) to the server entry spec in mcp-config.json / .mcp.json:
{
"mcpServers": {
"playwright": {
"type": "local",
"command": "npx",
"args": ["@playwright/mcp@latest"],
"tools": ["browser_navigate", "browser_screenshot"],
"autoConnect": false
},
"linear": {
"type": "http",
"url": "https://mcp.linear.app/sse",
"tools": ["create_issue", "list_issues", "update_issue"],
"autoConnect": false
},
"github": {
"type": "local",
"command": "gh",
"args": ["mcp", "serve"],
"autoConnect": true
}
}
}autoConnect: true(default) — current behavior, zero regressionautoConnect: false— registered but dormant: no process spawn, no stdio pipe, no handshake, zero schema tokens until explicitly activated
Lifecycle State Machine
┌─────────────────────────────────────────────────────────┐
│ REGISTERED (dormant) │
│ autoConnect: false at config parse │
│ No process. No pipe. No tokens. │
└────────────────────────┬────────────────────────────────┘
│ /mcp enable OR first tool-call trigger
▼
┌─────────────────────────────────────────────────────────┐
│ CONNECTING │
│ Full initialize handshake per MCP spec 2025-11-25 │
│ Identical path to /mcp add mid-session │
└────────────────────────┬────────────────────────────────┘
│ initialized + tools/list complete
▼
┌─────────────────────────────────────────────────────────┐
│ ACTIVE │
│ Schemas injected at next turn boundary only │
└────────────────────────┬────────────────────────────────┘
│ /mcp disable
▼
┌─────────────────────────────────────────────────────────┐
│ SUSPENDED │
│ Process kept alive (fast re-enable) │
│ Schemas EVICTED from context at next turn ← NEW │
└────────────────────────┬────────────────────────────────┘
│ /mcp enable
▼
ACTIVE (re-announce tools at next turn)
Required Behavior Changes
| # | Change | Upstream Ref |
|---|---|---|
| 1 | /mcp disable MUST evict schemas at next turn boundary — not just hide from selector |
anthropics/claude-code#11370 |
| 2 | autoConnect: false MUST NOT spawn process, pipe, or handshake at session init |
anthropics/claude-code#18497 |
| 3 | /mcp enable on dormant server MUST execute full initialize handshake (already works for /mcp add — formalize as documented contract) |
anthropics/claude-code#6638 |
| 4 | New /mcp sync command — re-parses .mcp.json from cwd in-session, registers/deregisters without session restart |
anthropics/claude-code#6638, #14879 |
MCP Protocol Spec Extension
For modelcontextprotocol/specification RFC — add to initialize handshake:
// ClientCapabilities
lazyRegistration?: {
supported: boolean; // client can handle deferred tool injection
};
// ServerCapabilities (InitializeResult)
supportsLazyRegistration?: boolean; // server can defer tools/list until client requestsEnables bidirectional lazy-connect signaling at protocol layer.
Token Budget Impact
| Configuration | Schema Tokens at Session Start |
|---|---|
Eager wildcard * (current default) |
~75,000 |
autoConnect: false (this RFC) |
0 until /mcp enable |
autoConnect: true + defer loading: true |
~1,100/server (BM25 meta-tools, v2.1.9+) |
| Dormant + defer loading on activation | 0 → ~1,100 strictly on demand |
Current Workaround (Windows 11 / Copilot CLI)
# Launch: register all, connect none
copilot `
--disable-mcp-server playwright `
--disable-mcp-server linear `
--disable-builtin-mcps
# Mid-session — activate on demand:
/mcp enable linear # Full initialize handshake fires NOW
# Schemas available at NEXT prompt turn
/mcp disable linear # Suspend, evict schemas next turn
/mcp enable playwrightStructurally equivalent to autoConnect: false using existing primitives. This RFC formalizes it as a first-class config flag and closes the schema-eviction gap in /mcp disable.
/mcp sync Command Spec
/mcp sync [--file PATH]
- Re-reads
.mcp.jsonfromcwd(or--file) and~/.copilot/mcp-config.json - New entries: register per their
autoConnectvalue - Removed entries: kill process, deregister, evict schemas
- Modified entries: full disconnect + reconnect
- No session restart required
- Read-only from CLI perspective — writes nothing to disk
Handshake Path Comparison
| Property | Session Init | /mcp enable (post-RFC) |
|---|---|---|
| Trigger | CLI launch | In-session command or first tool call |
| Phase 4 harvest | Eager, ALL servers, blocking | Single server, on-demand |
| Context impact | Immediate, all schemas | Next turn boundary only |
| Config write | Read-only | Read-only (no mutation) |
References
- MCP Lifecycle Spec 2025-11-25: https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle
- anthropics/claude-code upstream issues: #6638, #11364, #11370, #14879, #16826, #18497
- FastMCP 3.1 Middleware: https://gofastmcp.com/servers/middleware
- tool-gating-mcp: https://github.com/ajbmachon/tool-gating-mcp
- MCP Tool Search (v2.1.9, Jan 2026): partial solution — defers schema injection, not connection
- Copilot CLI GA: https://github.blog/changelog/2026-02-25-github-copilot-cli-is-now-generally-available/