CLI session loses stdio MCP connections after initial successful calls; fresh codex exec still works

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

Summary

In a long-lived Codex CLI session, stdio MCP servers can work initially and then permanently degrade to Transport closed for the rest of that session.

The key detail is that the servers themselves still appear healthy: repeated fresh codex exec subprocesses on the same machine continue to use the same MCP servers successfully while the original interactive session remains broken.

I reproduced this on 2026-04-06 with:

  • Codex CLI 0.118.0
  • Linux / WSL2: Linux SimonRy9 6.6.87.2-microsoft-standard-WSL2 x86_64
  • MCP servers: vault_search and repo_search (both stdio Python servers)

Reproduction

  1. Start a fresh interactive Codex CLI session.
  2. Run a first burst of MCP calls in the session. In my case these all succeeded:
  • vault_search.vault_coverage
  • repo_search.repo_coverage
  • vault_search.vault_search(query="Prompting")
  • repo_search.repo_search(query="Prompting")
  1. Run a second burst of MCP calls in the same session.
  2. Observe that both MCP servers now fail with Transport closed.
  3. Try even simpler MCP operations like resource listing in the same session.
  4. Observe that those fail too.
  5. In parallel, run fresh codex exec subprocesses that use the same MCP servers.
  6. Observe that the fresh subprocesses continue to succeed repeatedly.

Expected

If the MCP servers are healthy, the existing interactive session should continue to use them successfully, or Codex should automatically reconnect / recover the MCP transport.

Actual

The interactive session enters a persistent broken state for MCP usage:

  • vault_search.vault_coverage -> Transport closed
  • repo_search.repo_search(...) -> Transport closed
  • list_mcp_resources(server="vault_search") -> Transport closed
  • list_mcp_resources(server="repo_search") -> Transport closed

At the same time, fresh codex exec subprocesses on the same machine still succeed with the same servers.

That suggests the problem is in the MCP client / session connection state of the long-lived interactive session, not in the MCP server process itself.

Why this seems like a Codex-side session bug

  • Two different stdio MCP servers fail together in the same session.
  • The failures persist for the remainder of that session.
  • Fresh codex exec subprocesses repeatedly succeed against the same servers.
  • No server config changes were made between the successful and failing calls.

Additional notes

  • The same pattern reproduced again after restarting the Codex session: first MCP burst succeeded, second burst failed.
  • This was not limited to one server or one MCP tool. It also affected resources/list.
  • I also ran repeated fresh-process probes over time and they stayed green while the interactive session stayed broken.

Fresh-process control probe

I ran repeated fresh-process probes that call:

  • vault_coverage
  • repo_search with query Prompting

All control probes succeeded while the interactive session remained broken.

Example aggregate result from the local probe log:

  • 7/7 successful fresh-process MCP runs
  • max duration about 25.449s
  • classifications: only ok

Suggested investigation areas

  • MCP transport lifecycle in long-lived interactive CLI sessions
  • stdio MCP connection reuse across multiple tool bursts
  • whether one failed/closed connection poisons other MCP client handles in the same session
  • whether MCP resource-list calls and tool calls share a broken session-level connection pool

View original on GitHub ↗

7 Comments

github-actions[bot] contributor · 3 months ago

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

  • #15508
  • #15365
  • #15267

Powered by Codex Action

simfor99 · 3 months ago

Validated a local workaround on 2026-04-06.

Workaround:

  • bypass the broken interactive-session MCP transport entirely
  • call the local search implementations directly via a wrapper script instead of mcp__vault_search__... / mcp__repo_search__...

Local wrapper paths:

  • scripts/mcp-search
  • scripts/mcp_search_workaround.py
  • periodic probe: scripts/debug/mcp_workaround_probe.py

What this does:

  • uses the Sanctum venv Python directly
  • loads the local Vault/Repo search server wrappers and calls their search / coverage functions without going through the long-lived Codex MCP session transport

