MCP Runtime Management

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

  1. Phase 1 (fast): Load local Claude Code configs via getClaudeCodeMcpConfigs() — plugins, user, project, local, dynamic scopes
  2. Phase 2 (slow): Fetch claude.ai configs via fetchClaudeAIMcpConfigsIfEligible() — may involve network requests
  3. Deduplication via dedupClaudeAiMcpServers() after phase 2 completes

Reconnection

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:

Trade-offs

  1. 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.
  2. 16ms batching — prevents UI thrashing but introduces a one-frame delay before connection state is visible.
  3. No reconnection for stdio/sdk — simpler but means local process crashes require manual restart or session restart.
  4. Two-phase loading — fast initial tool availability but claude.ai tools appear with a delay.

Depends on

Key claims

Relations

Sources

src-20260409-a5fc157bc756, source code analysis of src/services/mcp/useManageMCPConnections.ts, src/services/mcp/types.ts