Codex CLI MCP startup fails for local stdio server even though manual initialize succeeds

Open 💬 2 comments Opened Apr 7, 2026 by zdenda-balcar-clevertify
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of Codex CLI is running?

codex-cli 0.118.0

What subscription do you have?

Business

Which model were you using?

gpt-5.4

What platform is your computer?

Linux 6.6.87.2-microsoft-standard-WSL2 x86_64 x86_64

What terminal emulator and version are you using (if applicable)?

Linux terminal emulator (bash shell)

What issue are you seeing?

Codex CLI fails to complete MCP startup/handshake for a local stdio MCP server on Linux.

I tested a local Python MCP server that is launched successfully by Codex. The server starts, completes its own
initialization quickly, and is able to respond correctly to a manual MCP initialize request over stdio outside Codex.

However, when launched by Codex, startup fails with one of these errors:

``text
MCP client for
test-server timed out after 60 seconds. Add or adjust startup_timeout_sec` in your config.toml:
[mcp_servers.test-server]
startup_timeout_sec = XX

and in another variant:

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

I instrumented the server with simple startup logging. In the timeout case, the process is started by Codex and server
initialization completes, but no MCP request is ever received from Codex. In the handshake-failure case, Codex reports
handshake failure even though the same server responds correctly to manual initialize outside Codex.

What steps can reproduce the bug?

  1. Configure a local stdio MCP server in Codex.
  2. Start Codex in a Linux shell.
  3. Observe MCP startup failure.

I reproduced this with both:

  • project-scoped config in .codex/config.toml
  • global config via codex mcp add

Example project-scoped config:

```toml
[mcp_servers.test-server]
command = "my-mcp-server"
env_vars = ["SOME_REQUIRED_ENV"]
startup_timeout_sec = 60

I also reproduced it with a global wrapper-based registration.

Important observations:

  • the MCP server process starts successfully
  • the server completes startup quickly
  • the same server responds correctly to a manual stdio MCP initialize request
  • in the timeout case, Codex never appears to send any MCP message to the server
  • in the handshake-failure case, Codex reports connection closed: initialize response

Manual validation outside Codex:

  • manual stdio initialize request succeeds
  • tools/list succeeds

What is the expected behavior?

Codex should complete MCP startup successfully for a local stdio MCP server that starts correctly and responds to
initialize.

If the server process is launched successfully and the server can answer MCP requests, Codex should finish the handshake
and make the server available in the session.

Additional information

  • codex mcp list / codex mcp get show the MCP server as enabled.
  • The issue reproduces on Linux with codex-cli 0.118.0.
  • Manual stdio testing against the same server shows that the server returns a valid initialize response immediately.
  • This appears more likely to be a Codex MCP client issue than a server startup issue, because the process launches

successfully and the server works when tested directly outside Codex.

I can provide:

  • MCP server startup logs
  • a minimal reproducible Python stdio MCP server if needed

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 4 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #16262
  • #16229
  • #16550

Powered by Codex Action

hanneslipusch · 3 months ago

Still reproduces on codex-cli 0.134.0 (Linux), via the OpenClaw app-server harness — adding fresh diagnostics

Same signature as the OP and #6020: a local stdio MCP server that answers a manual initialize handshake fine, but codex never makes its tools available, and the only diagnostic is a connection closed: initialize response error.

Environment

  • codex-cli 0.134.0 (bundled in OpenClaw's @openclaw/codex@2026.5.27 harness; launched as codex app-server --listen stdio://)
  • Linux 6.17 x86_64, Node 24.15
  • Two independent stdio MCP servers configured, both affected: @sentry/mcp-server and @notionhq/notion-mcp-server
  • Launch shape: command = "bash", args = ["/…/launcher.sh"], where launcher.sh resolves a token into the env and then execs the pinned MCP binary.

What works

  • Driven manually over stdio in codex's exact spawned environment (same PATH/HOME/TMPDIR/CREDENTIALS_DIRECTORY, via env -i), each launcher returns a valid initialize result + a full tools/list (22 tools) in ~0.85 s, exit 0.
  • The host harness records that it projected both servers to codex (its userMcpServersFingerprint for the thread contains both mcp_servers entries verbatim).

What codex does

  • The MCP servers' tools never appear in the session tool catalog.
  • There is no MCP-related log at session start — across a full ~30 min thread (start → shutdown) codex emits nothing about MCP init while the thread is live.
  • The only diagnostic is a WARN at thread shutdown, target codex_mcp::rmcp_client:

``
failed to initialize MCP client during shutdown: MCP startup failed:
handshaking with MCP server failed: connection closed: initialize response
`
and, in one instance, the lower-level variant:
`
failed to initialize MCP client during shutdown: MCP startup failed:
handshaking with MCP server failed: Send message error Transport
[codex_rmcp_client::stdio_server_launcher::StdioServerTransport]
error: Broken pipe (os error 32), when send initialize request
``

So the stdio child is spawned, but initialize is never successfully sent/answered — even though the same child answers initialize immediately when driven by hand in the identical environment. The "during shutdown" wording suggests init is attempted lazily / on the teardown path rather than at session start, which lines up with the OP's "codex never appears to send any MCP message to the server."

Possibly related

  • #6020 — same connection closed: initialize response string across many servers
  • #16229 — stdio launch via a wrapper/indirection vs a direct binary. In my case the server is launched through a bash wrapper that execs the real binary; happy to test a direct-binary launch if that would help isolate whether the wrapper indirection is the trigger.

I can also re-run against 0.135.0 — its #24667 adds connection_manager startup-snapshot breadcrumbs that should make the pending-init state visible in the trace — and paste the full codex_mcp::rmcp_client / rmcp::service span sequence if useful.