Skip to content

fix: Windows hang in Claude Code MCP stdio adapter - #36

Open
rebekahrichar wants to merge 1 commit into
RichSchefren:masterfrom
rebekahrichar:fix/windows-mcp-stdio-hang
Open

fix: Windows hang in Claude Code MCP stdio adapter#36
rebekahrichar wants to merge 1 commit into
RichSchefren:masterfrom
rebekahrichar:fix/windows-mcp-stdio-hang

Conversation

@rebekahrichar

Copy link
Copy Markdown

Summary

  • The Claude Code MCP stdio adapter (atlas_core/adapters/claude_code.py) hung forever on startup on Windows. loop.connect_read_pipe(sys.stdin) requires an overlapped-I/O handle under ProactorEventLoop, and an inherited stdin pipe on Windows isn't one — it fails with OSError: [WinError 6] The handle is invalid, which the surrounding code silently swallowed into a hang.
  • Replaced the async pipe-transport read with asyncio.to_thread(sys.stdin.readline), which works identically on Windows, Linux, and macOS.

Reproduced independently via a manual JSON-RPC handshake over both Git Bash and PowerShell pipes, and via the repo's own tests/integration/test_claude_code_stdio.py subprocess test (which hung identically before the fix).

Test plan

  • pytest tests/integration/test_claude_code_stdio.py -v — 4/4 passing (previously hung indefinitely on Windows)
  • pytest tests/integration/test_mcp_server.py tests/integration/test_claude_code_stdio.py -v — 18/18 passing
  • Full suite: pytest tests/ -q — 670 passed, 22 skipped, 4 failed (all 4 pre-existing, unrelated POSIX-only gaps: two Hermes installer tests that shell out to a .sh installer, two CLI tests that exec a .sh file directly without bash)
  • Manually verified ./demo.sh end-to-end on Windows (Docker Desktop + WSL2 + Neo4j 5.26) — full Ripple propagation loop closes correctly
  • Manually verified the fixed adapter against a live Claude Code .mcp.json config on Windows — all 17 tools list and dispatch correctly

loop.connect_read_pipe(sys.stdin) requires an overlapped-I/O handle under
ProactorEventLoop; an inherited stdin pipe on Windows isn't one, so the
adapter hung on startup with OSError: [WinError 6] The handle is invalid.
Reading via asyncio.to_thread(sys.stdin.readline) works identically on
Windows, Linux, and macOS. Verified against tests/integration/test_claude_code_stdio.py
and tests/integration/test_mcp_server.py (18/18 passing) plus the full suite
(670/674 passing; remaining 4 are pre-existing POSIX-only test gaps).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants