按会话惰性加载 MCP 工具,精简上下文工具列表
29.4/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/11/1 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/MikotoMyWife/dsh-mcp-loader.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 按会话惰性加载工具
- 按智能体屏蔽工具
- 配置工具描述预设
为 DeepSeek Harness(DSH)懒加载 MCP 工具:每个多工具 MCP 服务商配一个加载器工具,按智能体屏蔽工具,描述预设
README
由 DeepSeek 最新模型翻译生成dsh-mcp-loader
为 DeepSeek Harness(DSH)提供懒加载 MCP 工具:每个带多个工具的 MCP 服务器都由一个加载器工具代表(默认 mcp_<server>),只有调用加载器之后,服务器真正的工具才会进入模型上下文。装了很多 MCP 服务器时,这样就去掉了「每个请求都携带全部工具 schema」的固定开销,同时把可见工具列表压得足够小,模型才挑得对工具。加载按会话隔离:调用加载器的会话(及其子代理)能看到这些工具,进程里其他会话——包括之后新建的会话——始终只看到加载器。
工作原理
Initial tool list: mcp_notes, mcp_browser, mcp_desktop, ... (one loader per server)
↓ model calls mcp_notes({})
→ "ok" the next request exposes mcp__notes__search, mcp__notes__create, ...
↓ model calls mcp_notes({}) again
→ "ok (20 tool(s) hidden)" those tools leave the context
↓ a third call loads them again
展开完整文档(README 剩余 1 节)
dsh-mcp-loader
为 DeepSeek Harness(DSH)提供懒加载 MCP 工具:每个带多个工具的 MCP 服务器都由一个加载器工具代表(默认 mcp_<server>),只有调用加载器之后,服务器真正的工具才会进入模型上下文。装了很多 MCP 服务器时,这样就去掉了「每个请求都携带全部工具 schema」的固定开销,同时把可见工具列表压得足够小,模型才挑得对工具。加载按会话隔离:调用加载器的会话(及其子代理)能看到这些工具,进程里其他会话——包括之后新建的会话——始终只看到加载器。
工作原理
Initial tool list: mcp_notes, mcp_browser, mcp_desktop, ... (one loader per server)
↓ model calls mcp_notes({})
→ "ok" the next request exposes mcp__notes__search, mcp__notes__create, ...
↓ model calls mcp_notes({}) again
→ "ok (20 tool(s) hidden)" those tools leave the context
↓ a third call loads them again
加载器是个开关,作用域限定在调用它的会话:调一次加载,再调一次隐藏,第三次调又加载——不需要单独占一个槽位的「卸载工具」。第二个会话切换同一个服务器时,状态是它自己的:它不会继承第一个会话的披露结果,在一个会话里隐藏也绝不会把工具从另一个会话撤走。底层生成物只有在最后一个持有者放手后才释放。工具数 ≤ singleToolThreshold 的服务器在启动时就被识别出来,常驻,不配加载器——而且既然再没有东西能让它们重新出现,它们也永远不会按会话被遮蔽(singleToolThreshold: 0 会给每个服务器都配加载器,于是每个服务器都按会话隔离)。
注册模型
- 组装提示词时才投影工具 schema(ctx.systemPrompt.tools(...)),所以在一次工具调用里注册的工具,会在同一轮模型的下一个步骤出现——不用多跑一个来回。
- 启动时只注册加载器(不拉起进程)。一次性探测可能连接 auto/eager 服务器来数它们的工具:工具数 ≤ singleToolThreshold 的服务器转为常驻,加载器被移除;mode: lazy 的服务器从不参与探测,启动时也不拉起。
- 注册是部署级(全局)的,和官方 dsh-mcp-client 一致,因为 ctx.tools.restrict() 只过滤继承来的工具,并且会拒绝未全局注册的名字——按智能体隐藏(hiddenTools)建立在全局注册之上。
- 可见性按会话隔离。全局注册会把工具放进每个智能体都继承的那一层,于是没有会话限定的加载会泄漏到其他所有会话;所以加载器把调用它的会话记为持有者,凡不是持有者(也不是持有者的子代理)的智能体,都会收到一个 restrict({ deny }) 掩码这一代的公开名称。完全没有持有者的那一代——没有智能体的调用,例如测试或脚本直接驱动 ctx.tools.execute——保持部署级的 v0.5.0 行为。
子代理继承:当子会话是 subagent 时,遍历沿 parentSession 向上走,并在分叉处(isSeeded,无 origin)主动停止——分叉是新会话,从未展开。
功能
- 按服务器切换加载器——加载、隐藏、重新加载,结果消息可见(ok、ok (N tool(s) hidden)),且按会话隔离:一个会话的加载对其他所有会话不可见(其子代理会继承)。
- 模式——auto(启动时探测一次)、lazy(始终藏在加载器后面,从不探测)、eager(始终常驻,无加载器)。
- hiddenTools——服务器加载后按智能体屏蔽指定工具(restrict({ deny })),对每个已存在的智能体和之后创建的智能体都生效。条目是规则——精确原始名(ping)、精确公开名(mcp__solo__ping)或通配符(e、mcp__solo__、? 匹配单个字符)——在加载时按服务器实际暴露的工具展开。屏蔽只影响按智能体的可见性;工具仍全局注册。
- disabledTools——匹配的工具完全不注册(注册轴,全局):工具在注册前就被丢弃,不计入已加载工具总数,对所有智能体不可见。规则语法与 hiddenTools 相同。加载器工具永不受影响(它不是被发现的 MCP 工具)。
- 描述工程——按服务器的 description、descriptionPreset、按工具的 toolDescriptions 覆盖,以及参数描述截断(maxParameterDescriptionChars),让面向模型的文本说明工具做什么、何时使用。
- 服务器指令——服务器发送 MCP instructions 时,加载结果会带上它们,标注为 ### MCP server: <name>,模型在会话展开该服务器的那一刻就能读到。它们放在结果里而不是加载器描述里:描述会在加载器存在的整个期间让每个请求都付出这些 token 的代价。
maxInstructionBytes 限制该块大小,服务器超出时加载失败。
- 韧性——原子注册(任何失败都把服务器回滚到零工具)、共享并发尝试、list_changed 重新同步(整代替换)、原始 tools/call(跳过对 structuredContent 的 outputSchema 校验,与官方客户端一致)、传输失败时丢弃并在下次调用时重连。
- 有界释放——每个被丢弃的代都在 closeTimeoutMs 期限内关闭。无法确认关闭的传输会被记录并毒化该连接:它拒绝重连,因为子进程可能仍在运行,新连接会为同一服务器启动第二个。
- 子进程环境——stdio 服务器启动时使用父环境,去掉所有形似凭据的键(/KEY|PASSWORD|SECRET|TOKEN/i)以及每一条 DSH_ 事实,这样 npx/mcp-remote 服务器就能保留 PATH、NPM_CONFIG_ 和代理变量(当它们是 http(s) URL 时,会设置 NODE_USE_ENV_PROXY),而 SDK 的最小默认环境本来会丢掉这些。配置的 env 条目最后合并,并且始终优先。
- 发现硬上限 —— 对每个服务器,一次真实发现受 maxToolListPages 页、maxToolsPerServer 个原始工具和 discoveryTimeoutMs 截止时间限制;超过任何一项都会让加载/重新同步失败,错误信息会指明服务器和原因,保留 loader 工具,并且永不重试。
- 资源桥接(可选) —— 当组合提供 harness 资源服务(mcpResources)时,会话已展开的服务器也会发布其资源:共享的 list_mcp_resources / list_mcp_resource_templates / read_mcp_resource 工具代理到该连接,再次隐藏服务器会撤回该表面。没有该服务时,插件照常加载服务器,并说明一次。
- 有序重新同步 —— 每个服务器的单调发现代次确保两个并发的 list_changed 重新同步(或与加载竞争的重新同步)绝不会让较旧的快照在较新的快照之后落地并覆盖它:过期的发现结果会被丢弃,而不是被应用。
- 传输 —— stdio(用清理过的子环境启动 command/args)和 streamable-http(url/headers)。
- 配置快速失败 —— 未知预设或无效服务器名([A-Za-z0-9_-]{1,32})会让插件挂载失败,并指明字段。
安装
npm install # build/test locally
npm run build # tsc → lib/
npm test # real-link e2e: real cordis ctx + dsh-tools ToolRuntime + real MCP stdio subprocesses
MCP 客户端层是 @modelcontextprotocol/client 2.0.0 —— 与 harness 自身发布的是同一线 —— 并且它是除 Node 内置模块外唯一的运行时依赖。v1 @modelcontextprotocol/sdk 仍作为 devDependency 用于测试夹具,这些夹具是 v1 服务器。
然后在你的配置档中注册插件(id mcp-loader,包 dsh-mcp-loader)并添加你的服务器:
- id: mcp-loader
name: dsh-mcp-loader
config:
servers:
notes:
description: "Search, read, create and organize personal notes. Use when the task involves the user's notes."
command: npx
args: ['-y', 'mcp-remote', 'https://example.invalid/mcp']
desktop:
description: "Control the real desktop ..."
mode: lazy
command: npx
args: ['-y', 'example-desktop-mcp']
配置
| 字段 | 默认值 | 含义 |
| servers | {} | 服务器表;键是 mcp__<server>__<tool> 的命名空间 |
| servers.<n>.description | — | loader 描述正文:它能做什么 + 何时使用 |
| servers.<n>.mode | auto | auto / lazy(始终 loader)/ eager(始终常驻) |
| servers.<n>.loaderName | mcp_<server> | 模型可见的加载器名称 |
| servers.<n>.hiddenTools | — | 工具规则(原始名/公开名精确匹配或 glob);加载后按智能体屏蔽,glob 匹配任意字符,? 匹配单个字符 |
| servers.<n>.disabledTools | — | 工具规则,永不注册(语法同 hiddenTools) |
| servers.<n>.toolDescriptions | — | 按工具覆盖描述 |
| servers.<n>.descriptionPreset | — | 内置描述表(desktop-touch) |
| servers.<n>.maxParameterDescriptionChars | 0 | 截断参数描述(预设可能隐含一个值) |
| servers.<n>.maxInstructionBytes | 32768 | 服务器自身 MCP instructions 的上限;超出则加载失败,报错会指明该服务器、上限和实际大小(绝不截断,绝不重试) |
| servers.<n>.transport | stdio | stdio 或 streamable-http |
| servers.<n>.command/args/env/cwd | — | 要启动的 stdio 进程;env 合并到已清理的父环境之上(凭据形态的键和 DSH_ 会被扣留,代理和 NPM_CONFIG_ 保留) |
| servers.<n>.url/headers | — | streamable-http 端点和额外请求头 |
| servers.<n>.toolCallTimeoutMs | 60000 | 每次 tools/call 的超时 |
| servers.<n>.reconnectAttempts | 1 | 按用户可见操作计(一次加载器加载、一次工具调用、一次启动探测):连接/发现失败后重试——连接和发现共用一个预算,共 reconnectAttempts + 1 次尝试(0 = 只尝试一次,v0.5.0 行为) |
| servers.<n>.reconnectBackoffMs | 500 | 重试基础延迟;每次重试翻倍(×2ⁿ),上限 30s |
| servers.<n>.idleDisconnectMs | 0 | 未加载的服务器空闲这么久后关闭其 MCP 连接(0 = 始终保持热连接);下次加载时重连 |
| servers.<n>.maxToolListPages | 100 | 发现硬上限:每次真实发现最多 tools/list 页数;超出则加载/重新同步失败,报错指明 pages(绝不重试,绝不截断) |
| servers.<n>.maxToolsPerServer | 500 | 发现硬上限:单个服务器最多可暴露的原始工具数;超出则失败,报错指明 tools(在 disabledTools 之前计数) |
| servers.<n>.discoveryTimeoutMs | 60000 | 单次真实分页的发现截止时间;超时则失败,报错指明 timeout 并断开连接,卡住的服务器不会阻塞后续调用 |
| servers.<n>.closeTimeoutMs | 5000 | 确认已断开的服务器传输确实关闭的截止时间;未确认关闭会记日志,且连接拒绝重连(子进程可能仍在运行,新连接会与它重叠) |
| connectTimeoutMs | 30000 | 连接握手超时 |
| singleToolThreshold | 1 | auto 模式:工具数 ≤ 此值的服务器保持常驻 |
| loaderHint | Call to load this MCP server's tools into this session; call again to hide them. | 追加到每个加载器描述 |
| probeAtStartup | true | 启动时探测 auto/eager 服务器(lazy 永不探测) |
隐藏工具与禁用工具
两种做法都能让模型看不到工具,但它们作用在不同层面,不能混为一谈。
两者接受相同的规则语法:
- 精确原始名,例如 ping —— 用 ^ping$ 匹配 MCP 工具的原始名;
- 精确公开名,例如 mcp__inkstone__search —— 匹配公开名 mcp__<server>__<tool>;
- 通配符,两种写法都行,例如 note_、search_?、mcp__inkstone__ —— 匹配任意长度的字符(包括零个),? 匹配恰好一个字符;模式两端锚定(^…$)。
服务器加载时,规则会展开到它实际暴露的工具列表上(重新同步时再展开一次),所以模式只会隐藏真实存在的工具,多条规则命中同一个工具也只拒绝一次。精确名保持 v0.5.0 的行为不变。
| 配置 | 机制 | 作用范围 | 生效时机 |
| 加载器被调用两次 / mode: lazy 从未加载 | 从注册表移除(卸载 / 未注册) | 所有智能体 | 调用时 |
| 加载后未持有加载器(默认) | 移除可见性 —— 按智能体 restrict({ deny }),会话自身选择加入时解除 | 仅非持有者会话 | 加载后,按智能体应用 |
| disabledTools | 从注册表移除 —— 匹配的工具在注册之前就被过滤掉 | 所有智能体(全局禁用) | 加载 / 重新同步时 |
| hiddenTools | 移除可见性 —— 按智能体 restrict({ deny }) | 每个智能体(按智能体掩码) | 加载后,按智能体应用 |
这三个层面彼此独立:在注册表里 ≠ 可见 ≠ 可调用。disabledTools 属于注册表层面(从未注册的工具无法触达),而按会话的默认掩码和 hiddenTools 留在可见性层面(工具仍全局注册,只是按智能体掩码)。两个掩码按智能体合并,所以一个服务器可以既被配置隐藏,又不被当前智能体持有。
这里刻意没有执行层面:本插件不添加 pre-execute 拒绝监听器 —— 注册且可见的工具就可调用。(只有当未来某种模式让工具保持注册、却把它们投影出去时,才值得加执行层面的拒绝。)
锁定保护。 服务器自己的加载器工具永远不会被它自己的规则隐藏或禁用:
- 与加载器名(loaderName 或默认的 mcp_<server>)字面相同的精确规则,会在插件挂载时被拒绝,并给出指明服务器和加载器的消息;
- 会覆盖加载器名的通配符会从拒绝掩码中剔除,加载时记录一次警告;加载器保持可见,服务器总能再次切换。
disabledTools 完全无法禁用加载器:加载器是插件注册的工具,从不是被发现的 MCP 工具。
全部禁用时。 一个服务器如果所有被发现的工具都匹配 disabledTools,会被当作一个空服务器:加载器调用返回 ok,但什么都没注册(日志里记成 loaded 0 tool(s) ... (N suppressed by disabledTools))。在 auto/eager 下,启动探测会直接移除加载器——之后只有你改配置并重启,服务器才会回来(如果你可能想不重启就重新启用工具,就保留 mode: lazy)。
与发现上限的交互。 每个服务器的发现上限在连接层,统计的是原始发现的工具数(页数 / 工具数 / 截止时间),而 disabledTools 在更晚的加载器层过滤。因此,服务器上报的原始工具数超过上限时,会在 disabledTools 起作用之前就发现失败——这是有意为之:上限防的是失控服务器自己的目录,不是你对它的配置。如果你要禁掉一个巨大目录里的大部分工具,就调高上限或删掉这个服务器。上限失败是确定性的,永远不会重试。
已知限制
- 粒度是每个服务器,不是每个工具(每个服务器一个加载器)。
- 工具规则在某一代加载时展开,在重新同步时重新展开,所以 glob 看到的是那一刻的工具集。掩码对智能体每个服务器只应用一次(每个智能体的 restrict 不会在重新同步时重放),因此某个工具若在之后的重新同步中才首次出现,它只对那次重新同步之后创建的智能体生效,对更早展开时已被掩码的智能体不生效。
- 启动探测是快照:之后增长到超过阈值的服务器会一直保持暴露,直到重启(用 mode: lazy 固定它)。
- 一个服务器名只能由一个桥接服务:每个配置名在挂载时被认领,第二个实例(本插件的另一次挂载,或同一名字上的官方 dsh-mcp-client)会被拒绝并报具名错误,而不是静默注册失败——注册是全局的,公开工具名会冲突。
- 图像/音频会变成 [image image/png] 文本占位符,且只桥接工具:MCP 资源只通过上面描述的可选资源服务桥接,而提示词、进度和任务型工具不在范围内。图像是有意分歧——官方 dsh-mcp-client 0.1.6 通过附件块投射它们。
- 从不声明 tools 能力的服务器会加载为空目录(记录一次,保留加载器),且永远不会被要求提供工具列表,所以纯资源服务器不会每次加载都失败。
- 重连有界且惰性:一次用户可见操作(加载器加载、工具调用、启动探测)从 reconnectAttempts + 1 次连接+发现尝试的单一预算中支取(reconnectAttempts/reconnectBackoffMs);失败的 tools/call 立即暴露,永不重放。没有急切的背景保活/重连——idleDisconnectMs: 0(默认)的空闲服务器会无限期保持热态,而 idleDisconnectMs > 0 的服务器只有在没有加载任何工具时才断开连接,下次加载时重新连接。
- 已知的生命周期边界情况(目前接受;为这些情况设计连接「代」的方案留到后续切片):
- 另一个调用方正在连接时执行断开,在很窄的时间窗口内可能留下两个已启动的子进程,并让竞争失败的那个变成孤儿。
- 空闲断开会等待已经在进行中的连接尝试(最长 connectTimeoutMs)结束后再关闭;只是被排期、尚未开始的重新连接会被取消,而不是推迟断开。
- 默认 reconnectAttempts: 1 时,确定性的发现错误(例如工具名重复)会先重试一次再暴露出来。发现阶段的硬性上限是例外:DiscoveryLimitError(页数/工具数上限或截止时间)是确定性的,会立即暴露,绝不重试。
生态位
dsh-mcp-loader 是若干 DSH 插件之一,这些插件让庞大的 MCP 工具目录不必进入每次请求(可对比 dsh-mcp-lazy、dsh-capability-menu、dsh-tool-folder、dsh-mcp-lens、dsh-tool-search)。
它的差异点:按服务器切换加载器、按智能体用 hiddenTools 做屏蔽、面向模型的描述预设——并且自己持有连接(stdio 和 streamable-http),而不是包装另一个 MCP 客户端。
许可证
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
MikotoMyWife/dsh-mcp-loader
按会话惰性加载 MCP 工具,精简上下文工具列表
相关插件 · 开发 / 工程
隐私简历生成器reactive-resume/reactive-resume
Reactive Resume 已迁至 GitHub 上的…
★ 45,412已汉化MCP
71.7
长时任务执行闭环AMAP-ML/LongHorizon-Harness
面向 Computer-Use Agent 的 Loop Engineering
★ 1,764已汉化DSH
70.5
多代理编排运行时Enderfga/claw-orchestrator
面向编程智能体的运行时。把 Claude Code、Codex、Antigravity、Grok…
★ 586已汉化MCP
69.4
记忆进化插件csyangwen/dsh-memory-evolve
dsh-memory-evolve 使用场景指南
★ 461已汉化DSH
67.9
原生编程智能体paean-ai/deeptide
由 DeepSeek 打造,为 DeepSeek 而生。
★ 1,107已汉化DSH
67.7
北斗运维告警平台aide-family/moon
自建、多租户的运维平台:数据源评测、告警、通知与值班处置在同一条链路上完成。
★ 251已汉化DSH
66.7
这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。