Validation:

  • 3 iterations
  • 180-second interval between iterations
  • 4 probes per iteration: vault_search, repo_search, vault_coverage, repo_coverage
  • result: 12/12 successful runs, 0 failures
  • max probe duration: 5.791s

Relevant local log:

  • tmp/logs/mcp-workaround-probe.jsonl

This does not fix the Codex bug itself, but it does confirm that the underlying search implementations remain healthy and usable while the interactive session MCP transport is degraded to Transport closed.

simfor99 · 3 months ago

I reviewed the suggested duplicates.

My take:

  • #15508 is the closest related issue, because it is also about existing sessions losing MCP usability while fresh sessions still work.
  • #15365 does not look like a duplicate: that one is macOS desktop Browser MCP failing on brand new threads, while this report is about Codex CLI and two non-browser stdio MCP servers that work initially and then fail later in the same live session.
  • #15267 also does not look like a duplicate: that one is about desktop thread/tool availability after MCP auth state changes, not a persistent Transport closed state in an already-working CLI session.

I am leaving this issue open for now because the distinguishing details here are:

  • Codex CLI, not desktop/app-only
  • two separate stdio MCP servers (vault_search and repo_search) fail together
  • the first MCP burst in-session succeeds, then the session degrades to Transport closed
  • repeated fresh codex exec control probes remain healthy on the same machine

If maintainers believe #15508 already fully covers the CLI/session-transport variant too, I am happy to close this as a duplicate of #15508.

brendannoble · 3 months ago

I’m seeing a similar pattern here with context-mode as the stdio MCP server.

What I observed locally:

  • context-mode is configured as a stdio MCP server in my Codex config
  • context-mode --version reports v1.0.75
  • the server was not failing at startup; it was usable earlier in the same interactive Codex session
  • later in that same session, a ctx_batch_execute MCP tool call failed with:

tool call failed for context-mode/ctx_batch_execute
Caused by: Transport closed

The main reason I’m adding this here is that it does not look like a pure initialize/handshake failure. In my case, the MCP had already worked earlier in the session, and then a later tool call failed with Transport closed.

That feels directionally similar to the failure mode described in this issue: a long-lived interactive session gets into a bad MCP transport state even though the problem is not just “server never started.”

I’m also looking at a potentially related context-mode issue on their side:

  • mksglu/context-mode#236

I’m not claiming root cause yet, only that I’m seeing the same client-visible symptom class from Codex:

  • stdio MCP works initially
  • later call fails with Transport closed
simfor99 · 2 months ago

Still reproducible on 2026-04-22 with codex-cli 0.122.0 on Linux/WSL2.

I hit the same failure mode again today with our stdio Python MCPs, especially vault_search (and also repo_search in the same session):

  • in a long-lived interactive CLI session, MCP calls worked initially and then degraded to persistent Transport closed
  • once the session entered that state, even simple MCP operations like resource access/listing failed for the rest of the session
  • the server itself does not look like the root cause here: the same machine still succeeds with a fresh subprocess probe

Current evidence from ~/.codex/log/codex-tui.log on 2026-04-22:

  • read_mcp_resource {"server":"vault_search","uri":"config://info"} -> Transport closed
  • list_mcp_resources {"server":"vault_search"} -> Transport closed
  • mcp__vault_search__vault_search {...} -> Transport closed
  • the same interactive session also later showed repo_search MCP calls failing with Transport closed

Fresh-process control probe on the same machine is still green:

  • I ran a fresh codex exec subprocess today and asked it to call vault_search.vault_coverage exactly once
  • result: RESULT: OK

So #16899 does not appear to be fixed in 0.122.0. This still looks like a Codex-side MCP transport/session lifecycle bug in long-lived interactive CLI sessions, not a bug in the MCP server implementation itself.

A short-term mitigation might be to route affected FastMCP servers over local Streamable HTTP instead of stdio, but that is only a workaround. The actual product fix still seems to be needed on the Codex side: the CLI should either keep these MCP transports healthy across turns or automatically reconnect/recover instead of poisoning the rest of the session after the first break.

