dsh-mcp-lazy:为 DSH 会话按需加载 MCP 工具

前言

在 DSH 里接上多个 MCP server 时,客户端会把每个远端工具注册成 mcp__<server>__<tool>,这些工具的 schema 每轮请求都会随工具列表发给模型。配 5 个 server、每个 10 个工具,就是 50 份定义常驻上下文;而一次会话里往往只会用到其中两三个。常规做法是「全部带着走」,前缀越长,缓存和计费压力越大。

dsh-mcp-lazy(维护者 liuhange789)只做一件事:给每次请求的前缀瘦身——默认只保留 coreTools 白名单里的 MCP 工具定义,其余从本会话的工具集里真正移除;模型需要时再调用 lazy_load_tool 现场装载。它不负责 MCP 的配置、启停或热加载,属于 DSH 社区「工作流」类插件,源码见 GitHub,目录页见 SkillHub。

这是什么

MCP 工具的按需加载插件:非核心工具的定义不会进入 tools.schemas,模型通过 system prompt 里的一行名字清单知道「还有哪些工具可按需打开」,真正用到前先 lazy_load_tool,再调用目标工具。

常规 装上本插件
每轮工具定义 全部 MCP 工具 coreTools + 已激活工具
模型如何知道还有别的工具 看 schema 看 prompt 里的一行名字清单
用到新工具 直接调用 先 lazy_load_tool,再调用

实现上依赖 DSH 的 ctx.tools.restrict({ deny }) 在会话作用域动态收窄工具列表,不是用 systemPrompt 把 schema「藏起来」的降级方案;限制生效后,下一轮请求的工具数组会真的变小。

核心功能

常驻与隐藏

  • coreTools:留在上下文里的 MCP 工具名,最多 5 个,超出会被丢弃并告警;为空时表示所有 MCP 工具都按需加载。
  • 非 mcp__ 开头的名字会被忽略并告警,内置工具不受本插件影响。
  • announceHiddenTools(默认 true):在 system prompt 追加未加载工具的名字清单(只有名字,没有 schema),方便模型调用 lazy_load_tool;设为 false 可关闭,代价是只能从拦截错误里看到工具名。

lazy_load_tool

调用一次,把指定 MCP 工具装进当前会话,之后一直可用,直到会话结束。参数示例:

{ "toolName": "mcp__github__create_issue" }

返回结构化结果(不抛异常),常见 status 包括:activated、already-active、already-core、unknown-tool、not-mcp-tool、no-session、invalid-request 等;失败时 availableTools 可给出可选名字。

执行前拦截

在 tools/pre-execute 上,未加载的 MCP 工具调用会被拒绝,错误信息会指示先对同名工具执行 lazy_load_tool。放行的情形包括:非 MCP 工具、coreTools 中的工具、本会话已激活的工具、以及 enabled=false 时插件完全不介入。

会话生命周期

在 agent/session-start、agent/pre-step 等处执行 reconcile:全局 MCP 工具减去 coreTools 与已激活项,对剩余名字做 restrict;agent/disposed 时解除限制并清激活状态。激活状态是内存态,进程重启或会话 resume 会从「全部未加载」重新开始。

安装与启用

前置条件:MCP 工具必须在 DSH 装配里已经注册;插件只负责「摘」和「装」,不创建 MCP 工具。

下面介绍在 DSH profile(例如 $DSH_HOME/profiles/web)中的装配方式。在 profile 的配置里加入 bundle 与依赖:

{
  "dsh": {
    "profile": {
      "bundles": [
        "@deepseek-ai/dsh-base",
        "@deepseek-ai/dsh-web-app",
        "@liuhange/dsh-mcp-lazy"
      ]
    }
  },
  "dependencies": {
    "@liuhange/dsh-mcp-lazy": "^1.0.0"
  }
}

然后在 profile 目录执行:

npm install

插件自带的 cordis.patch.yml 会插入装配树,一般不需要手改 cordis.yml。许可证为 MIT(见仓库 README)。

配置

配置有两个来源,优先级从高到低。

1. cordis 条目上的 config(profile 的 cordis.yml / cordis.patch.yml):

- id: "@liuhange/dsh-mcp-lazy"
  name: "@liuhange/dsh-mcp-lazy"
  config:
    coreTools:
      - mcp__filesystem__read_file
      - mcp__github__get_issue

2. 独立 JSON 文件 $DSH_HOME/dsh-mcp-lazy.json(DSH_HOME 未设置时为 ~/.dsh/dsh-mcp-lazy.json):

{
  "coreTools": ["mcp__filesystem__read_file"],
  "enabled": true,
  "announceHiddenTools": true
}
字段 类型 默认 说明
coreTools string[] [] 常驻 MCP 工具名,最多 5 个
enabled boolean true false 时插件不介入
announceHiddenTools boolean true 是否在 system prompt 列出未加载工具名

不想动 yml 时,写第二个文件即可。

典型用法

1、装好 profile 与 MCP server,在 coreTools 里填会话里几乎总要用的两三件工具(例如读文件、查 issue)。

2、会话开始后,模型若要用未加载的 MCP 工具,会先看到名字清单或收到拦截提示,再调用:

{ "toolName": "mcp__github__create_issue" }

3、返回 activated 或 already-active 后,下一轮起该工具的 schema 回到上下文,即可正常调用。

Code Mode 下经 tools.execute 的嵌套调用同样会过闸门;若宿主实现绕过 tools/pre-execute 直访问注册表,则只能依赖「工具已不在列表中」的行为。

适用场景与注意

适合谁: 本地或 profile 里挂了较多 MCP server、但单轮对话只用少数工具的智能体开发者;希望压缩每轮 prefix、减轻 schema 堆积,又愿意接受「先用 lazy_load_tool 再调用」的两步流程。

边界(README 已写明): MCP server 在会话开始之后才连上时,其工具要到下一次 agent/pre-step 才会被摘掉,中间一轮仍可能可见;本插件不做跨会话的使用历史学习;只处理 mcp__ 工具。

安全与权限: 插件以当前 DSH 进程的权限运行,装载后的 MCP 工具与普通 MCP 调用权限一致。安装前建议阅读 仓库源码 与 MIT 许可证,再决定是否纳入生产 profile。

社区插件目录 SkillHub 与 DeepSeek / 幻方无官方从属关系;DSH 生态理念是「一切皆插件」,本组件是其中的上下文优化工作流插件。

结尾

dsh-mcp-lazy 把「全量 MCP schema 常驻」改成「核心常驻 + 按需激活」,用会话级 restrict 和 lazy_load_tool 控制前缀体积。需要细节、验证说明与开发命令时,以 GitHub 仓库 README 为准;在站内浏览与归类见 SkillHub 目录页。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye