🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

MCP 工具懒加载 MikotoMyWife/dsh-mcp-loader

MCP
MikotoMyWife29 天前有提交已提供中文文档扫描:未发现敏感能力兼容 / 相关生态

按会话惰性加载 MCP 工具,精简上下文工具列表

29.4/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/11/1 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/MikotoMyWife/dsh-mcp-loader.git

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
生态插件
可安装,未声明 dsh 能力
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已真实安装成功
非静态推断
L4 · 真实安装等级说明 →
数据截至 2026/09/25·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/06·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 29 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安装兼容性检查⚠ 装前注意
要求 Node:>=20(dsh 本身要求 Node ≥ 22.19)

未发布到 npm registry,仅可从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-mcp-loader(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=20 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/9/22 13:29:29

安全扫描自动 · 静态分析源码
v2.7.0
🟢 扫描:未发现敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。

发起外部网络请求
查看扫描证据(共 3 处,展示前 3 条)
  • 发起网络请求
    lib/connection.js:550
    const page = await client.request({ method: 'tools/list', params: cursor === undefined ? {} : { cursor } }, RAW_LIST_TOOLS_RESULT_SCHEMA);
  • 发起网络请求
    lib/connection.js:576
    const result = await client.request({
  • 发起网络请求
    lib/connection.js:615
    return await client.request({ method: request.method, params }, RAW_RESOURCE_RESULT_SCHEMA, { signal, timeout: this.#toolCallTimeoutMs });
扫描于 2026/11/6(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 按会话惰性加载工具
  • 按智能体屏蔽工具
  • 配置工具描述预设

为 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
预览分享卡片长什么样 ↓MikotoMyWife/dsh-mcp-loader
分享 · DeepSeek Harness Hub
MikotoMyWife/dsh-mcp-loader

按会话惰性加载 MCP 工具,精简上下文工具列表

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部