TUI falsely reports "MCP startup interrupted" for servers that did connect (startup status events are droppable; lag handler mislabels them as cancelled)
Summary
The TUI intermittently shows ⚠ MCP startup interrupted. The following servers were not initialized: … naming servers that did, in fact, initialize successfully. Running /mcp immediately afterwards shows every named server connected with its full tool list, and tool calls against them succeed. The warning is cosmetic, but it reads as a real failure and sends users off debugging healthy MCP servers.
Environment
- codex CLI v0.146.0 (latest release at time of writing), ChatGPT-account auth
- Linux (Ubuntu) server, TUI running inside tmux panes
- Two MCP servers: the built-in
codex_apps, plus one local streamable-HTTP server that answersinitializein ~3 ms (measured with curl)
Occurrence is stochastic: roughly half of TUI boots on this machine, sometimes naming both servers, sometimes one.
What we ruled out
- User input during startup (reproduces with zero keystrokes after launch)
- MCP server slowness (the local server's
initializeround-trip is ~3 ms;startup_timeout_sec = 30configured) - tmux client attached vs. detached (reproduces in both)
- Feature flags:
--disable appsand--disable skill_searchdo not change the occurrence rate
Root cause (from source, current main)
The TUI learns MCP startup state through the bounded in-process event channel, and MCP startup status notifications are in the best-effort (droppable) class:
codex-rs/app-server-client/src/lib.rs—forward_in_process_event: best-effort events are sent withtry_send; when the consumer queue is full they are dropped andskipped_eventsis incremented, later surfaced as aLaggedmarker. Only transcript deltas / item / turn completions are in the lossless class (event_requires_delivery).codex-rs/tui/src/app/app_server_events.rs—AppServerEvent::Lagged { skipped }→finish_mcp_startup_after_lag().codex-rs/tui/src/chatwidget/mcp_startup.rs—finish_mcp_startup_after_lagtreats every server whose status is stillStarting(or unknown) as cancelled and emits "MCP startup interrupted". But when the server'sReadynotification was among the dropped events, the server is connected and the TUI simply never heard about it — the warning then misreports a healthy server as not initialized.codex-rs/tui/src/lib.rs— the channel capacity is passed as the hardcodedDEFAULT_IN_PROCESS_CHANNEL_CAPACITY; there is no config or env override, so users cannot widen the channel to avoid the drop.
So: boot-time event burst overflows the channel → the MCP Ready notification is dropped as best-effort → Lagged fires → the lag handler assumes cancellation → false "interrupted" warning for connected servers.
Repro
- Configure at least one MCP server (a fast local HTTP server makes the point clearly — it cannot plausibly be "not initialized").
- Launch the TUI repeatedly in a tmux pane on a Linux box; touch nothing.
- On a fraction of boots the warning appears after startup. Run
/mcp: the named servers are connected with full tool lists.
Suggested fixes
Either (or both):
- Classify MCP startup status notifications as lossless in
event_requires_delivery— they are low-volume and load-bearing for what the startup UI reports; or - Have
finish_mcp_startup_after_lagre-query the actual server/connection state before reporting, instead of assuming any status it didn't witness means cancellation. The information is available —/mcpshows the true state seconds later.
Happy to provide more environment detail if useful.
6 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Can confirm this root cause independently — traced the same path (
app_server_events.rs→finish_mcp_startup_after_lag→mcp_startup.rs) on macOS, codex CLI v0.146.0,lm_studioprovider (local model,qwen/qwen3.6-35b-a3bvia LM Studio), 4 MCP servers (codex_apps,local_files,node_repl,playwright).One addition to the analysis: in our setup the divergence was not always cosmetic. We inspected the raw HTTP request payload sent to the model provider (via
~/.codex/logs_2.sqlite,codex_http_client::transporttarget) across several repro attempts:toolsarray in the request did contain the full MCP tool set (e.g. allbrowser_*tools fromplaywright) — consistent with this issue's "cosmetic" framing./mcpshowing full connectivity, where the model still failed to have/use the expected tools in practice. We haven't fully isolated whether that specific case was a model-behavior issue (small local model ignoring available tools) or a second, rarer instance of the same snapshot-staleness problem — flagging here in case it's a related edge of the same root cause (tool-list snapshot taken for the sampling request vs. the/mcplive status query use different code paths / timing).Tried both suggested config-side mitigations first (before finding this issue): switching
npx -y ...@latestMCP servers to pre-installed global binaries (removes ~1-2s npx overhead) and settingrequired = true+ higherstartup_timeout_secper server. Neither eliminates the banner, which matches this issue's finding that it's a channel/event-drop problem, not a startup-timing/timeout problem —required/startup_timeout_secaddress a different failure class entirely.+1 on both suggested fixes, especially reclassifying MCP startup status notifications as lossless — they're low-frequency and directly load-bearing for a correctness-relevant UI signal, unlike high-volume streaming deltas where drop-on-backpressure makes sense.
I can confirm this on Codex CLI 0.146.0 using the built-in OpenAI provider and ChatGPT authentication on Windows WSL.
The logs show a particularly clear ordering:
10:31:27.Service initialized as clientby10:31:31.397.10:31:32.604, Codex loggedtask cancelledfor all six servers together.Therefore, the grouped cancellation happened after successful initialization. The banner named the same six servers that had already initialized.
A subsequent startup initialized all six normally within approximately 3.4 seconds. I also found no MCP startup-timeout events in the preceding 48 hours. This appears consistent with the startup-status event loss/stale TUI state described here, rather than server slowness or independent MCP failures. It also reproduces with the built-in provider.
I can provide sanitized
logs_2.sqliteexcerpts if useful.Confirmed on macOS arm64 with Codex CLI 0.146.0. codex_apps successfully initialized according to logs_2.sqlite, but
the TUI still displayed MCP startup interrupted.
Adding this to ~/.codex/config.toml consistently eliminated the warning across clean launches:
[features]
plugins = false
Built-in Apps remained enabled and codex_apps started successfully:
apps stable true
plugins stable false
Re-enabling plugins reproduced the warning. This is only a workaround because it disables plugin bundles and their
skills/integrations, but it may help isolate the startup event or plugin-loading race.
Additional confirmation from a mixed-transport setup, with one possible reproduction signal:
This appears transport-independent and consistent with the false TUI state described in the issue.
I can reproduce this on Ubuntu 22.04 under WSL2.
With Codex CLI 0.146.0 and 0.147.0, affected runs show both
codex_appsandopenaiDeveloperDocsreachingService initialized as client. A few seconds later, both are logged astask cancelled/serve finishedwithquit_reason=Cancelled. The TUI then shows the “MCP startup interrupted” warning. However,/mcpstill lists the servers’ tools and the thread remains usable.A controlled version comparison points to the CLI MCP lifecycle rather than the provider or profile configuration:
This looks consistent with successful MCP initialization being followed by cancellation or stale startup-status handling, rather than an MCP handshake failure. See also #37418 for the 0.147.0 report.