MCP startup should not block tool listing or thread startup

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

Summary

A configured MCP server that is still starting or unreachable can block core Codex workflows when the session builds the aggregated MCP tool list. This makes optional MCP extensions behave like startup-critical dependencies.

Root cause found locally

codex-mcp currently waits on pending MCP clients from McpConnectionManager::list_all_tools() through AsyncManagedClient::listed_tools(). When an MCP server is unreachable and has no startup tool cache, the first turn/tool-router construction can wait until MCP startup timeout instead of keeping chat usable.

Proposed fix

I have a local/fork branch that changes listed_tools() to skip clients that are still initializing and have no cached startup tools. Cached startup tools are still returned while initialization continues; once startup completes, tools are listed normally.

Branch:
https://github.com/caokaizz/codex/tree/codex/mcp-nonblocking-tool-list

Compare:
https://github.com/openai/codex/compare/main...caokaizz:codex:codex/mcp-nonblocking-tool-list

Commit:
9502ad125c Avoid blocking tool listing on MCP startup

Validation run locally

  • just test -p codex-mcp list_all_tools_skips_pending_client_without_cached_tool_info_snapshot
  • just test -p codex-mcp (88 passed)
  • just fmt
  • just fix -p codex-mcp

Note

I attempted to open a PR from the fork branch, but GitHub returned: caokaizz does not have the correct permissions to execute CreatePullRequest.

View original on GitHub ↗

5 Comments

github-actions[bot] contributor · 2 months ago

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

  • #28556
  • #28935

Powered by Codex Action

Necmttn · 2 months ago

MCP tool discovery should probably be a degraded capability inventory, not a hard pre-turn dependency.

Each server row can carry last successful tool manifest, manifest hash, started_at, freshness, startup status, and timeout/error reason. The router can use cached tools when fresh enough, omit unknown servers for the current turn, and surface MCP server pending in diagnostics.

---

_Generated with ax._

zyz23333 · 2 months ago

I hit what looks like the same issue today. Codex failed to start a new conversation, and removing one MCP server config made it work again.

This was hard to diagnose from the user side because the failure happened during conversation startup, and it was not obvious that an optional MCP server was blocking core Codex functionality.

tangweigang-jpg · 2 months ago

This failure mode is worth treating as a dependency-classification problem, not only a timeout problem.

For startup, I would separate MCP servers into three states:

  1. required and blocking, where the session cannot safely proceed without the server;
  2. optional but cached, where the last known tool surface can be shown with a stale/revalidating marker;
  3. optional and unavailable, where the thread should start normally and expose a visible warning.

The important edge case is the first turn. If an optional MCP server is slow or unreachable, the user still needs a usable chat and a clear diagnostic: which server blocked, how long it waited, whether cached tools were used, and whether the server will be retried in the background.

For the proposed skip-pending behavior, I would also make the event observable in logs/UI. Otherwise users may see a model ignore a tool and misdiagnose it as a planning problem when the real cause was that the server was still initializing or had no startup cache.

A useful acceptance test would be: configure one fast MCP server and one unreachable optional server, start a fresh session, and verify that core chat plus the fast server are usable before the unreachable server timeout expires. Then verify the unavailable server can become visible later without restarting the thread.

MugenLee · 1 month ago

+1, Pls fix it

This bug is stupid and wasting my token!