Skip to content

macOS: stdio MCP tool calls can fail with raw Transport closed even when the underlying operation is healthy #18977

@alario-tang

Description

@alario-tang

Summary

On macOS, stdio MCP servers can fail with Transport closed even when the server logic itself is healthy and the same operation succeeds via a non-MCP parity path.

What looks wrong from the outside is that Codex's MCP host/transport lifecycle seems able to drop or replace the stdio connection in a way that leaves the tool call with a stale/closed transport handle.

In my case this showed up with local OMX MCP servers (omx_state, etc.), but the evidence suggests the more general problem is on the Codex MCP host/stdio lifecycle side, not in the specific state logic.

What version of Codex is running?

codex-cli 0.122.0

What subscription do you have?

Pro

Which model were you using?

Observed inside Codex App / Codex CLI session; model choice does not seem relevant to the failure.

What platform is your computer?

macOS (Apple Silicon)

What issue are you seeing?

Intermittent MCP tool failures like:

tool call error: tool call failed for `omx_state/state_write`

Caused by:
    Transport closed

Key observations:

  1. omx doctor reports the environment is healthy.
  2. codex mcp list shows the OMX MCP servers are enabled.
  3. The same state operations succeed via CLI parity:
    • omx state write ...
    • omx state read ...
  4. So the state logic itself is healthy; the failure is specific to the MCP tool transport path.

I also locally verified that the OMX stdio MCP server exits immediately when stdin/transport is closed, which means Codex-side transport churn can surface directly as Transport closed.

What steps can reproduce the bug?

I do not yet have a minimal reproduction using a public MCP server, but here is the concrete local evidence path:

  1. Run a Codex session with stdio MCP servers configured.
  2. Use MCP tools successfully for a while.
  3. Later in the same long-running session, a tool call may fail with Transport closed.
  4. The same operation still succeeds immediately via a direct CLI parity command outside the MCP tool path.

Additional local debugging:

  • The OMX MCP server uses StdioServerTransport and shuts down on:
    • stdin_end
    • stdin_close
    • transport_close
    • parent_gone
  • With OMX_MCP_TRANSPORT_DEBUG=1, manually closing stdin reproduces a clean server shutdown with:
[omx-state-server] transport shutdown: stdin_end
[omx-state-server] transport shutdown: exit

This does not prove Codex is always at fault, but it does show that if Codex drops/replaces the stdio transport, the MCP server will terminate and the tool call will surface as Transport closed.

What is the expected behavior?

For stdio MCP servers:

  1. Codex should avoid exposing stale/closed transport handles to tool calls where possible.
  2. If the host has restarted/replaced the MCP client process, Codex should reconnect/retry rather than surfacing a raw Transport closed immediately.
  3. At minimum, the error should distinguish between:
    • server exited intentionally
    • host transport was closed/replaced
    • handshake/startup failure
    • tool execution failed after a healthy connection

Why I think this is a Codex-side issue

Because the exact same logical operation succeeds through CLI parity using the same underlying handler, which strongly suggests:

  • the underlying operation is fine
  • the failure is in the MCP host/client transport lifecycle

Related but not identical issues

This report is different: it is about macOS stdio MCP lifecycle robustness and stale transport closure surfacing as raw Transport closed during otherwise healthy local tool usage.

Additional information

If helpful, I can provide a more minimal reproduction, but I wanted to file this first because the pattern seems broader than the specific OMX tool.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmcpIssues related to the use of model context protocol (MCP) servers

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions