Codex Desktop receives MCP startup failures but silently omits plugin tools
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
Codex Desktop receives MCP startup failure events but silently omits plugin tools
What version of the Codex App are you using?
26.825.51511 (build 7377), bundled codex-cli 0.151.0-alpha.7.2
What subscription do you have?
Authenticated ChatGPT subscription; the exact tier is not material to the reproduction.
What platform is your computer?
Darwin 27.0.0 arm64 arm
What issue are you seeing?
When an enabled local plugin's stdio MCP process exits before completing the initialize handshake, Codex Desktop silently omits that server and all of its tools from the task. The task UI does not show the launcher error, a failed-plugin state, or a recovery action.
In the reproduced case, the launcher wrote a stable diagnostic to stderr and exited. Local Codex logs then showed all of the following:
- the launcher stderr diagnostic was captured;
mcpServer/startupStatus/updatednotifications were emitted to connected app clients;- the tool catalog omitted the server because there was no exact ready client;
- the task UI displayed none of this and the model received none of the plugin tools.
The current desktop bundle contains a handler that logs mcpServer/startupStatus/updated, including status, error, failureReason, threadId, and server name. The notification is therefore reaching the desktop boundary, but a generic failed plugin server does not become a durable, user-visible task warning.
This is distinct from a server that completes the handshake but whose tools are later filtered. The failure occurs before initialize, and Codex already has the failure information.
The reproduction does not depend on a specific private plugin: any minimal stdio MCP launcher that writes a diagnostic and exits before initialize should exercise the same boundary. No private plugin source, account data, or user content is required.
What steps can reproduce the bug?
- Install and enable a local plugin with a stdio MCP server.
- Make the plugin launcher print a stable error to stderr and exit non-zero before returning an MCP
initializeresponse. - Start a fresh Codex Desktop task in a project where the plugin is enabled.
- Observe the task UI and the model-visible tool list.
- Inspect Codex logs.
Actual result:
- the plugin appears enabled;
- its tools are absent;
- the task UI shows no startup failure;
- logs contain the launcher stderr diagnostic and outgoing
mcpServer/startupStatus/updatedevents; - the tool catalog records that the server is omitted because no ready client exists.
What is the expected behavior?
Codex Desktop should retain and display a per-thread, per-server failed state whenever an enabled MCP server fails startup. The warning should include:
- plugin and server name;
- a bounded, sanitized error summary;
- classified failure reason when available;
- actions to retry startup and open diagnostics.
Tool omission should not be the only user-visible signal.
Additional information
The public app-server protocol already exposes the necessary notification:
McpServerStatusUpdatedNotificationincludesthread_id,name,status,error, andfailure_reason;- the TUI already converts failed startup notifications into visible warnings;
- app-server integration coverage already verifies a failed optional stdio server produces
mcpServer/startupStatus/updatedwith an error.
Relevant existing reports include:
- https://github.com/openai/codex/issues/4176 — silent exclusion after MCP tool conversion errors; closed by a schema-conversion fix, but it established that silent omission is harmful;
- https://github.com/openai/codex/issues/32447 — CLI visibly reports MCP startup failures, showing the expected failure-surfacing behavior;
- https://github.com/openai/codex/issues/34321 — an enabled plugin can contribute no capabilities while status remains apparently healthy.
Suggested implementation direction
Desktop renderer:
- Subscribe to generic
mcpServer/startupStatus/updatednotifications for every server, not only special built-in servers. - Keep a state map keyed by
(hostId, threadId, serverName). - On
failed, render a deduplicated persistent warning in the affected task and invalidate the MCP status query. - On
ready, clear the warning or mark it recovered. - Truncate and sanitize stderr-derived error text before display.
Public app-server follow-up suitable for a small PR:
- Extend
McpServerStatuswith optionalstartup_errorandstartup_failure_reasonfields. - Preserve the latest
StartupOutcomeErrorin the read-only connection-status snapshot instead of collapsing it to theFailedenum alone. - Return those fields from
mcpServer/listso clients can reconstruct the failed state after a reload or a missed notification. - Add an app-server integration test asserting that a broken optional stdio server is listed as failed with its bounded error text.
The renderer change is likely maintained outside the public openai/codex repository, but the persistent app-server status enhancement is independently PR-able and would make every client more robust.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the public app-server entry points for McpServerStatus, StartupOutcomeError, mcpServer/list, and the mcpServer/startupStatus/updated notification; inspect the existing integration coverage for failed optional stdio servers. Trace how the read-only connection-status snapshot represents startup failures. Done means failed servers retain bounded error details in mcpServer/list and the integration test verifies them after startup failure.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api, backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100