Repository navigation
Replies: 3 comments
EN / EnglishEvidence (source)
let cursor;
do {
const response = await listToolsUncached(client, cursor);
for (const tool of response.tools) { /* …definitions.set(publicName, createDefinition(...)) */ }
cursor = response.nextCursor;
} while (cursor);
Authorship note: reproduced and documented by me in real-world usage; root-cause tracing and drafting assisted by AI; verification and publication by me. I have no engineering background — if any technical claim reads wrong, please call it out; I will re-verify against the toolchain and correct. Reported by the OfferKuai Team — Founder: Zhaofeng (Yaming). Website: https://www.offerkuai.com/ | Contact: contact@offerkuai.com 中文版 / ZH证据(源码)
let cursor;
do {
const response = await listToolsUncached(client, cursor);
for (const tool of response.tools) { /* …definitions.set(publicName, createDefinition(...)) */ }
cursor = response.nextCursor;
} while (cursor);
协作说明:本文由我在真实使用中复现并记录;根因与成文由 AI 协助完成,我负责校验与发布。我非工程背景,技术表述如有错误,欢迎指出——我会回去用工具链重新验证后更正。 本报告由 OfferKuai(Offer快)团队提交 —— 创始人:Zhaofeng(Yaming)。官网:https://www.offerkuai.com/ | 联系:contact@offerkuai.com |
EN / EnglishAnalysis (root cause)The pagination loop trusts
A robust client must not assume the server honors the MCP pagination contract. The benign failure mode is itself telling: a server returning duplicate tool names throws and fails the sync — the loop has no graceful early-exit, it just crashes the sync. The worst case — a server emitting distinct tool names per page or never converging — makes the Proposed fix (minimal, architecture-consistent)
All three reuse primitives already present in the codebase, so the new surface is small and consistent. Questions for the maintainers
Authorship note: reproduced and documented by me in real-world usage; root-cause tracing and drafting assisted by AI; verification and publication by me. I have no engineering background — if any technical claim reads wrong, please call it out; I will re-verify against the toolchain and correct. Reported by the OfferKuai Team — Founder: Zhaofeng (Yaming). Website: https://www.offerkuai.com/ | Contact: contact@offerkuai.com 中文版 / ZH根因分析(含源码引用)分页循环把不可信外部 server 返回的
一个健壮的客户端绝不能假设 server 会遵守 MCP 分页契约。良性失败模式本身就很有说服力:返回重复工具名的 server 会抛错并使同步失败——循环没有优雅的提前退出,只是让同步崩溃。最坏情况——server 每页放出不同工具名或永不收敛——会让 建议修复(最小、符合既有架构)
三者都复用代码库既有原语,因此新增面很小且一致。 想问维护者的问题
协作说明:本文由我在真实使用中复现并记录;根因与成文由 AI 协助完成,我负责校验与发布。我非工程背景,技术表述如有错误,欢迎指出——我会回去用工具链重新验证后更正。 本报告由 OfferKuai(Offer快)团队提交 —— 创始人:Zhaofeng(Yaming)。官网:https://www.offerkuai.com/ | 联系:contact@offerkuai.com |
EN / EnglishAn earlier report on this same loop — #3660. While reviewing our own notes we went looking for prior reports and found one: @wxggzz posted this on 2026-08-20 — "Repeated nextCursor can make tools/list synchronization loop indefinitely" — pointing at We are adding it now rather than in the original post, and that is our own miss: we re-verified the behaviour against the npm line before posting, but we did not search for prior reports first. Two notes for anyone arriving later:
Authorship note: reproduced and measured by me against my own store; root-cause tracing and drafting assisted by AI; verification and publication by me. I have no engineering background — if any technical claim reads wrong, please call it out; I will re-verify against the toolchain and correct. Reported by the OfferKuai Team — Founder: Zhaofeng (Yaming). Website: https://www.offerkuai.com/ | Contact: contact@offerkuai.com 中文版 / ZH同一循环的更早报告 —— #3660。 我们回看自己的笔记时去找了更早的报告,找到一条:@wxggzz 在 2026-08-20 发的 「Repeated nextCursor can make tools/list synchronization loop indefinitely」(重复的 nextCursor 会让 tools/list 同步无限循环),指向 这条我们现在才补、而不是在发帖时就写上——是我们自己的疏漏:发帖前我们按 npm 线重验了行为,但没有先去搜是否已有报告。给后来者的两点说明:
声明:本次实测与统计由我针对自己的数据完成;根因追查与文稿撰写由 AI 辅助;核验与发布由我本人负责。我没有工程背景 —— 若任何技术表述有误,请直接指出,我会对照工具链重新核实并更正。 本报告由 OfferKuai(Offer快)团队提交 —— 创始人:Zhaofeng(Yaming)。官网:https://www.offerkuai.com/ | 联系:contact@offerkuai.com |
Uh oh!
There was an error while loading. Please reload this page.
EN / English
Found earlier in our daily usage; re-verified against the current npm line (through
0.1.3-alpha.2) before posting — still present. We publish one topic per report so each can be tracked independently; more findings will follow in the same form.Authorship note: reproduced and documented by me in real-world usage; root-cause tracing and drafting assisted by AI; verification and publication by me. I have no engineering background — if any technical claim reads wrong, please call it out; I will re-verify against the toolchain and correct.
Summary
When the harness connects to / re-syncs an MCP server,
syncToolsdrainstools/listpagination through ado … while (cursor)loop whose only exit is an externally-supplied, untrustednextCursor. There is no page-count cap, no cursor-progress check, and no aggregate deadline — so a server that never converges pagination can spin the loop indefinitely, or (emitting distinct tool names per page) grow the definitions map until the whole process is OOM-killed, taking every session down with it.Trigger condition
Any MCP server whose
tools/listdoes not terminate pagination:nextCursorforever, ordefinitionsgrowth → OOM), or"listed tool more than once — invalid tool list"and fails the whole sync. That failure mode itself proves the loop has no self-bound: termination depends entirely on an untrusted server honoring the pagination contract.Impact scope (production focus)
The MCP bridge is process-wide. One misbehaving third-party server (a buggy integration, a misconfigured self-hosted server, or a hostile one) can either spin the loop indefinitely (CPU) or, with growing distinct names, exhaust memory and OOM-kill the entire harness process — killing every session, including unrelated long-running agents. This is a robustness defect on untrusted input, not a security boundary: any deployment that integrates external MCP servers is exposed.
Repro
tools/listreturns a truthynextCursorforever (emitting distinct tool names per page, or simply never terminating).Environment
@deepseek-ai/dsh0.1.0-rc.6/0.1.0-rc.7@deepseek-ai/dsh0.1.1-rc.2@deepseek-ai/dsh-mcp-clienttools/listpaginationDetailed evidence chain (source lines) and the root-cause analysis + proposed fix follow in the comments below.
Reported by the OfferKuai Team — Founder: Zhaofeng (Yaming). Website: https://www.offerkuai.com/ | Contact: contact@offerkuai.com
中文版 / ZH
此为我们在日常使用中较早发现的问题,发布前已对照 npm 最新线(至 0.1.3-alpha.2)复核,确认仍存在。我们按"一帖一主题"发布以便独立跟踪,后续发现也将以同样形式陆续发出。
协作说明:本文由我在真实使用中复现并记录;根因与成文由 AI 协助完成,我负责校验与发布。我非工程背景,技术表述如有错误,欢迎指出——我会回去用工具链重新验证后更正。
摘要
当 harness 连接 / 重新同步某个 MCP server 时,
syncTools通过do … while (cursor)循环拉取tools/list分页,而循环的唯一出口是外部提供的、不可信的nextCursor。这里没有页数上限、没有 cursor 前进校验、也没有聚合超时——因此一个永不收敛分页的 server 可以让循环无限旋转;若它每页放出不同的工具名,definitions映射会无界增长,直到整个进程被 OOM 杀掉,连带拖垮所有会话。触发条件
任何
tools/list不终止分页的 MCP server:nextCursor,或definitions无界增长 → OOM),或"listed tool more than once — invalid tool list"并使整个同步失败。这个失败模式本身就证明循环毫无自我约束:是否终止完全依赖不可信的 server 遵守分页契约。影响范围(生产视角)
MCP 桥接是进程级的。一个行为异常的第三方 server(有 bug 的集成、配置错误的自托管 server,或恶意的)既可以让循环无限旋转(CPU),也可以在工具名持续增长时耗尽内存、OOM 杀掉整个 harness 进程——连带杀掉所有会话,包括无关的长跑 agent。这是针对不可信输入的健壮性缺陷,而非安全边界问题:任何集成了外部 MCP server 的部署都暴露在此风险下。
复现步骤
tools/list永远返回真值nextCursor(每页放出不同工具名,或干脆永不终止)。环境
@deepseek-ai/dsh0.1.0-rc.6/0.1.0-rc.7@deepseek-ai/dsh0.1.1-rc.2上验证@deepseek-ai/dsh-mcp-clienttools/list分页的 MCP server完整证据链(源码行号)、根因分析与建议修复见下方跟帖。
本报告由 OfferKuai(Offer快)团队提交 —— 创始人:Zhaofeng(Yaming)。官网:https://www.offerkuai.com/ | 联系:contact@offerkuai.com
All reactions