fix(runtime-core): close partially initialized MCP clients when startup fails - #452
Conversation
…up fails executeAgentBlock created MCP clients with Promise.all, which rejects as soon as one createMCPClient call fails — before the result is ever assigned to mcpClients. Clients that had already resolved were then invisible to the cleanup loop in the finally block, leaking their stdio subprocesses. Switch to Promise.allSettled: retain every fulfilled client into mcpClients first, then re-throw the first rejection so the existing finally block closes what was actually started. The original startup error still propagates unwrapped; the finally block itself is untouched. Adds a regression test with one client that starts successfully and one that fails, asserting the successful client's close() is called and the agent never runs. Closes #449 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aip97YnPuwVwg4zpNLkfMc
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #452 +/- ##
==========================================
+ Coverage 88.24% 88.30% +0.06%
==========================================
Files 191 191
Lines 10691 10697 +6
Branches 2993 2996 +3
==========================================
+ Hits 9434 9446 +12
+ Misses 1255 1249 -6
Partials 2 2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…ilure attribution When a failing MCP server precedes a successful one, the compacted mcpClients array loses index alignment with mergedMcpConfig, causing close-failure warnings to name the wrong server. Pair each client with its config name at assignment time so the finally block always reports the correct server. Adds a regression test with failure-first ordering that asserts the warning message contains the correct server name. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MH71aBtxrizLCVrWUhSAzj
|
@coderabbitai full review |
✅ Action performedFull review finished. |
📝 WalkthroughWalkthroughMCP client initialization now uses Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant executeAgentBlock
participant MCP initialization
participant MCP client
executeAgentBlock->>MCP initialization: start configured clients
MCP initialization-->>executeAgentBlock: settled client results
executeAgentBlock->>MCP client: load tools from successful clients
executeAgentBlock->>MCP client: close retained clients during cleanup
MCP client-->>executeAgentBlock: close result or warning
Possibly related issues
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 6✅ Passed checks (6 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/runtime-core/src/agent-handler.ts`:
- Around line 192-194: Update the startup handling around the client-settling
logic in agent-handler.ts to record each rejection as it occurs and preserve the
first rejection observed in time, rather than selecting the first rejected
result by configuration order. Throw the recorded error after all startup
promises settle, and add a regression test covering two servers that fail in
reverse configuration order.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9e17d696-1d12-45fe-b723-78a1e0dc3cb2
📒 Files selected for processing (2)
packages/runtime-core/src/agent-handler.tspackages/runtime-core/src/execute-agent-block.test.ts
Summary
Fixes #449.
executeAgentBlockcreated MCP clients withPromise.all, which rejects as soon as onecreateMCPClientcall fails — before the result is ever assigned tomcpClients. Clients that had already resolved were then invisible to the cleanup loop in thefinallyblock, leaking their stdio subprocesses.What changed
packages/runtime-core/src/agent-handler.ts: switch toPromise.allSettled, retain every fulfilled client intomcpClients, then re-throw the first rejection so the existing (untouched)finallyblock closes what was actually started. The original startup error still propagates unwrapped.Test plan
close()is called exactly once, the original error still propagates viarejects.toBe, and the agent never runs.close()call-count assertion, then passes after the fix.pnpm test(2785 passed),pnpm typecheck, andpnpm biome:checkall clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01Aip97YnPuwVwg4zpNLkfMc
Summary by CodeRabbit