fix(server): MCP app cards work again after a restart unloads their Codex thread#29497
Problem
After T3's server restarts, an MCP app card in an older Codex thread stops working once another Codex thread has brought the shared Codex app-server back: clicking it shows "Not saved: The app's MCP server request failed." The restarted app-server has not loaded that conversation, so mcpServerStatus/list and mcpServer/tool/call fail with -32600 thread not found.
Reproduced on main (edc37c96c8) in the web dev server with the reporter's sample rating server and Codex 0.163.0: show the card in thread A and save a rating, restart the server, run a turn in thread B, reopen A and click a rating.
Change
ProviderSessionManager now wraps the session runtime's mcpApps the way it already wraps resumeThread. Before an MCP app call, the wrapper does three things:
- It attaches the card's thread, which issues its T3 MCP credential.
- It holds the thread loaded and resumes it if this session hasn't loaded that provider thread. This uses the same load path the turn path uses, now factored into one
loadThread. - After the call, it schedules the thread's idle unload again.
No turn is started.
The load key is split into provider thread and settings:
- A card call reuses any existing load of the thread, so a thread loaded by a turn isn't resumed again on every click.
- A load made by a card records no model or policy, so the next turn still resumes with its own.
Resuming through the manager rather than the adapter matters for the thread's next turn. The resume that loads the thread carries T3's MCP config, and Codex ignores config overrides when it resumes a thread that is already loaded.
Loading a thread for a card issues its MCP credential. So McpAppRequests reports a stopped session in three cases rather than loading the thread:
- the thread is archived;
- the thread is deleted;
- the card's provider thread is no longer the thread's active one, for example after a provider switch.
Scope and approval
Fixes pingdotgg/t3code#29433
Triaged via the automated issue flow.
Verification
Session manager:
ProviderSessionManager.test.tsgets two new tests.- "loads an unloaded provider thread with its MCP session before an MCP app call" fails on main: no
resume native-app mcp=truehappens beforelistTools. It passes here, and also checks that an idle unload follows. - "MCP app calls reuse any load of the thread without hiding a turn's resume" covers the load-key rule in both directions.
- "loads an unloaded provider thread with its MCP session before an MCP app call" fails on main: no
App requests:
McpAppRequests.test.tscovers archived, deleted and provider-switched threads. Each reportssession-stoppedwithout calling the provider.Suites:
McpAppRequests.test.ts,ProviderSessionManager.test.tsandCodexAdapterV2.test.tspass, 190 tests.vp run check:changedpasses.Real app: the web dev server with a fresh database, Codex 0.163.0, and the reporter's sample server. Runtime transcript of the Codex app-server requests:
Before, on main edc37c96c8, the card shows "Not saved: The app's MCP server request failed." and the saved rating is unchanged:
1 mcpServerStatus/list Failure CodexAppServerRequestError: thread not found: <native-thread-id> After, on the session-manager fix (880157ce3f; the later commits only add the guards above), the card shows "Saved" and the state file changes:
1 thread/resume Success (thread B's turn) 2 turn/start Success 3 thread/resume Success (card thread A, loaded by the session manager) 4 mcpServerStatus/list Success 5 mcpServer/tool/call Success 6 thread/resume Success (next turn in A) 7 turn/start Success That next turn in A called
t3_thread_listsuccessfully, so T3's MCP tools stay available after a card-only load.Unchanged by design: when no Codex session is live after a restart, the card still reports "The app's thread is not running…".
Not checked: macOS and Windows desktop, mobile clients, and Codex versions other than 0.163.0. The fix is server-only, and every client uses the same RPCs.
Model and harness: Claude Opus 5.5 through Claude Code (T3 Code), with Codex gpt-6.1-sol reviewers.
🤖 Generated with Claude Code
Checks
Added 6 commits
- Merge remote-tracking branch 'origin/main' into fix/issue-294330bc8ce1
- fix(server): archived threads' MCP app cards stay stopped12b9145
- fix(server): retired threads' MCP app cards stay stopped267c91c
- test(server): reproduce #29433 MCP app calls on an unloaded shared-session thread6374320
- fix(server): MCP app cards load their Codex thread after a restart880157c
- test(server): build the archived timestamp with DateTimee251f6f
Approvability
Verdict: Approved at 0bc8ce1
Macroscope's review found this PR approvable — MCP app cards reload their existing provider thread before app operations, restoring functionality after unloads. Archive/delete/provider-switch guards and existing tool restrictions bound the change without altering product defaults.
You can add or adjust custom eligibility rules. Learn more.
Thread transfer impact
✅ Thread transfer remains within every enforced ceiling.
ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful
mainmeasurement shown below.
| Provider | Metric | Main baseline | This PR | Impact | PR ceiling | |
|---|---|---|---|---|---|---|
| Codex | Total thread wire | 5.0 KiB | 5.0 KiB | +6 B (+0.1%) | 6.8 KiB | ✅ |
| Codex | Thread snapshot wire | 3.8 KiB | 3.8 KiB | 0 B (0.0%) | 4.9 KiB | ✅ |
| Codex | Live turn WebSocket wire | 1.2 KiB | 1.3 KiB | +6 B (+0.5%) | 2.0 KiB | ✅ |
| Codex | Live turn WebSocket decoded | 21.6 KiB | 21.6 KiB | 0 B (0.0%) | 24.4 KiB | ✅ |
| Codex | Live turn messages | 2 | 2 | 0 (0.0%) | 8 | ✅ |
| Claude | Total thread wire | 5.0 KiB | 5.1 KiB | +6 B (+0.1%) | 6.8 KiB | ✅ |
| Claude | Thread snapshot wire | 3.8 KiB | 3.8 KiB | 0 B (0.0%) | 4.9 KiB | ✅ |
| Claude | Live turn WebSocket wire | 1.3 KiB | 1.3 KiB | +6 B (+0.5%) | 2.0 KiB | ✅ |
| Claude | Live turn WebSocket decoded | 21.9 KiB | 21.9 KiB | 0 B (0.0%) | 24.4 KiB | ✅ |
| Claude | Live turn messages | 2 | 2 | 0 (0.0%) | 8 | ✅ |
Baseline: 8657eec · PR result: 0bc8ce1 · Source CI: success
Scenario and decoded snapshot size
10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
- Codex decoded thread snapshot: 108.5 KiB
- Claude decoded thread snapshot: 108.8 KiB
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.
No actionable comments were generated in the recent review.
External image Recent review info
-
External image Run configuration
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: fix/issue-29433
- File: .coderabbit.config.ts
- Commit: 0bc8ce1
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
60e7dcf8-a3f5-4353-afb0-9d4984a1afa8
External image Commits
Reviewing files that changed from the base of the PR and between 0847a448fdca5a688720050ca706cbbd37e6347e and 0bc8ce1463f53a4137e0af023eb5f92c148bde73.
External image Files selected for processing: 4
apps/server/src/mcpApps/McpAppRequests.test.tsapps/server/src/mcpApps/McpAppRequests.tsapps/server/src/orchestration-v2/ProviderSessionManager.test.tsapps/server/src/orchestration-v2/ProviderSessionManager.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.
Walkthrough
MCP app request resolution now stops requests for archived, deleted, or no-longer-active provider threads. Provider-session management loads threads for MCP app operations, tracks load state by runtime identity and configuration, and reuses or resumes threads according to the operation. Tests cover retired threads and shared-session load behavior.
Changes: MCP thread recovery
Layer / File(s) Summary Reject retired MCP threads
apps/server/src/mcpApps/McpAppRequests.ts,apps/server/src/mcpApps/McpAppRequests.test.tsresolvereturnssession-stoppedfor archived or deleted threads, threads whose active provider thread differs from the resolved thread, and provider threads without a session ID. Tests check the result forcallToolandtoolInfoand verify that no tool call occurs.Load provider threads for MCP operations
apps/server/src/orchestration-v2/ProviderSessionManager.ts,apps/server/src/orchestration-v2/ProviderSessionManager.test.tsLoad state now stores provider-runtime identity and configuration separately. MCP app operations load or reuse provider threads and schedule unloading after the operation. Tests cover MCP session availability, shared sessions, and a subsequent turn resume. Estimated code review effort: 3 (Moderate) | ~25 minutes
Change: Bug fix · Severity of issue fixed: Medium
Sequence Diagram(s)
mermaid1 sequenceDiagram 2 participant MCPAppOperation 3 participant ProviderSessionManager 4 participant ProviderRuntime 5 MCPAppOperation->>ProviderSessionManager: Run MCP app operation 6 ProviderSessionManager->>ProviderRuntime: resumeThread when thread is not loaded 7 ProviderRuntime-->>ProviderSessionManager: Return provider thread 8 ProviderSessionManager->>ProviderRuntime: Run MCP app operation Suggested reviewers:
maria-rcks,t3dotgg
Merge Risk: External image Minimal · up to 0bc8c
No merge-blocking issue was identified in the MCP thread-recovery changes; proceed with normal checks.
Pre-merge checks: Passed 4
Check name Status Explanation Title check Passed The title names the main change: MCP app cards in Codex threads work again after a restart unloads the thread. The changeset adds a thread load before MCP app calls and guards in McpAppRequests that r… Description check Passed The description follows the template. It has Problem, Change, Scope and approval, and Verification sections. The Problem section gives the failure, the reproduction steps, and the error text. The Chan… Linked Issues check Passed Issue #29433requires MCP app discovery and calls to recover after the provider thread is unloaded, without a new chat turn.ProviderSessionManager.tsnow wrapsmcpApps, attaches the card thread, …Out of Scope Changes check Passed The changes remain within issue #29433. The load-key refactor supports reuse of an already loaded thread and prevents a card-only load from suppressing the next turn resume. TheMcpAppRequestsguard…Full details: Title check
Explanation
The title names the main change: MCP app cards in Codex threads work again after a restart unloads the thread. The changeset adds a thread load before MCP app calls and guards in McpAppRequests that return session-stopped. The title is specific and follows conventional commit style, so it passes.
Full details: Description check
Explanation
The description follows the template. It has Problem, Change, Scope and approval, and Verification sections. The Problem section gives the failure, the reproduction steps, and the error text. The Change section explains the ProviderSessionManager wrapper, the load-key split, and the three session-stopped guards. Scope links issue
#29433and states it was triaged through an automated flow. Verification lists the new tests, the suites run, the real-app transcript, and the unchecked platforms. The template asks for a maintainer approval comment for scope, and the author gives only an automated triage reference, so that item is weak. The rest of the description is complete, so the check passes.
Full details: Linked Issues check
Explanation
Issue
#29433requires MCP app discovery and calls to recover after the provider thread is unloaded, without a new chat turn.ProviderSessionManager.tsnow wrapsmcpApps, attaches the card thread, loads it throughresumeThread, performs the MCP operation, and schedules idle unload. The shared load path reuses an existing provider-thread load and preserves the next turn's model and policy resume.McpAppRequests.tsreturnssession-stoppedfor archived, deleted, and provider-switched threads before it calls the provider.ProviderSessionManager.test.tsverifies load-before-call, MCP-session attachment, idle unload, load reuse, and a later turn resume. The reported tests also cover the stopped-session cases.
Full details: Out of Scope Changes check
Explanation
The changes remain within issue
#29433. The load-key refactor supports reuse of an already loaded thread and prevents a card-only load from suppressing the next turn resume. TheMcpAppRequestsguards prevent credential restoration for archived, deleted, or provider-switched threads. The added tests verify these behaviors. No unrelated production behavior or unrelated feature appears in the reviewed changes.
Finishing Touches
Generate docstrings
- Commit to this branch
- Create a new PR
Generate unit tests (beta)
- Commit to this branch
- Create a new PR
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks @juliusmarminge for the earlier fix and detailed verification. Closing this in favor of #29498 by @amr807, which addresses the same unloaded Codex MCP app failure and has a more recently updated branch. This branch is over a week old and main has changed the affected files since its base.