Skip to content

fix(server): Claude threads no longer inherit the launching Claude session or race MCP connects - #25976

Open
juliusmarminge wants to merge 6 commits into
mainfrom
fix/issue-25959
Open

juliusmarminge wants to merge 6 commits into
mainfrom
fix/issue-25959

Conversation

@juliusmarminge

Copy link
Copy Markdown
Member

Problem

Claude threads fail to share a prompt cache across new threads, for two reasons.

  • When T3 is started from inside a Claude Code session, every claude it spawns inherits that session's environment: CLAUDECODE, CLAUDE_CODE_ENTRYPOINT=claude-desktop, the session id, the messaging socket and token, CLAUDE_EFFORT, CLAUDE_PID, and so on. The spawned process runs as a child of a session it does not belong to.
  • Claude Code connects MCP servers without blocking by default. A server that is still connecting when a turn's first request goes out is left out of that request's tool list and added on a later one. Each change rewrites the whole ~52k-token cached prefix, and new threads whose first tool list differs each write a fresh one.

Reproduced on main e9236274a3 with the dev server launched under a fake host session's variables, a Claude instance whose binaryPath logs its env, and a user-scope stdio MCP server that connects after 0.5 to 4 s. Every probe and turn received CLAUDE_CODE_ENTRYPOINT=claude-desktop and the host session's variables. Of four new threads, one went out with the slow server's tools and wrote 52,691 tokens of fresh cache. In the others the tools only arrived on the second request, and that request rewrote the prefix.

Change

  • mergeClaudeProcessEnvironment in ClaudeHome.ts removes a fixed list of Claude Code host-session markers from the host environment, then merges the instance's own environment as before. A value set on the instance still wins.
  • The adapter (turns) and the driver (version and capability probes, text generation) build their env with it. The driver now reads HostProcess.Environment like the adapter does, instead of process.env.
  • Turns default MCP_CONNECTION_NONBLOCKING to false unless the host or instance env sets it. The first request then waits for MCP servers to connect, so every new thread sends the same tool list.
  • User configuration such as CLAUDE_CONFIG_DIR, ANTHROPIC_*, proxy and telemetry variables still passes through.

Scope and approval

Fixes #25959

Verification

  • ClaudeAdapterV2.test.ts, "ClaudeAdapterV2 turn environment":
    • does not leak a parent Claude Code session into the spawned claude fails on main with CLAUDECODE: "1", CLAUDE_CODE_ENTRYPOINT: "claude-desktop", the session id, socket and effort all present. It passes with the fix, and it fails again if CLAUDE_CODE_ENTRYPOINT is removed from the scrub list.
    • connects MCP servers before the first request unless the instance opts out fails on main with [undefined, "true"]. It passes with the fix.
  • ClaudeAdapterV2.test.ts, ClaudeHome.test.ts and ClaudeTextGeneration.test.ts: 258 passed. vp run check:changed passes.
  • Runtime transcript: real dev server and real Claude Code 2.1.303 (Sonnet 5.5), the same prompt in each new thread, a fresh database on each side.
Before, main e923627 After, f072531
Spawned turn env CLAUDECODE=1, CLAUDE_CODE_ENTRYPOINT=claude-desktop, host CLAUDE_CODE_SESSION_ID, CLAUDE_CODE_MESSAGING_SOCKET/TOKEN, CLAUDE_EFFORT, CLAUDE_PID, CLAUDE_CODE_CHILD_SESSION CLAUDE_CODE_ENTRYPOINT=sdk-ts (set by the SDK), MCP_CONNECTION_NONBLOCKING=false, no host-session variables in any of the 7 spawns
First-request tool list, jittered slow MCP server varies per thread: 91 tools without the slow server, or 98 with it the same 98 tools in all 5 threads
Cache writes on new threads B1 52,691 fresh; B2 3,652 rewritten on request 2; thread A1 rewrote 53,232 on request 2 when the server connected D1 52,274 once; D2 to D5 read it (0 written on request 1)

Transcripts: before-main-e9236274a3.txt, after-fix-f072531c75.txt. Scripts: claude-wrap (env-logging binaryPath), slow-mcp.mjs (stdio MCP server with a jittered initialize), shapes.py (reads request shapes and cache usage from the transcripts).

  • Not checked: the macOS open -a launch from a Claude Desktop session, and claude.ai connectors. The run used a user-scope stdio server through the hub API on Linux; the code path does not depend on the platform.

Model and harness: Claude Opus 5.5 in Claude Code, run as a T3 Code issue lead, with Claude Opus 5.5 and GPT-6.1 Sol step agents.

