[BUG] MCP tools incorrectly mapped when connect multiple servers

Resolved 💬 3 comments Opened Jan 16, 2026 by zth9 Closed Jan 16, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

Summary

When Claude Code initializes multiple MCP servers concurrently at startup, some servers receive responses intended for other servers. This causes tools to be mapped to incorrect server namespaces. The issue only occurs during initial startup - reconnecting via /mcp command resolves the mapping correctly.

Environment

  • Claude Code version: 2.1.9
  • MCP SDK version: 1.24.0 (@modelcontextprotocol/sdk)
  • Platform: macOS (Darwin 25.1.0, arm64)
  • MCP Transport: SSE (Server-Sent Events)
  • Number of MCP servers: 21
  • MCP Gateway: Custom gateway (OpenAPI-to-MCP proxy)

Problem Description

Observed Behavior

After a fresh start of Claude Code with 21 SSE-type MCP servers configured, some servers receive initialize responses intended for other servers:

From debug logs (~/.claude/debug/*.txt):

2024-XX-XXT05:39:15.826Z [DEBUG] MCP server "server-A": Starting connection...
2024-XX-XXT05:39:15.826Z [DEBUG] MCP server "server-B": Starting connection...
2024-XX-XXT05:39:15.828Z [DEBUG] MCP server "server-C": Starting connection...
2024-XX-XXT05:39:15.828Z [DEBUG] MCP server "server-D": Starting connection...

2024-XX-XXT05:39:15.940Z [DEBUG] MCP server "server-B": Connection established with capabilities: {"serverVersion":{"name":"server-A",...}}  ❌ WRONG!
2024-XX-XXT05:39:15.940Z [DEBUG] MCP server "server-A": Connection established with capabilities: {"serverVersion":{"name":"server-A",...}}  ✓ Correct

2024-XX-XXT05:39:15.977Z [DEBUG] MCP server "server-D": Connection established with capabilities: {"serverVersion":{"name":"server-D",...}}  ✓ Correct
2024-XX-XXT05:39:16.014Z [DEBUG] MCP server "server-C": Connection established with capabilities: {"serverVersion":{"name":"server-D",...}}  ❌ WRONG!

Key Observations

  1. Timing correlation: Servers that start connection at the exact same millisecond are affected
  • server-A and server-B both started at 05:39:15.826Z
  • server-C and server-D both started at 05:39:15.828Z
  1. Response routing error: The initialize response from one server is delivered to another server's connection
  1. Unique serverInfo.name doesn't help: Even after configuring each MCP server to return a unique serverInfo.name, the problem persists because the entire response is routed to the wrong connection

Expected Behavior

Each MCP server connection should receive its own initialize response, regardless of concurrent connections.

Workaround

Running /mcp command to reconnect all servers immediately fixes the tool mapping.

Root Cause Analysis

Hypothesis 1: MCP Gateway Bug

The MCP gateway may have a race condition when handling concurrent SSE connections:

  • When multiple /sse endpoints are requested simultaneously
  • The initialize responses may be routed to incorrect SSE streams

Evidence against: External concurrent testing (50+ rounds) could not reproduce the issue.

Hypothesis 2: Claude Code Client Bug

Claude Code's MCP client may have a race condition when:

  • Multiple SSE connections are established simultaneously
  • Responses arriving at the same time may be associated with wrong connections

Evidence for:

  • The issue only occurs during Claude Code startup (high concurrency)
  • Manual reconnection (/mcp) always works correctly (lower concurrency)
  • Affected server pairs always start at the exact same millisecond

Hypothesis 3: MCP SDK Bug

The @modelcontextprotocol/sdk SSE transport may have issues with concurrent connections sharing some state.

Steps to Reproduce

Prerequisites

  1. Set up 10+ MCP servers accessible via SSE transport
  2. Configure all servers in Claude Code

Reproduction Steps

  1. Configure Claude Code with 10+ MCP servers in ~/.claude.json:

``json
{
"projects": {
"/path/to/project": {
"mcpServers": {
"server-1": { "type": "sse", "url": "http://gateway/mcp/server-1/sse" },
"server-2": { "type": "sse", "url": "http://gateway/mcp/server-2/sse" },
"server-3": { "type": "sse", "url": "http://gateway/mcp/server-3/sse" },
// ... 10+ servers
}
}
}
}
``

  1. Start Claude Code fresh (not resuming a session)
  1. Check debug logs at ~/.claude/debug/*.txt for "Connection established" entries
  1. Look for mismatches where MCP server "X" shows serverVersion.name: "Y" (where X ≠ Y)
  1. Expected: Each server's serverVersion.name matches its configured name

Actual: Some servers show another server's serverVersion.name

  1. Run /mcp to reconnect - all mappings become correct

Detailed Debug Log Analysis

Connection Timeline

Time (ms)    Event
─────────────────────────────────────────────────────────────
826          server-A: Starting connection
826          server-B: Starting connection      ← Same millisecond!
828          server-C: Starting connection
828          server-D: Starting connection      ← Same millisecond!
...
940          server-B: Connected (got server-A's response) ❌
940          server-A: Connected (correct)      ← Same millisecond!
...
977          server-D: Connected (correct)
1014         server-C: Connected (got server-D's response) ❌

Pattern

Servers that start connection at the exact same millisecond are at risk of receiving each other's responses.

Suggested Investigation

  1. Check SSE connection isolation: Verify that each SSEClientTransport instance maintains completely isolated state
  1. Check response correlation: Verify that JSON-RPC response IDs are correctly matched to their originating connections
  1. Add connection identifiers: Consider adding unique connection IDs to debug logs to trace response routing
  1. Test with artificial delays: Add small random delays between MCP server connections to see if it prevents the issue

Potential Fix

// Instead of starting all connections simultaneously:
await Promise.all(servers.map(s => s.connect()));

// Consider sequential or batched initialization:
for (const server of servers) {
  await server.connect();
  await sleep(10); // Small delay between connections
}

// Or use a semaphore to limit concurrency:
const semaphore = new Semaphore(5);
await Promise.all(servers.map(async s => {
  await semaphore.acquire();
  try {
    await s.connect();
  } finally {
    semaphore.release();
  }
}));

Impact

  • Severity: High - Tools are registered under wrong server namespaces
  • Frequency: Occurs on most fresh starts with 10+ MCP servers
  • Workaround available: Yes - /mcp reconnect fixes the issue

Additional Information

Test Environment

  • 21 MCP servers configured
  • All using SSE transport via custom gateway
  • Each server returns unique serverInfo.name
  • Each server has distinct tools

Files for Reference

  • Debug logs: ~/.claude/debug/*.txt
  • MCP config: ~/.claude.jsonprojects.*.mcpServers

Related Components

  • MCP SDK: @modelcontextprotocol/sdk v1.24.0
  • Transport: SSEClientTransport
  • Protocol version: 2024-11-05

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