Skip to content

Retry failed Codex Apps MCP startup - #29920

Merged
kbazzi merged 9 commits into
mainfrom
codex/apps-mcp-startup-retry
Jun 26, 2026
Merged

Retry failed Codex Apps MCP startup#29920
kbazzi merged 9 commits into
mainfrom
codex/apps-mcp-startup-retry

Conversation

@kbazzi

@kbazzi kbazzi commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Problem

The built-in Codex Apps MCP client shares a future for the full startup operation: connect, complete initialize, fetch the initial tools, and return a usable client. Sharing deduplicates startup work, but it also memoizes terminal errors.

After a transient connection, handshake, or initial tools/list failure, later tool builds observe the same failed future. The thread cannot reconnect after the backend recovers and continues serving its startup-time cached tool snapshot, which may be empty or stale.

Fix

When Apps MCP startup ends in an error, Codex starts bounded recovery without putting startup latency on tool-router construction:

  1. The current tool build immediately continues with the cached startup snapshot.
  2. After the initial failure is reported, Codex starts one fresh full startup attempt in the background.
  3. Concurrent tool builds share that in-flight attempt and also continue with cached tools.
  4. On success, the recovered client becomes active, refreshes the Apps tools cache, emits a Ready startup status, and is reused by later operations.
  5. On failure, the cache remains unchanged and later tool builds may start another background attempt after exponential cooldown: 1s, 2s, 4s, 8s, 16s, then 30s maximum.

Each recreated startup performs a fresh MCP initialize and uncached tools/list. The MCP client retains its existing bounded retries for retryable initialize and tools/list failures.

This avoids adding the Apps startup timeout to every request during a sustained outage.

Scope

This is limited to the built-in Codex Apps MCP client:

  • no reconnects for user-configured MCP servers;
  • no cache deletion; and
  • no proactive refresh for a healthy client with stale tools.

Tests

Coverage verifies:

  • tool builds return cached tools without waiting for a blocked reconnect;
  • concurrent tool builds start only one background reconnect;
  • failed reconnects preserve cached tools and respect exponential cooldown;
  • a recovered client is retained and reused; and
  • a long-lived thread exposes recovered app tools on a later follow-up.

Validation:

  • just test -p codex-mcp — 95 passed
  • just test -p codex-core later_follow_up_uses_background_recovered_apps_after_mid_thread_startup_failures --no-capture — passed
  • just fix -p codex-mcp
  • just fmt

@kbazzi
kbazzi marked this pull request as ready for review June 25, 2026 05:55
@kbazzi
kbazzi requested a review from a team as a code owner June 25, 2026 05:55

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1c2e1abb3e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +404 to +405
if !self.startup_complete.load(Ordering::Acquire) {
return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retry Apps startup failures observed during listing

When Apps startup is still in flight at the beginning of a tool-list build and then fails before listed_tools() awaits or observes it, this early return skips the reconnect path; listed_tools() then falls back to cached/no tools on the failed original future, so that request can still go to the model without recovered Apps tools and only a later turn retries. This makes the new recovery race-dependent after refresh or any slow transient failure; trigger the reconnect after the awaited startup returns Failed, not only when startup_complete was already true before listing.

Useful? React with 👍 / 👎.

@mzeng-openai

Copy link
Copy Markdown
Contributor

Thank you! One high-level q: If it's a sustained outage like the sev, do we reconnect every turn? that could mean 30s added to every turn

Comment thread codex-rs/codex-mcp/src/rmcp_client.rs Outdated
.unwrap_or_else(std::sync::PoisonError::into_inner);
state.reconnect_in_flight = false;
match result {
Ok(client) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to emit a Ready startup status when the background reconnect succeeds? Otherwise app-server clients may keep showing the server as failed even though the recovered client is active.

kbazzi added 2 commits June 25, 2026 14:32
…p-retry

# Conflicts:
#	codex-rs/codex-mcp/src/connection_manager.rs
#	codex-rs/codex-mcp/src/connection_manager_tests.rs
#	codex-rs/codex-mcp/src/rmcp_client.rs
@kbazzi

kbazzi commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@kbazzi
kbazzi merged commit 92d2e1d into main Jun 26, 2026
31 checks passed
@kbazzi
kbazzi deleted the codex/apps-mcp-startup-retry branch June 26, 2026 04:31
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants