前言¶
在 DSH 里接 MCP、装插件、换 preset 之后,注册表里的工具会越来越多。模型侧往往只能看到一份被截断或精简后的工具表:表一长就容易挑错工具;表被截断时,没出现在表里的工具容易被忽略,模型会反复用几个熟面孔凑合。
另外,工具定义通常排在每次请求的最前部。工具表一变,整段前缀缓存就会失效,带来重新计费和首字延迟变长——而工具表又恰恰是最容易变动的一块。
下面介绍社区插件 dsh-tool-gateway(维护者 leolee9086),它把模型可见的工具表收成少量「元工具」,其余工具仍可通过元工具调用,并配套会话开关、工具箱面板、工具组与硬禁用名单。分类为工作流;仓库当前星标为 0。目录页:https://www.skillhub.cn/plugins/leolee9086/dsh-tool-gateway,源码:https://github.com/leolee9086/dsh-tool-gateway。
这是什么¶
dsh-tool-gateway 挂在 DSH profile 层(根作用域),对 preset 与会话施加同一套网关逻辑(会话级总开关除外)。它做两件事:
- 可见性:在装配系统提示时过滤
assembled.tools,让模型可见的工具表主要是find_tools、call_tool,以及在条件满足时的call_tools。 - 执行守卫:拒绝模型对其它工具的直接调用;通过
call_tool(带 parent 的子分发)发起的调用仍走ctx.tools.execute(),审批、守卫、沙箱与会话日志与直接调用一致。
因此,长列表不再堆在模型眼前,而是先 find_tools 查、再 call_tool 调;装插件或改面板开关时,模型可见的工具表字节可以保持不变,变的只是检索索引与守卫判定。
三个元工具¶
| 工具 | 作用 | 何时用 |
|---|---|---|
find_tools |
按名字、描述、中文或拼音检索,返回完整参数 schema | 不知道有什么工具,或不清楚参数怎么写 |
call_tool |
调用单个工具,参数为 {tool_name, arguments} |
一次调一个 |
call_tools |
用一段 TypeScript 程序批量调用 | 连续调多个,中间结果不必进对话 |
find_tools 的结果按 token 估算收缩(默认预算 10000,可配置);单个 schema 不截断。被截断时可用返回的 offset 继续查同一查询。普通查询不会列出会话里关掉的工具;要用 find_tools({scope: "disabled"}) 查看关着的工具——该路径每次需审批,在 danger-full-access 下会直接拒绝。
call_tools 在 DSH PTC 运行时中执行模型写的程序,程序内仅可调用 tools.find_tools({query}) 与 tools.call_tool({tool_name, arguments});只有 return 的值回到对话。参数与输出对齐官方 PTC 的 run_code(含 description 必填、结构化输出与 CodeRunFailedError),但 SDK 声明只保留上述两条,避免把整份注册表再喂给模型。
何时不挂 call_tools:
- 已开启 PTC 模式(
mode: 'ptc'或'both'),且可见集里已有run_code。 - 部署未提供
ctx.ptcRuntime。
检测按会话进行;读不出时保守地不挂载 call_tools。
会话开关、工具箱与工具组¶
会话级总开关¶
Web 会话标题栏有「工具箱 开 / 工具箱 关」chip,控制当前会话是否施加网关约束,默认开。状态持久在 $DSH_HOME/storages/tool_gateway/sessions;子代理跟随父会话。关闭后模型看到完整工具表,可直接调用任意工具;执行守卫立即生效,工具表与提示段落在下一轮请求生效。切换时会通过 agent.inject() 注入一条用户可见通知。无 webServer 的 headless 部署不挂界面,开关固定为默认「开」。
工具箱面板¶
右侧栏「工具」面板列出该会话可见的全部工具(含被网关收起来的)。单工具三态:未设置(跟随组默认)、显式开、显式关。关掉后从 find_tools 结果消失,直接调用会被守卫拒绝;三个元工具不可关。面板改动同样会通知模型。网关开启时,开关只改目录索引与守卫,不用 restrict() 改可见工具表,以免破坏前缀缓存。
工具组¶
注册方可声明一批工具默认关着,避免一次注册几百个工具时面板爆满。示例(摘自 README):
const gateway = ctx.get('toolGateway')
if (gateway !== undefined) {
const group = gateway.registerGroup({
id: 'siyuan-http',
title: '思源 HTTP 端点',
origin: 'dsh-plugin-siyuan',
defaultEnabled: false,
})
ctx.effect(() => () => group.dispose(), 'siyuan: gateway group')
for (const tool of tools) {
ctx.tools.register(tool)
group.add(tool.name)
}
}
未安装网关时 ctx.get('toolGateway') 为 undefined,插件应照常注册工具,只是没有「默认关着」语义。
硬禁用名单¶
部分工具在任何会话、任何路径(含 call_tool 子分发)都不允许执行。默认禁用 ask_user_question。配置 ban: { deny: [] } 表示显式清空禁用列表;完全不写 deny 才使用默认名单。配置项中的名字在面板里也不可切换。
安装与启用¶
插件以当前 DSH 进程权限运行,安装前请自行查看源码与 MIT 许可证。要求 Node >=22.19.0。
dsh plugin --profile web add github:leolee9086/dsh-tool-gateway#v0.3.0
安装会依据包内 dsh.bundle.patch 追加到 dsh.profile.bundles,无需手工改 profile 的 cordis.patch.yml。仓库提交的是 lib/ 产物,从 git 安装不需要 pnpm 构建授权。重启 DSH 生效,不需要改 preset。
典型用法(模型侧)¶
网关开启且会话约束为「开」时,模型侧流程可以概括为:
- 用
find_tools按任务关键词检索,必要时用offset翻页,拿到目标工具的完整 schema。 - 用
call_tool传入tool_name与arguments执行。 - 若需连续多步且中间结果不必进上下文,在 PTC 可用且未与官方
run_code冲突时,用call_tools写短程序,内部只调用tools.find_tools与tools.call_tool。
人在 Web 界面可通过标题栏 chip 关闭单会话约束,或在工具箱面板按工具/按组开关;需要看被关工具时用 find_tools({scope: "disabled"})(受审批策略约束)。
适用场景与注意¶
适合: 工具数量多、经常接 MCP 或热插拔插件,希望模型「先查再调」、并稳定前缀缓存的 DSH 用户;插件作者希望大批量工具默认关着、由用户按需打开。
注意:
- 插件版本以安装标签为准(资料中为
v0.3.0);锁版本可把#v0.3.0换成 commit sha。 - 硬禁用与
danger-full-access下对scope: "disabled"的限制属于安全设计,部署时需理解审批服务行为。 - 社区目录 SkillHub 与 DeepSeek / 幻方无官方从属关系;DSH 生态是「一切皆插件」,本文事实均来自上述仓库 README 与
package.json。
结尾¶
dsh-tool-gateway 用可见性过滤加执行守卫,把工具入口收成检索与调用元工具,并用面板与工具组管理「谁能被查到、谁能被执行」,同时尽量保持模型可见工具表稳定。进一步了解请见目录页 https://www.skillhub.cn/plugins/leolee9086/dsh-tool-gateway 与 GitHub https://github.com/leolee9086/dsh-tool-gateway。