Please prioritize a real fix here. For MCP-heavy workflows, the current behavior makes the interactive CLI unreliable.

simfor99 · 2 months ago

Follow-up with a working local mitigation / workaround.

I was able to stop the recurring MCP breakage for our local Python MCPs by moving them off stdio and onto local Streamable HTTP endpoints.

What worked here on 2026-04-22:

  1. Keep the same FastMCP server implementation, but start it with transport="streamable-http" instead of stdio.
  2. Run each MCP as a long-lived local user service (systemd --user in my case).
  3. Point Codex at the local MCP URL instead of command / args in ~/.codex/config.toml.
  4. Restart the Codex session so it reloads the MCP registry.

Example config pattern:

[mcp_servers.vault_search]
url = "http://127.0.0.1:8765/mcp"
startup_timeout_sec = 20
tool_timeout_sec = 45

[mcp_servers.repo_search]
url = "http://127.0.0.1:8766/mcp"
startup_timeout_sec = 20
tool_timeout_sec = 180

[mcp_servers.windows-search]
url = "http://127.0.0.1:8767/mcp"
startup_timeout_sec = 20
tool_timeout_sec = 180

Example service pattern:

[Service]
ExecStart=/home/simon/.venvs/sanctum/bin/python3 /path/to/server.py --transport streamable-http --host 127.0.0.1 --port 8765 --streamable-http-path /mcp
Restart=always
RestartSec=2

Results on my side after switching to local Streamable HTTP:

  • vault_search: stable, verified with repeated live searches in fresh Codex sessions
  • windows-search: stable, verified with live searches
  • repo_search: MCP transport is stable and repo_coverage works; I still see a separate search/index-recall issue on my current repo index, but that appears independent from the Codex MCP transport problem

So the original Codex bug still matters: long-lived stdio MCP sessions were the thing poisoning the interactive CLI for us. But if someone is blocked right now and their server already supports FastMCP HTTP transport, switching the local MCP from stdio to Streamable HTTP is a practical workaround.

simfor99 · 2 months ago

Follow-up after applying the workaround locally.

I was able to get all three local Python MCPs (vault_search, repo_search, windows-search) working reliably in Codex by moving them from stdio to local Streamable HTTP endpoints and running them as long-lived user services.

What I changed:

  • start each FastMCP server with --transport streamable-http --host 127.0.0.1 --port <port> --streamable-http-path /mcp
  • run each one via a local user service (systemd --user on my machine)
  • point Codex at url = "http://127.0.0.1:<port>/mcp" instead of command/args
  • raise tool_timeout_sec for heavier MCPs and increase startup_timeout_sec for repo_search

Example config.toml pattern:

[mcp_servers.vault_search]
url = "http://127.0.0.1:8765/mcp"
startup_timeout_sec = 20
tool_timeout_sec = 45

[mcp_servers.repo_search]
url = "http://127.0.0.1:8766/mcp"
startup_timeout_sec = 60
tool_timeout_sec = 180

[mcp_servers.windows-search]
url = "http://127.0.0.1:8767/mcp"
startup_timeout_sec = 60
tool_timeout_sec = 180

One extra bug I found while fixing repo_search:

  • the repo index metadata claimed chunks existed, but the actual LanceDB table was missing
  • that made repo_search look superficially healthy while every real search returned no hits
  • I patched my local repo_search implementation to detect metadata exists but table missing and force a rebuild instead of incorrectly returning up_to_date
  • I also changed the reindex path from an all-in-memory build to batch flushing, because the old path could balloon to ~14 GB RAM and wedge the service

Current result on my side:

  • vault_search: working with real searches
  • windows-search: working with real searches
  • repo_search: working again with real docs/code searches after the rebuild fix

So the product bug still matters: Codex interactive sessions and local stdio MCPs were not stable enough for this workflow. But for anyone blocked today, local Streamable HTTP MCP + a persistent local service is a viable workaround.