Repository navigation
Replies: 1 comment
|
Your reading of The swap disposes the previous generation before it registers the new one ( // Phase 2: swap generations.
for (const dispose of previous.values()) dispose() // :146 old generation is gone from here on
const disposers: ToolDisposers = new Map()
try {
for (const [publicName, definition] of definitions) {
disposers.set(publicName, ctx.tools.register(definition)) // :150
}
} catch (error) {
for (const dispose of disposers.values()) dispose() // rollback of the NEW generation only
ctx.logger.error(`mcp-client(${opts.serverName}): tool registration failed, no tools registered: ${String(error)}`)
if (opts.registrationFailure === 'throw') throw error
return new Map() // :159
}So Note the contrast with Phase 1 ( Which lines to grep, and what each one means
If none of the first four appear near the disappearance, the family was never registered in that process at all, and the bridge is the wrong place to look — check the session surface instead (a Why "only a host restart recovers" — two facts about the sync triggers make that outcome predictable:
On your resync ask, the state of the knobs is worth stating exactly, since it is the same area as the On the 75 → 84 arithmetic. It says the pre-restart process held five tools the post-restart one does not (84 − 14 = 70, but you counted 75). That is not the signature of a missing family; it is the signature of registrations surviving from an earlier generation, which the disposer lifetime above makes possible. It is worth one measurement rather than one inference: list the full runtime tool surface before and after the restart and diff the two sets by name, instead of comparing counts. Plugin boundary, honestly. An out-of-tree plugin cannot reach |
Uh oh!
There was an error while loading. Please reload this page.
环境
0.2.0-rc.2(Windows 11 家庭中文版 10.0.22631,profile:desktop)@deepseek-ai/dsh-mcp-client0.2.0-rc.2(源码路径packages/mcp/mcp-client)matlab-mcp-serverv0.15.0(Windows x64 发布二进制,Go,stdio),额外用--extension-file挂了 9 个自定义工具,共 14 个 tool + 2 个 resourceresource-filter只有skillSeries,没有toolPrefixes,即不存在任何"按前缀屏蔽工具"的逻辑现象
同一会话内同时满足:
matlab-mcp-server-windows-x64.exe);resources/list正常返回 2 个 resource;initialize→tools/list)直连同一个二进制,稳定返回 14 个 tool;mcp__matlab__*是 0 个。量化读数
mcp__matlab__*补充一句读数观察:75 → 84 差 9,而新增的 matlab 家族是 14,两者对不上,怀疑那一次丢的不止一个 MCP 家族;这点我没有别的证据,只记录读数。2026-10-16 当天"重启宿主即恢复"共出现两次。
从插件源码读到的行为(
lib/index.js)syncTools():遍历tools/list结果后逐个ctx.tools.register(definition);一旦抛错,先回滚本轮已注册的部分,打一条mcp-client(<serverName>): tool registration failed, no tools registered: <error>的 error 日志,然后按
registrationFailure: "contain"吞掉并返回空 Map;failOnStartupError: true时registrationFailure才由"contain"变为"throw";outcome.error非空且failOnStartupError为真,抛initial connection or tool synchronization failed;listChanged.autoRefresh: false,首次成功同步之后再发生的注册失败既没有重试也没有重同步,对使用者表现为"工具整族凭空消失",只能重启宿主。复现
没有稳定触发步骤:两次都发生在日常连续使用中,不是某个特定操作之后。能稳定复现的只有"恢复动作"——重启 DSH 宿主(或重载插件、重开会话)后工具恢复。裸 MCP 直连始终正常,说明故障在客户端的注册环节,不在 server。
期望
ctx.tools.register()失败时按策略重试,或在下一轮请求前做一次强制重同步(把listChanged的 autoRefresh 做成可配置开关);run_code里Object.keys(tools)自查)。附:本机 mcp-matlab 配置(cordis.patch.yml)
failOnStartupError是事后加的缓解,只覆盖初次连接/同步路径,不改变本问题本身。附:裸握手读数
All reactions