🤖 Generated with Claude Code

juliusmarminge and others added 3 commits October 27, 2026 13:38
…Code session env

These tests reproduce #25959. The env createClaudeAdapterV2 passes to the
SDK query still carries a parent Claude Code session's variables
(CLAUDECODE, CLAUDE_CODE_ENTRYPOINT, CLAUDE_CODE_SESSION_ID,
CLAUDE_CODE_MESSAGING_SOCKET, CLAUDE_EFFORT), and never sets
MCP_CONNECTION_NONBLOCKING=false, so MCP tools can miss a turn's first request.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…hat launched T3

Every Claude spawn path (turns, capability and version probes, text
generation) strips the host Claude Code session markers before the
instance environment is merged, so a value set on the instance still
wins. Turns default MCP_CONNECTION_NONBLOCKING to false so new threads
send a stable tool list on their first request and share one prompt
cache.

Fixes #25959

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions github-actions Bot added vouch:trusted Author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 27, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — Claude threads now default to blocking MCP connections, while retaining environment overrides. Human review is needed to accept the default tradeoff between stable tool availability and potentially longer connection waits.

You can add or adjust custom eligibility rules. Learn more.

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 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.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 21.5 KiB 21.5 KiB 0 B (0.0%) 24.4 KiB ✅
Codex Live turn messages 1 1 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 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.2 KiB 1.2 KiB 0 B (0.0%) 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 1 1 0 (0.0%) 8 ✅

Baseline: b883156 · PR result: 747e7ca · 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.

@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The Claude adapter now sets MCP_CONNECTION_NONBLOCKING to "false" by default. Provider-instance environment values override this default, and tests verify both cases.

Changes: Claude MCP connection environment

Layer / File(s) Summary
Set and test MCP connection default
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts, apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
The adapter sets MCP_CONNECTION_NONBLOCKING to "false" before applying provider-instance environment values. Tests capture full query environments and check the default and explicit override.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Possibly related issues

  • Issue 31200 concerns Claude failures during MCP registration. This change sets the default MCP connection behavior, but does not change error reporting or session state.

Suggested reviewers: maria-rcks, saphid

Merge Risk: Minimal · up to 747e7

Claude turns now default to waiting for MCP servers to connect before the first request. Instance settings can still opt out. No merge-blocking risk was found.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title clearly and concisely describes both primary changes: Claude session environment isolation and blocking MCP connections.
Description check Passed The description includes all required sections. It explains the problem, implementation, scope, focused tests, observed results, limitations, and agent details.
Linked Issues check Passed Direct issue #25959 is closed and supplies historical context only. No active directly linked issue provides coding requirements for this pull request. The reported environment and MCP changes therefo…
Out of Scope Changes check Passed The reviewed changes set the Claude turn environment and add focused environment-capture and MCP override coverage. These changes address the historical #25959 problem. The available change summary sh…
Full details: Linked Issues check

Explanation

Direct issue #25959 is closed and supplies historical context only. No active directly linked issue provides coding requirements for this pull request. The reported environment and MCP changes therefore do not fail a current linked-issue requirement.

Full details: Out of Scope Changes check

Explanation

The reviewed changes set the Claude turn environment and add focused environment-capture and MCP override coverage. These changes address the historical #25959 problem. The available change summary shows no unrelated product behavior or unrelated file 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
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 134bf64 and 747e7ca.

Files selected for processing: 2

  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.

Copy link
Copy Markdown
Member Author

Thanks for the thorough investigation and fix. #29169 (47f2c8d29e) covers the inherited host-session environment. Could you cut this PR down to the separate blocking MCP connection behavior and its tests? The startup latency tradeoff noted in the merged PR still needs consideration.

# Conflicts:
#	apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
#	apps/server/src/provider/Drivers/ClaudeDriver.ts

Copy link
Copy Markdown
Member Author

The automated pipeline stopped on this pull request and will not merge it:

someone else pushed to fix/issue-25959 (head is now 134bf64); the pipeline does not build on commits it did not review

It stays open for a person to finish or close.

The merge with main kept main's environment sanitizing and dropped this
branch's blocking MCP connect default. Restore it on top of main's
environment, keeping instance and host overrides, and cover it with a test.

AI-assisted; verified with the tests and tools listed above.
@github-actions github-actions Bot added size:XS 0-9 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Nov 11, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Fix PR opened by an issue lead; enters the PR loop pr:gate-failed A land gate failed size:XS 0-9 changed lines (additions + deletions). vouch:trusted Author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Claude threads rewrite the prompt cache on every new thread (inherited host session env, late MCP connections)

1 participant