Windows: Python stdio MCP servers fail handshake — stdout response never received by rmcp client

Resolved 💬 2 comments Opened Jun 20, 2026 by kevinmo3 Closed Jun 30, 2026

What version of Codex is running?

codex-cli v0.142.0-alpha.6 (also tested v0.141.0)

What subscription do you have?

N/A — using Ollama as backend (glm-5.2:cloud)

Which model were you using?

glm-5.2:cloud (via Ollama OpenAI-compatible endpoint)

What platform is your computer?

Microsoft Windows NT 10.0.26200.0 x64

What issue are you seeing?

Python-based stdio MCP servers fail the JSON-RPC handshake on Windows. The server starts successfully, loads all tools (visible in stderr logs), and writes the initialize response to stdout — but Codex's Rust MCP client (rmcp) never receives it.

Error:

MCP startup failed: handshaking with MCP server failed: connection closed: initialize response

Key Evidence

  • ✅ The Python MCP server (workspace-mcp / FastMCP) starts and loads 9 tools correctly — all visible in stderr
  • ✅ The initialize JSON-RPC response IS written to stdout (verified via manual shell pipe test)
  • ✅ Node.js-based MCP servers work fine (e.g., node_repl) — this is Python-specific
  • ❌ Codex's rmcp client never logs Service initialized as client for the Python server
  • ❌ Only node_repl gets Service initialized; the Python server is silently dropped

What steps can reproduce the bug?

  1. Configure a Python-based MCP server in ~/.codex/config.toml:
[mcp_servers.gdrive]
command = 'C:\path\to\python.exe'
args = ['-u', 'path/to/launcher.py']
startup_timeout_sec = 120
  1. The Python launcher imports FastMCP/MCP SDK and runs in stdio mode:
sys.argv = ['workspace-mcp', '--tools', 'drive', '--transport', 'stdio']
from main import main
main()
  1. Start Codex (Desktop or codex exec)
  1. Observe:
  • Server stderr shows successful startup (tools loaded, auth configured)
  • Service initialized as client is logged for node_repl but NOT for the Python server
  • Error: handshaking with MCP server failed: connection closed: initialize response

Debug log output

Running with RUST_LOG=debug codex exec shows:

INFO codex_rmcp_client::stdio_server_launcher: MCP server stderr (python.exe): INFO:auth.google_auth:Using credentials directory...
INFO codex_rmcp_client::stdio_server_launcher: MCP server stderr (python.exe): [TOOLS] Tool tier 'core' loaded: 9 tools across 1 services [['drive']]
INFO codex_rmcp_client::stdio_server_launcher: MCP server stderr (python.exe): [REGISTRY] Tool filtering: removed 13 tools, 9 enabled. Mode: Read-Only
INFO serve_inner: rmcp::service: Service initialized as client peer_info=Some(InitializeResult { ... server_info: Implementation { name: "rmcp" ...})  ← only node_repl

WARN codex_mcp::rmcp_client: failed to initialize MCP client during shutdown: MCP startup failed: handshaking with MCP server failed: connection closed: initialize response

What was tried (all failed)

| Approach | Result |
|----------|--------|
| uvx workspace-mcp | Same — sandbox also blocks AppData |
| Direct workspace-mcp.exe (pip wrapper) | Same |
| python.exe -u + PYTHONUNBUFFERED=1 | Same |
| .bat wrapper around python | Same |
| cmd.exe /c python.exe | Same |
| Node.js wrapper spawning Python with stdio: inherit | Same |
| Python sys.stdout.reconfigure(line_buffering=True) | Same |

Root Cause Hypothesis

This appears to be a Windows pipe compatibility issue between Python's stdout and Codex's Rust MCP client (rmcp). The MCP SDK's stdio writer (mcp/server/stdio.py) uses:

stdout = anyio.wrap_file(TextIOWrapper(sys.stdout.buffer, encoding="utf-8"))
# ...
await stdout.write(json + "\n")
await stdout.flush()

On Windows, Python's sys.stdout.buffer may not properly flush to the pipe created by Codex's Rust process, even with PYTHONUNBUFFERED=1 and -u. The anyio async wrapper adds another layer of buffering.

This is related to #7155 (Windows stderr MCP issue) and #24439 (diagnostic command request), but specifically affects Python stdout to Rust stdin pipe on Windows during the initial handshake.

Node.js-based MCP servers don't have this issue because Node handles Windows pipes differently.

Workaround

Use a direct CLI script (shell command) instead of MCP — Codex calls Python via codex exec shell tool, bypassing the MCP protocol entirely. This works but loses MCP's benefits (tool auto-discovery, persistent connection, etc.).

Expected behavior

Python stdio MCP servers should complete the handshake on Windows, same as Node.js servers.

Related issues

  • #7155 — Windows stderr MCP Transport closed (same rmcp client, stderr blocking)
  • #24439 — Request for codex mcp check diagnostic command
  • #6020 — Broad initialize response failures (42 comments)
  • #3510 — MCP servers not working on Windows (closed)

View original on GitHub ↗

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