Leader footer can stay stuck on child-session MCP startup (for example `starting omx_state MCP`)
What version of Codex CLI is running?
codex-cli 0.120.0
What subscription do you have?
Redacted for privacy. I can provide it privately if needed.
Which model were you using?
gpt-5.4
What platform is your computer?
Darwin 24.6.0 arm64 arm
What terminal emulator and version are you using (if applicable)?
A macOS terminal emulator inside tmux 3.6a
What issue are you seeing?
The foreground leader footer can keep showing a child-session MCP startup state (for example starting omx_state MCP) for the entire lifetime of background subagent work.
This does not look like raw omx_state startup slowness. I measured omx_state cold-connect locally over stdio at roughly 100-160 ms, which is far shorter than the time the footer can remain in the "starting ... MCP" state.
So the bug appears to be closer to footer status attribution / cleanup for background child sessions than to actual MCP startup duration.
Related but not identical to existing reports such as #16821 and #12976: in my case the key symptom is that the leader footer stays visually stuck on child MCP startup even while child tasks are already running normally.
I am intentionally omitting screenshots, thread IDs, local file paths, usernames, and workspace-specific prompts for privacy.
What steps can reproduce the bug?
- Configure a few lightweight stdio MCP servers, including
omx_state. - Start a normal interactive Codex CLI leader session.
- From that leader session, spawn multiple background child sessions (native subagents;
omx teamworkers can trigger a similar pattern). - Watch the leader footer while the child sessions initialize.
- The leader footer can continue to show a child MCP startup indicator such as
starting omx_state MCPuntil all background tasks finish.
Important detail: the background work itself often proceeds normally, so the footer state appears stale or incorrectly attributed rather than accurately representing a still-pending MCP startup.
What is the expected behavior?
- The leader footer should only show MCP startup state for the foreground leader session itself, or clearly scope any child-session state to the child.
- Once a child session finishes its MCP handshake/startup, the leader footer should clear that startup indicator promptly.
- A lightweight MCP such as
omx_stateshould not appear to be starting for the entire duration of unrelated background task execution.
Additional information
A few observations that may help narrow the issue:
- Child sessions appear to initialize their own MCP managers rather than reusing the leader's live MCP connections.
- The persistent footer state seems decoupled from the actual cold-connect time of
omx_state. - This looks like a TUI/session-status scoping problem on top of normal child-session MCP lifecycle behavior.
- I intentionally redacted any identifiers that could expose local paths, repo names, usernames, or private session metadata.
3 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Sub-agent
McpConnectionManagerstartup events leak into the leader TUI's status header becauseMcpServerStatusUpdatednotifications carry no thread identity and are routed asGlobal, which falls through to the leader'schat_widgetand overwrites itsmcp_startup_statusmap. Reproducible on codex-cli 0.128.0; same root cause as #16821 and #19542.Causal chain (verified against
main)McpConnectionManager.codex-rs/core/src/session/session.rs:986-1006- sub-agent sessions build their own manager and emit a freshStarting->Readysequence for every configured server, every time a sub-agent spawns.McpServerStatusUpdatedcarries nothread_id.codex-rs/tui/src/app/app_server_event_targets.rs:144returnsNonefor this notification variant, so the router classifies it asGlobal.Globalnotifications fall through to the leader'schat_widget.codex-rs/tui/src/app/app_server_events.rs:135-139- theGlobalmatch arm is a no-op with noreturn, so execution continues intoself.chat_widget.handle_server_notification(...)regardless of which session emitted the event.mcp_startup_statusmap is overwritten by child events.codex-rs/tui/src/chatwidget/mcp_startup.rs:81-85doesstartup_status.insert(server, status)unconditionally, so a sub-agent'sStartingfor a server the leader already has asReadyflips the leader's view back toStarting.Startingstate.codex-rs/tui/src/chatwidget/mcp_startup.rs:102-127- while sub-agents keep re-emittingStarting, the settle condition never passes, and the spinner remains up indefinitely.The leader has no way to filter these events because they carry no session or thread identity to filter by.
Reproduction
bearer_token_env_var(e.g. context7 againsthttps://mcp.context7.com/mcp)spawn_agentStarting MCP servers (X/N): <name>indefinitely while sub-agents are activecodex execis unaffected - no TUI, no spinner to wedgeStartingset; the underlying mechanism is server-agnostic, which is why #16821 reportsomx_stateand #19542 reports "the last MCP" on different setupsCross-references
omx_stateBoth are the same root cause as this issue. The reporter here framed it correctly as a "TUI/session-status scoping problem".
Suggested fix direction
The minimal patch lives in the routing layer, not the TUI:
thread_idfield toServerNotification::McpServerStatusUpdated, carried through from the emittingMcpConnectionManager.app_server_event_targets.rs, classifyMcpServerStatusUpdatedwith a non-leaderthread_idasThread(thread_id)rather thanGlobal.mcp_startup_statusaccounting inchatwidget/mcp_startup.rsto events fromprimary_thread_idonly.This preserves the leader spinner for the leader's own MCP lifecycle while preventing sub-agent lifecycle events from cross-contaminating it. Sub-agent MCP status can still be surfaced separately if desired, but it should not mutate the leader's map.
Here's a patch 🩹