Skip to content

PR approval for 'Transport Closed' bug for MCP servers #35486

Open

Description

@welf

What version of Codex CLI is running?

0.125.0

What subscription do you have?

ChatGPT Pro 20x

Which model were you using?

all

What platform is your computer?

This bug is reproducible on all platforms

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

This bug is reproducible in all terminals

Codex doctor report

What issue are you seeing?

I investigated the #16899 issue and have a tested fix ready.

TLDR

Root cause: RmcpClient retains a closed RunningService in ClientState::Ready, so subsequent operations reuse the dead transport indefinitely. Fresh Codex processes work because they construct a new client and transport.

The proposed fix recreates and initializes the transport behind the existing recovery semaphore, shares one recovery across concurrent callers, never replays an interrupted tool call, preserves HTTP 404 retry behavior, and tracks replacement stdio processes for cleanup.

Validation: all 119 codex-rmcp-client tests pass, including new preclosed, concurrent recovery, no-replay, and process-cleanup regressions.

Tested commit: welf@bba585c

Would a Codex maintainer be willing to invite a PR for this approach?

Here is the full PR description:

Fixes #16899

Root cause

RmcpClient stores a successfully initialized service in ClientState::Ready. When the RMCP service task or underlying
transport closes, the stored state is not changed. Normal operations retrieve that Ready service without checking
whether it is still alive.

The RMCP dependency returns rmcp::service::ServiceError::TransportClosed, whose display text is Transport closed.
Codex returns that error but leaves the same closed service cached.

Prepared tool calls and resource clients retain the same Arc<RmcpClient>. Since transport closure does not mark the
MCP runtime dirty, the ordinary per-step dirty check does not rebuild the connection. Every subsequent operation
therefore calls the same closed service.

A new Codex process constructs a new McpRuntime, McpConnectionSet, ManagedClient, and RmcpClient, which explains
why fresh codex exec processes continue to work.

What

Recover an MCP client when its current transport has closed instead of leaving a long-lived Codex session permanently
attached to a dead RunningService.

  • Recreate and initialize the transport before the next operation when closure is already observable.
  • Serialize concurrent recovery attempts so callers share one replacement connection.
  • Recover eagerly after an in-flight operation reports TransportClosed, but return the original error and never replay
    the operation.
  • Track the active stdio process alongside the active service so shutdown cleans up a replacement server too.
  • Preserve the existing streamable HTTP 404 session-expiry behavior and its single operation retry.

Why

A persistent CLI session kept the original closed MCP service after a stdio server or transport exited. Every later tool
call therefore failed with Transport closed, while a fresh codex exec worked because it constructed a new client and
transport.

How

The client now uses its retained transport recipe and initialization context to rebuild the service behind the existing
recovery semaphore. Recovery atomically installs the replacement service, OAuth persistor, and stdio process handle.
Callers that arrive concurrently reuse a healthy replacement installed by the first recovery attempt.

Regression coverage verifies pre-closed recovery, single recovery under concurrency, no replay after an in-flight
tool-call closure, replacement stdio cleanup, and unchanged HTTP 404 retry semantics. The new recovery regressions were
confirmed to fail before the implementation.

Validation

  • just test -p codex-rmcp-client — 119 passed, 5 skipped
  • just argument-comment-lint -p codex-rmcp-client
  • just fix -p codex-rmcp-client
  • just fmt

Issue: #16899

What steps can reproduce the bug?

See implemented tests

What is the expected behavior?

After Transport Closed error MCP servers should continue to work

Additional information

No response

Activity

  1. added
    bugSomething isn't working
    on Jul 26, 2026
  2. added
    CLIIssues related to the Codex CLI
    mcpIssues related to the use of model context protocol (MCP) servers
    connectivityIssues involving networking or endpoint connectivity problems (disconnections)
    on Jul 26, 2026
  3. github-actions commented on Jul 26, 2026

    @github-actions
    Contributor

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

    Powered by Codex Action

  4. welf commented on Jul 27, 2026

    @welf
    Author

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

    It is the the fix of the mentioned bug, not the duplicated bug report.

  5. FlourishingHumanityCorporation commented on Sep 24, 2026

    @FlourishingHumanityCorporation

    Following up the evidence we posted on #16899 in July: this is still present in rust-v0.156.1 (b412ff3), on macOS arm64.

    A stdio MCP server that exits after initialize leaves the client unusable: the next list_tools returns Transport closed, and nothing respawns the server until the process restarts. We carried a private patch with the same design as the one proposed here (recover behind the existing semaphore, never replay an interrupted tool call, have shutdown own the replacement process). Its regression test, run against unpatched 0.156.1:

    test stdio_transport_recovers_in_place_and_shutdown_owns_replacement_process ... FAILED
    Error: Transport closed
    

    The test starts test_stdio_server with an env flag that makes it exit right after initialize, waits for is_closed(), then calls list_tools and call_tool("echo") and asserts they succeed on a replacement process with a new pid, and that shutdown() stops that replacement. Happy to share the test file if it helps land the fix.

    We would much prefer to run upstream than keep patching every release, so a maintainer decision on the approach in this issue would help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workingconnectivityIssues involving networking or endpoint connectivity problems (disconnections)mcpIssues related to the use of model context protocol (MCP) servers

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions