MCP Runtime Management
- Entity ID:
ent-20260410-598bcda9820d - Type:
mechanism - Scope:
shared - Status:
active - Aliases: MCP connection lifecycle, useManageMCPConnections, MCP reconnection
Description
MCP runtime management (src/services/mcp/useManageMCPConnections.ts) handles the full lifecycle of MCP server connections: discovery, connection, reconnection, toggling, and cleanup. Implemented as a React hook that manages connection state for all configured MCP servers, with exponential backoff reconnection, batched state updates, and two-phase config loading.
Connection states
Servers exist in one of 5 states (discriminated union MCPServerConnection):
| State | Fields | Meaning |
|---|---|---|
connected |
Client, ServerCapabilities, serverInfo, instructions, cleanup() |
Active connection with capabilities |
failed |
optional error string |
Connection attempt failed |
needs-auth |
— | OAuth/auth required before connecting |
pending |
optional reconnectAttempt, maxReconnectAttempts |
Connection in progress or reconnecting |
disabled |
— | User disabled via toggle |
How it works
Two-phase config loading
- Phase 1 (fast): Load local Claude Code configs via
getClaudeCodeMcpConfigs()— plugins, user, project, local, dynamic scopes - Phase 2 (slow): Fetch claude.ai configs via
fetchClaudeAIMcpConfigsIfEligible()— may involve network requests - Deduplication via
dedupClaudeAiMcpServers()after phase 2 completes
Reconnection
- Only for non-stdio, non-sdk transports (SSE, HTTP, WebSocket) — local process servers don't benefit from reconnection
MAX_RECONNECT_ATTEMPTS = 5INITIAL_BACKOFF_MS = 1000MAX_BACKOFF_MS = 30000- Formula:
Math.min(1000 * 2^(attempt-1), 30000)— exponential backoff
Batched state updates
MCP_BATCH_FLUSH_MS = 16 (one frame at 60fps). Multiple server state changes within 16ms are coalesced into a single setAppState call via flushPendingUpdates(), preventing UI thrashing when many servers connect simultaneously.
Change notification handlers
Registered handlers for ToolListChangedNotificationSchema, PromptListChangedNotificationSchema, and ResourceListChangedNotificationSchema. When a server notifies that its tools/prompts/resources changed, the cache is invalidated (fetchToolsForClient.cache.delete) and re-fetched.
Stale server cleanup
excludeStalePluginClients() removes servers whose config hash changed or whose plugin source was removed, preventing ghost connections to outdated configs.
Public API
The hook useManageMCPConnections(dynamicMcpConfig, isStrictMcpConfig) returns:
reconnectMcpServer(serverName)— trigger manual reconnectiontoggleMcpServer(serverName, enabled)— enable/disable without editing config files
Trade-offs
- React hook — natural for the Ink-based UI but couples connection management to the React render cycle. Server management in headless/SDK mode requires a different code path.
- 16ms batching — prevents UI thrashing but introduces a one-frame delay before connection state is visible.
- No reconnection for stdio/sdk — simpler but means local process crashes require manual restart or session restart.
- Two-phase loading — fast initial tool availability but claude.ai tools appear with a delay.
Depends on
- mcp-client — transport and connection
- mcp-server-discovery — config loading
- mcp-subsystem — parent system
Key claims
- Exponential backoff: 1s initial, 30s max, 5 attempts for remote transports
- State updates batched at 16ms intervals to prevent UI thrashing
- Two-phase config loading: local configs fast, claude.ai configs deferred
- Cache invalidation on server tool/prompt/resource change notifications
Relations
part_ofmcp-subsystemdepends_onmcp-clientdepends_onmcp-server-discovery
Sources
src-20260409-a5fc157bc756, source code analysis of src/services/mcp/useManageMCPConnections.ts, src/services/mcp/types.ts