fix(mcp): terminate descendants after discovery timeout#6926
Conversation
|
Thanks for the PR! Template looks good ✓ Problem: Real, observed gap — the non-pooled Direction: Aligned. This is a parity fix bringing the non-pooled timeout cleanup in line with the pooled lifecycle. Reuses existing cross-platform utilities ( Size: 29 production lines (in Approach: Scope feels right. The diff does exactly one thing: adds a best-effort descendant PID sweep before Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:已确认的差距——非池化 方向:对齐。这是一个对等修复——将非池化超时清理与池化生命周期保持一致。复用现有的跨平台工具( 规模:29 行生产代码( 方案:范围合理。diff 只做一件事:在超时处理程序的 进入代码审查 🔍 — Qwen Code · qwen3.7-max Reviewed at |
|
Code review: I independently proposed adding a best-effort descendant PID sweep before The diff is clean: one import line, 28 lines of new logic (try/catch for the PID sweep, then the existing disconnect block), and four focused tests. Reuses the existing cross-platform One observation: the PR adds a debug log when no PID is available ( Tests: All 116 tests pass, including the 4 new tests covering:
Real-scenario testing: This is an internal process-lifecycle change (no UI) — the behavior is about signaling descendant PIDs during a discovery timeout, which cannot be meaningfully observed through tmux 中文说明代码审查: 我独立提出的方案是在超时处理程序的 Diff 干净:一行 import、28 行新逻辑(PID 清理的 try/catch,然后是现有的 disconnect 块)、四个聚焦的测试。复用现有的跨平台 一个观察:PR 添加了无 PID 可用时的 debug 日志("Skipping descendant pid sweep")和部分信号覆盖时的 warn 日志,这两者池化 测试: 全部 116 个测试通过(包括 4 个新增测试),覆盖:stdio 包装进程后代在超时后被信号通知再断开连接、远程传输完全跳过 PID 枚举、无后代情况跳过信号发送但仍断开连接、后代枚举失败时仍执行断开连接。 真实场景测试: 这是内部进程生命周期更改(无 UI)——行为涉及发现超时期间的后代 PID 信号发送,无法通过 tmux — Qwen Code · qwen3.7-max Reviewed at |
|
Confidence: 5/5 — Clean across every stage. Minimal, focused parity fix with strong test coverage and independent maintainer verification. This is a textbook bugfix: a documented gap between the pooled and non-pooled MCP lifecycle paths, fixed by reusing existing utilities with no new abstractions. The 29-line production change does exactly one thing — best-effort descendant PID sweep before disconnect — and the four tests comprehensively cover the stdio, remote, no-descendants, and error paths. The diff faithfully mirrors the 中文说明信心度:5/5 — 每个阶段都干净。最小化的对等修复,测试覆盖充分,且有维护者的独立验证。 这是一个教科书式的 bugfix:池化和非池化 MCP 生命周期路径之间的已记录差距,通过复用现有工具修复,无新抽象。29 行生产代码只做一件事——断开连接前尽力而为地清理后代 PID——四个测试全面覆盖了 stdio、远程、无后代和错误路径。diff 忠实地镜像了 — Qwen Code · qwen3.7-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline.
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline. Not reviewed: chunk 1 — no agent reported covering these; nobody read them.
— qwen3.7-max via Qwen Code /review
2ee72c6 to
de8bcbd
Compare
|
Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration. 中文请勿对活跃的 PR 执行 rebase 或 force-push,因为这会使已有的评审评论失效。另外,供日后参考:作为集成流程的一部分,机器人始终会自动将所有改动压缩(squash)为单个提交。 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline. Not reviewed: chunk 1 — no agent reported covering these; nobody read them.
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline.
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline.
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline. Not reviewed: coverage — no plan was given, so this run cannot show that any of the diff was read.
— qwen3.7-max via Qwen Code /review
Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com>
qqqys
left a comment
There was a problem hiding this comment.
Blocking: the current head d569b24 leaves a duplicated partial-signal fragment at packages/core/src/tools/mcp-client-manager.ts:2402-2406 after the complete if block ending at line 2401. This is syntactically invalid TypeScript; the required Ubuntu and web-shell jobs fail at install/build time. Remove the stray duplicate lines and rebalance the braces before merge.
|
Addressed the blocking review in commit 8636675. The five stray lines introduced at d569b24 were removed, restoring balanced TypeScript syntax while preserving the complete partial-signal warning block. I reproduced the relevant gates locally: MCP client manager tests 116/116, repository build, repository typecheck, focused ESLint, Prettier, diff-check, and final autoreview all pass. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. 1 Suggestion-level finding(s) could not be anchored to the diff; see the terminal output. Not reviewed: chunk 1 — no agent reported covering these; nobody read them.
— qwen3.7-max via Qwen Code /review
✅ Local real-build verification — confirmedI verified this PR locally with a real build (not just the mocked unit tests) at head TL;DR: The fix works end-to-end in the real runtime path. A real stdio wrapper that leaks a real grandchild has that grandchild SIGTERM'd by the sweep and reaped with this PR, whereas on Environment: macOS (Darwin 24.6.0) · Node v22.23.1 · 1. Real end-to-end controlled experiment (the key evidence)The PR's unit tests mock
Only the sweep hunk differs between the two builds (the "before" source is byte-identical to
This reproduces #6918 on 2. Load-bearing check (tests genuinely exercise the fix)Reverting only the sweep hunk (keeping the new tests) flips exactly the three stdio-path tests red, while the remote/no-PID control stays green: 3. Full suite + gates at head
4. Code reviewThe change is a faithful mirror of the pooled path's Verdict: LGTM — ready to merge from a verification standpoint. 🇨🇳 中文版本(点击展开)✅ 本地真实构建验证 —— 已确认我在本地对本 PR 进行了真实构建验证(不仅仅是被 mock 的单元测试),基于 head 结论: 该修复在真实运行路径中端到端有效。一个泄漏真实孙进程的真实 stdio 包装器,在本 PR 下其孙进程会收到 SIGTERM 并被回收;而在 环境: macOS (Darwin 24.6.0) · Node v22.23.1 · 1. 真实端到端对照实验(核心证据)PR 的单元测试mock 了
两个构建之间仅 sweep 这一段代码不同("before" 源码与
这在 2. 承重性检查(测试确实验证了修复)仅回退 sweep 这一段(保留新测试),恰好使三个 stdio 路径测试变红,而 remote/无 PID 的对照用例保持绿色: 3. Head 上的完整测试与门禁
4. 代码审查该更改忠实地镜像了池化路径的 结论:从验证角度看 LGTM —— 可以合并。 |
|
@qwen-code /triage |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅

What this PR does
When non-pooled MCP discovery times out for a stdio server, terminate processes below the transport wrapper before disconnecting the wrapper. The sweep is best-effort and reuses the existing bounded, cross-platform descendant-PID utilities. Remote transports continue directly to disconnect because they expose no process ID.
Why it's needed
Stdio launchers such as
npxanduvxcan run the MCP server as a grandchild. The SDK closes its direct child on timeout, but that does not terminate the grandchild, so a timed-out discovery can leave the actual server running.Reviewer Test Plan
How to verify
Regression proof on the base branch: the two stdio cases failed because descendant enumeration was never called, while the remote/no-PID control passed. With this change, all three cases pass. An independent SDK fallback also confirmed that direct-child close is bounded: it returned in 2017 ms, stopped the wrapper, and left the wrapper's grandchild alive.
Evidence (Before & After)
N/A — internal process-lifecycle change with no UI.
Tested on
Environment (optional)
Linux, Node.js 24.18.0. Focused timeout tests: 4/4 passed. Full MCP client manager tests: 116/116 passed. Core build, typecheck, formatting, and ESLint passed.
Risk & Scope
Linked Issues
Fixes #6918
中文说明
此 PR 的作用
当非池化 MCP 的 stdio 服务器发现过程超时时,在断开包装进程之前终止其下层进程。该清理为尽力而为,并复用现有的、有界且跨平台的后代 PID 工具。远程传输不提供进程 ID,因此仍直接执行断开连接。
为什么需要此更改
npx和uvx等 stdio 启动器可能将 MCP 服务器作为孙进程运行。SDK 会在超时时关闭直接子进程,但不会终止孙进程,因此发现超时后实际服务器可能仍在运行。审阅者测试计划
验证方法
基线分支上的回归证明:两个 stdio 用例因从未调用后代进程枚举而失败,远程无 PID 对照用例通过。应用此更改后,三个用例全部通过。独立 SDK 回退验证还确认直接子进程关闭是有界的:关闭在 2017 毫秒内返回,包装进程退出,但其孙进程仍然存活。
证据(更改前与更改后)
不适用——内部进程生命周期更改,无 UI。
测试平台
环境(可选)
Linux,Node.js 24.18.0。聚焦超时测试 4/4 通过;完整 MCP 客户端管理器测试 116/116 通过;核心包构建、类型检查、格式检查和 ESLint 均通过。
风险与范围
关联问题
Fixes #6918