[BUG] v2.1.105 breaks all stdio MCP servers - stdin pipe closed immediately on spawn

Resolved 💬 4 comments Opened Apr 14, 2026 by fernmerc Closed Apr 21, 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

What's Wrong?

After updating from v2.1.101 to v2.1.105, all stdio MCP servers receive EOF on stdin immediately after being spawned (~3-70ms after the process reaches its read loop). The server initializes successfully, enters its stdin read loop, and stdin is already closed. No initialize message is ever received by the server.

This affects every stdio MCP server across all projects (confirmed by testing with a trivial 16 line MCP server that has zero imports, no stderr output, no initialization delay, and responds with pure JSON). The issue seems to be coming from Claude Code's stdio pipe management, not in any particular server implementation.

Rolling back to v2.1.101 immediately resolves the issue, and servers stay alive after startup and function normally.

What Should Happen?

Claude Code should keep the stdin pipe open after spawning a stdio MCP server, send the initialize request, and maintain the connection for the duration of the session. This is the behavior in v2.1.101.

Error Messages/Logs

# Server log showing immediate EOF (repeated for every startup attempt since the update):
2026-04-13 18:34:53,165 [INFO] Google MCP Server starting run loop...
2026-04-13 18:34:53,241 [INFO] Waiting for input on stdin...
2026-04-13 18:34:53,265 [INFO] Stdin closed (EOF received). Exiting loop.
2026-04-13 18:34:53,265 [INFO] Initiating server shutdown sequence...

Steps to Reproduce

  1. Create a minimal MCP server test_minimal_mcp.py
#!/usr/bin/env python3
import sys
import json

for line in sys.stdin:
    line = line.strip()
    if not line:
        continue
    msg = json.loads(line)
    method = msg.get("method")
    msg_id = msg.get("id")
    if method == "initialize":
        print(json.dumps({"jsonrpc": "2.0", "result": {"protocolVersion": "2024-11-05", "capabilities": {"tools": {}}, "serverInfo": {"name": "test", "version": "0.1"}}, "id": msg_id}), flush=True)
    elif method == "tools/list":
        print(json.dumps({"jsonrpc": "2.0", "result": {"tools": []}, "id": msg_id}), flush=True)
    else:
        print(json.dumps({"jsonrpc": "2.0", "result": {}, "id": msg_id}), flush=True)
  1. Add to .mcp.json:
{
  "mcpServers": {
    "test_minimal": {
      "type": "stdio",
      "command": "python3",
      "args": ["test_minimal_mcp.py"]
    }
  }
}
  1. Launch a new Claude Code session using v2.1.105
  2. The server is spawned and immediately receives EOF on stdin, never getting an initialize message

Note: The same server works perfectly on v2.1.101

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.101

Claude Code Version

2.1.105 (Claude Code)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

WSL (Windows Subsystem for Linux)

Additional Information

  • Suspected culprit is the v2.1.105 changelog entry: "Fixed stdio MCP server emitting malformed (non-JSON) output hanging the session instead of failing fast with 'Connection closed'". It looks like the fix is closing the stdin pipe unconditionally rather than only when malformed output is detected.
  • Tested and ruled out: slow server init time, stderr logging output, stdout contamination.
  • Old server processes started before the v2.1.105 auto-update (started on v2.1.101) continued running fine in the same sessions on the same system afterwards. Only newly spawned servers were affected.
  • Reproduced across multiple independent projects and machines, not specific to any server implementation.

View original on GitHub ↗

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