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

懒加载工具箱 anyi-520/dsh-lazy-toolbox

DeepSeek Harness
anyi-5202 天前有提交已提供中文文档扫描:高危

按需注入技能与 MCP 定义,用完即卸,省下每轮对话的 token

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

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

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add anyi-520/dsh-lazy-toolbox
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · tool
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 2 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
🔴 安全扫描发现高危能力自动 · 静态分析源码
v2.7.0
🔴 扫描:高危尚无人工评估

静态扫描发现安装期即执行代码,或命令参数由运行时变量拼接(参数来源无法静态判定,从严处理)。

安装时即执行脚本可执行外部命令读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 12 处,展示前 12 条)
  • 发起网络请求
    client.js:37
    const response = await fetch(API, options);
  • 发起网络请求
    lib/tools.js:507
    const response = await fetch(url);
  • 发起网络请求
    lib/update.js:133
    this.fetchImpl = fetchImpl ?? ((...args) => fetch(...args));
  • 读取密钥环境变量
    lib/update.js:245
    const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
  • 读取密钥环境变量
    lib/update.js:291
    const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
  • 执行外部命令来自配置/变量
    lib/mcp-client.js:84
    this.child = spawn(command, spawnArgs, {
  • 发起网络请求
    lib/mcp-client.js:211
    const response = await fetch(this.config.url, {
  • 发起网络请求
    lib/mcp-client.js:256
    await fetch(this.config.url, { method: "DELETE", headers: this.headers() });
  • 发起网络请求
    lib/mcp-client.js:349
    const result = await this.request("initialize", {
  • 发起网络请求
    lib/mcp-client.js:366
    const result = await this.request("tools/list", {}, signal);
  • 发起网络请求
    lib/mcp-client.js:379
    const result = await this.request("tools/call", {
  • 发起网络请求
    lib/mcp-client.js:391
    return this.request("ping", {}, signal);
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DeepSeek Harness 插件:把 skill 与 MCP 从默认工具定义里抽出来,改成按需热加载的懒工具箱(skill / mcp 分开列出,一句话说明用途,用时注入、用完卸载)

README

由 DeepSeek 最新模型翻译生成
dsh-lazy-toolbox 仓库:<https://github.com/anyi-520/dsh-lazy-toolbox> · 安装: git clone https://github.com/anyi-520/dsh-lazy-toolbox.git node dsh-lazy-toolbox/bin/cli.mjs wire-profile # 挂进 profile 并加好配置行 也可以下 Release 附件 解压后同样一条命令;npm 发布后可直接 dsh plugin add dsh-lazy-toolbox。 把技能和 MCP 从「每个对话都塞进工具定义」改成「列个目录,用时才注入」。 DSH(DeepSeek Harness)默认会把所有技能、所有 MCP 服务的完整工具定义(名字 + 描述 + 参数 schema)推进每一次请求。装的技能 / MCP 越多,每轮对话要付的 token 越大、模型挑工具的噪声越高。 dsh-lazy-toolbox 做三件事: 1. 搬走:安装时把本机技能目录、配置档里的 mcp-client 配置整体搬进插件库,DSH 因此不再把它们放进全局工具定义。卸载时按原文原位置还原。 2. 留目录:系统提示里只留一份清单 —— skill 与 mcp 分开列,每条一句话用途,不含任何调用参数。
展开完整文档(README 剩余 1 节)
dsh-lazy-toolbox

仓库:<https://github.com/anyi-520/dsh-lazy-toolbox> · 安装:
git clone https://github.com/anyi-520/dsh-lazy-toolbox.git
node dsh-lazy-toolbox/bin/cli.mjs wire-profile # 挂进 profile 并加好配置行

也可以下 Release 附件 解压后同样一条命令;npm 发布后可直接 dsh plugin add dsh-lazy-toolbox。

把技能和 MCP 从「每个对话都塞进工具定义」改成「列个目录,用时才注入」。

DSH(DeepSeek Harness)默认会把所有技能、所有 MCP 服务的完整工具定义(名字 + 描述 + 参数 schema)推进每一次请求。装的技能 / MCP 越多,每轮对话要付的 token 越大、模型挑工具的噪声越高。

dsh-lazy-toolbox 做三件事:

1. 搬走:安装时把本机技能目录、配置档里的 mcp-client 配置整体搬进插件库,DSH 因此不再把它们放进全局工具定义。卸载时按原文原位置还原。
2. 留目录:系统提示里只留一份清单 —— skill 与 mcp 分开列,每条一句话用途,不含任何调用参数。
3. 热加载:模型需要时调用 toolbox,把那一项的定义注册进当前会话(agent.ctx 作用域,只影响这一个对话),用完 unload 撤掉,下一轮请求立刻变小。

安装前 安装后 ┌──────────────────┐ ┌──────────────────┐ │ tool: mcp__gh__x │ │ tool: toolbox │ ← 常驻,唯一的入口 │ tool: mcp__gh__y │ │ prompt: 目录 │ ← skill/mcp 各一行,无 schema │ tool: mcp__db__q │ └──────────────────┘ │ ... 40 个 │ │ load └──────────────────┘ ▼ ┌──────────────────┐ │ 本会话工具表 │ ← 只有此刻需要的定义 └──────────────────┘

快速开始

从图形界面装(最省事)

插件 → 添加插件,填本地目录路径(解压出来的 dsh-lazy-toolbox 目录)或包名都行。
包里有 dsh.bundle 声明(cordis.patch.yml),DSH 会自己写好依赖、bundles 和配置行,重启生效。

0.7.0 及更早没有这个声明,安装器会报 这个包没有声明组合包,无法作为插件安装:dsh-lazy-toolbox declares no dsh.bundle,换 0.7.1+ 即可。

从本地目录接入(开发 / 自用)

1) 把插件接到 profile(bundles + insert 行 + node_modules 链接,幂等) dsh-lazy-toolbox wire-profile

2) 重启 dsh,插件首次启动会自动迁移本机 skill 与 MCP 配置

也可以让 dsh 的插件管理器装它,或直接写进配置档:

// $DSH_HOME/profiles/<profile>/package.json
{
"dependencies": { "dsh-lazy-toolbox": "link:D:/path/to/dsh-lazy-toolbox" },
"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "...", "dsh-lazy-toolbox"] } }
}

$DSH_HOME/profiles/<profile>/cordis.patch.yml 末尾
- insert:
- id: lazy-toolbox
name: dsh-lazy-toolbox
inject: [systemPrompt, tools]
config:
autoImport: true
autoUnloadOnTurnEnd: true

从 npm 安装

npm i -g dsh-lazy-toolbox
dsh-lazy-toolbox wire-profile

模型看到什么

系统提示里多出这样一段(节选):

懒工具箱(skill / MCP 按需加载)下面这些能力已经安装但不在当前工具列表里(所以你看不到它们的参数)。需要时调用 toolbox:
- toolbox { action: "load", ids: ["skill:<名字>" 或 "mcp:<服务>" 或 "mcp:<服务>:<工具>"] } 把定义注入本会话;
- toolbox { action: "unload", ids: [...] }(或 all: true)把定义撤掉,减少后续请求体积;
- toolbox { action: "list", ids: [...] } 展开某个 MCP 服务的工具清单;
- 用户要求安装新的 skill / MCP 时用 action: "add_skill" / "add_mcp",并给一句话 summary。

skills:
- skill:release-notes — 按提交记录生成发版说明 [已加载]
- skill:sql-review — SQL 变更评审清单

mcp:
- mcp:github — GitHub 仓库、Issue 与 PR 操作,38 个工具
- mcp:postgres — 只读 SQL 查询 load 之后,mcp__github__ 才会出现在该会话的工具表里;unload(或回合结束)后消失。
目录里的 [已加载] 是给模型的状态提示,不影响其他会话。

新会话不会被蒙在鼓里

光有目录还不够:模型容易扫一眼就当没看见,直接凭记忆答。所以插件另外注册了 运行时上下文提醒(systemPrompt.context),每个会话一开始就出现在上下文快照里:

懒工具箱:本机还装了 2 个 skill、1 个 MCP 服务,它们不在工具定义里,详情见系统提示里的目录(每条一句话用途)。只要当前任务和某条用途对得上,先调用 toolbox { action: "load", ids: ["skill:<名字>"] }(MCP 用 "mcp:<服务>")把定义注入本会话,再动手;不要因为工具列表里没有、就跳过它或凭记忆作答。
用完用 toolbox { action: "unload", ... } 撤掉。

- 每个会话都有,加载过东西之后这条文本变成空串,DSH 会把它从上下文快照里过滤掉,不占 token;
- 因为默认 autoUnloadOnTurnEnd,每个新的用户回合会重新提醒一次 —— 正是「别的对话不知道有这个插件」的对症药;
- 库里为空(没装任何 skill / MCP)时不输出,不会无中生有。

toolbox 的全部动作

| action | 作用 |
| status | 插件库概况、本会话已加载项、待还原记录 |
| list | 目录(skill / mcp 分列);ids 指定某个 mcp:<服务> 时展开它的工具清单 |
| load | 把 ids 里的项目注入当前会话;skill 直接给出正文 |
| unload | 撤掉 ids(或 all: true)注入的定义 |
| add_skill | 从本地路径或 http(s) URL 导入 skill(也支持 git 仓库) |
| add_mcp | 登记并先连一次验证 MCP,成功后记录工具数;失败自动回滚 |
| remove | 从插件库删除 skill 文件 / MCP 配置(ids:["skill:x"],也接受单个 id) |
| enable / disable | 打开 / 关闭某个 skill 或 MCP 服务(等价于设置页里的那个开关) |
| skill | 按需取某个 skill 的某一节正文(大纲模式下的「看详情」;section: "all" 整篇) |
| mode | 设置某条目加载方式:mode: "lazy"(懒加载)或 "skip"(跳过懒加载) |
| update | 云更新:step: "check" 查新版本、"download" 下载解压、"install" 覆盖安装(装完需重启) |
| code | 内置代码编辑器:step: "read" / "validate" / "write" / "patch" / "revert",写前先校验、不通过不落盘(见 docs/editor.md) |
| discover | 扫一遍已安装插件自带的 skill / MCP,发现就接管(dry_run: true 只看不写) |

设置页:懒加载 / 工具 / 关于

设置 → 懒工具箱 分三个标签(顶部还有一张插件名片:图标 + 正常/未就绪 + 版本 + 来源信息):

- 懒加载:三类开关(插件工具 / skill / MCP)与每条的加载方式;
- 工具:扫描插件内置资产、撤掉本会话注入、内置代码编辑器(读写文件不经过终端,写前先做语法校验,错了直接给行号列号)、导入插件 zip(拖进去就装,见 docs/plugin-zip.md)、云更新(检查 / 下载 / 安装);
- 关于:介绍软件、感谢名单、制作名单(头像 + 名字 + 角色)。

关于页的头像走插件自己的只读端点 /dsh-lazy-toolbox/avatar/<文件名>,文件放在 <数据目录>/assets/avatars/(换掉 anyi.jpg 就换头像,刷新生效;只认图片后缀,路径只取 basename,越不出这个目录)。

进 DSH 后会自动查一次新版本(约 4 秒),有新版就弹窗:本次不提醒 / 今天不提醒 / 更新。

外部工具链(JDK / Ghidra / rea-agents / JADX / IDA)的检测与一键安装已经拆成独立插件 dsh-toolchain:那边有独立的 toolchain 工具与设置 → 工具链 页面。本插件的 toolbox 不再提供 requirements / install。

插件工具:把别的插件的工具也变懒

有的插件一次注册十几个工具(比如内存工作台的 17 个 mem_),聊什么都没它们的份,却一直占着工具定义。现在它们可以把工具交给懒工具箱托管:

插件工具(别的插件交出来托管的)
- group:memstudio — 内存工作台:附加进程 / 读写搜索 / 断点 / 指针链 / 冻结〔插件 dsh-memstudio〕,17 个工具:mem_targets, mem_apps, …

启动时它一个工具都不注册;要用时 toolbox { action: "load", ids: ["group:memstudio"] } (或只挑一个 group:memstudio:mem_read),用完 unload。设置页里「插件工具」单独一栏,同样可选 懒加载 / 跳过。

插件侧接入就两行(全局符号桥,不挑安装路径):

const bridge = globalThis[Symbol.for("dsh-lazy-toolbox.bridge")]
if (bridge) bridge.provideToolGroup({ id: "memstudio", summary: "一句话用途", tools })
else for (const t of tools) ctx.tools.register(t) // 没装懒工具箱就照旧常驻

细节见 docs/plugin-tools.md。

云更新:查新版本 → 看更新内容 → 下载 → 安装 → 提示重启

云更新卡片在「工具」标签里(不在「关于」),它问的是本仓库的 GitHub Release:

当前 v0.5.3 · 有新版本 0.6.0 [检查更新] [下载 v0.6.0] [安装 v0.6.0] (下面是这个 Release 的更新内容,可滚动)

- 检查:GET /repos/<updateRepo>/releases/latest,结果落盘在 <数据目录>/update-state.json;启动时先显示缓存,再延迟 4 秒后台查一次,不阻塞启动;
- 下载:发布包 zip 下到 <数据目录>/updates/ 并解压好,大小对不上直接报错;
- 安装:先把现版本文件备份到 updates/backup-<版本>-<时间戳>/,再覆盖插件本体; node_modules / .git / 数据目录不碰;
- 装完只提示重启:红字「请关掉 DSH 再打开」——插件不会自己重启进程。

三条路径都行:设置页按钮、命令行 dsh-lazy-toolbox update check|download|install、 AI 侧 toolbox { action: "update", step: "check" }。细节见 docs/update.md。

设置 → 懒工具箱:插件工具 / skill / MCP 三类开关

设置页第一屏就是全部 skill 与全部 MCP(分两组),每条一行:名字、一句话用途、工具数 / 来源,右边一个开关。关掉之后:

- 它不再出现在系统提示的目录里,AI 也就不会再被告知它存在;
- toolbox action="load" 会明确拒绝(「在设置页里是关闭状态」),不会偷偷加载;
- 文件与配置都还在(store.json 里记成 disabled.skills / disabled.mcp),点一下就能回来。

适合「装了很多但这一轮用不到」的场景:不用删,也不会占目录与提示的 token。

// store.json 片段
"disabled": { "skills": ["reverse-engineer-anything-cn"], "mcp": [] }

skill 只注入大纲,正文按需取

一个 3 万 token 的 skill(比如「漫剧制作流程」),load 时不整篇塞进上下文,只给:

- 一句话用途(本来就在目录里);
- 大纲:每个分支(小节)一行,带一句人话概括;
- 取节方式:toolbox { action: "skill", id: "skill:ds", section: "2" } 只回「分镜」那一节, section: "all" 才整篇。

没有多一个工具定义——取节走的是常驻的 toolbox。细节见 docs/skill-index.md。
要整篇:单个 skill 在 store.json 写 loadMode: "full",或全局 skillInjectMode: full。

加载方式:懒加载 / 跳过

设置页每个条目右边是两段式选择器:懒加载(进目录、按需注入)或 跳过 (不做懒加载:不进目录、load 拒绝,文件与配置都还在)。AI 侧等价动作是
toolbox { action: "mode", ids: [...], mode: "skip" },命令行是 dsh-lazy-toolbox mode <id> skip。

「不做懒加载」名单(破甲类插件)

有些插件自己就往系统提示词里 hook 一大坨提示词,或自带「教怎么绕过限制」的 skill。
这类插件的内置资产不接管、不进目录(避免和插件自己的注入打架、也避免一句话骗过 AI):

- 内置名单:dsh-purge、dsh-jailbreak、dsh-uncensored、dsh-prompt-inject 等;
- 内置模式:包名/条目名含 jailbreak / 破甲 / 越狱 / uncensor / nsfw / prompt-inject 等;
- 追加自己的:neverLazyExtra: ["my-plugin"];关掉内置名单:neverLazyBuiltin: false;
- 只影响懒工具箱的接管,不删任何文件。细节见 docs/never-lazy.md。

插件自带的 skill / MCP:自动接管

有些插件自己就带能力(skills/ 目录、mcp.json,或 package.json 里的 dsh.skills / dsh.mcp)。
0.5.2 起这些会被自动登记进插件库,不用你一个个 add_skill:

- 扫描时机:插件启动时 + 每次扫描(内容没变时按指纹跳过,不重复读盘);
- 原地引用:不复制文件,插件升级后 load 到的就是新内容;
- 幂等 + 卸载回收:插件没了,条目下一轮自动删掉;你 disable / remove 过的不再复活;
- 不想被接管:package.json 里写 "dsh": { "autoDetect": false };
- 想立刻扫:node bin/cli.mjs discover [--dry-run],或让 AI 调 toolbox { action: "discover" }。

支持的全部写法、配置字段与例子见 docs/plugin-assets.md,插件骨架见 examples/plugin-with-skill/。

面板与 AI 看到的是同一份事实:GET /dsh-lazy-toolbox/api 返回的 inventory,改开关走 POST {"op":"toggle","id":"skill:<名字>","enabled":false}。

工具链面板已拆走

外部引擎(JDK / Ghidra / rea-agents / JADX / IDA)的检测、一键安装与 env 同步都在独立插件 dsh-toolchain 里:它有独立设置页 设置 → 工具链(order 55,排在懒工具箱之前)和常驻工具 toolchain。本插件不再注册工具链面板,也不再调用 applyEnv()。
拆分时状态文件 $DSH_HOME/lazy-toolbox/requirements.json 原样保留:dsh-toolchain 首次加载时会读它,写进自己的 $DSH_HOME/toolchain/requirements.json。所以拆完面板上立刻显示「已安装」,不用重装几百 MB 的引擎。MCP 服务注册表 store.json 仍由本插件维护,dsh-toolchain 只往里写 REA 条目的 env。

写操作失败时返回一段可读结果(# add_skill 失败 …),不会把异常直接抛给模型。

add_skill / add_mcp 都会要求一句话 summary —— 这就是目录里那一行用途。

生命周期

| 时机 | 行为 |
| 插件启动 | 迁移 profile 里的 mcp-client 条目、$DSH_HOME/skills、~/.agents/skills(可选项目目录) |
| 每个 pre-step | 节流扫描:AI 之后下载进标准目录的 skill、新加的 mcp-client 行,自动搬进来并补一句话用途 |
| 回合结束 | 默认自动卸载本会话注入的定义(autoUnloadOnTurnEnd),把请求体积还回去 |
| agent 销毁 | 撤销该 agent 的全部注入,关闭空闲 MCP 连接 |
| 插件卸载 | preuninstall 先还原全部 skill 与 MCP 行,再摘 profile 接线 |

还原语义:MCP 行保存的是原文整块 + 原始行号,还原时按行号写回;skill 目录整体移回原位。文件被外部改过时,先写 <file>.lazy-toolbox-backup 再动。冲突(同名已存在)一律跳过并报告,从不覆盖。

配置

config:
dataDir: "" # 插件库位置,默认 $DSH_HOME/lazy-toolbox autoMigrate: true # 启动时迁移 autoImport: true # 运行期自动导入新 skill / 新 mcp 行 autoImportProjectSkills: false # 是否也接管项目里的 .dsh/skills scanIntervalMs: 5000 # 自动导入的节流间隔 autoUnloadOnTurnEnd: true # 回合结束自动卸载 mcpIdleMs: 60000 # MCP 连接空闲多久关掉 maxCatalogItems: 200 # 目录最多列多少条 autoDetectPluginAssets: true # 自动接管插件自带的 skill / MCP updateRepo: anyi-520/dsh-lazy-toolbox # 云更新查的仓库(可换 fork) updateCheck: true # 启动时自动检查新版本 updateCheckHours: 6 # 隔多久再查 skillInjectMode: index # skill 注入方式:index(只给大纲)| full(整篇) skillSectionMaxChars: 60000 # action=skill 单次回传上限 neverLazyBuiltin: true # 「不做懒加载」内置名单
neverLazyExtra: [] # 额外名单(包名子串)
logEnabled: true # 本地运行日志(只写文件,设置页不显示) logDir: "" # 日志目录,默认 $DSH_HOME/lazy-toolbox/logs logLevel: info # debug | info | warn | error logMaxBytes: 2097152 # 单个日志文件上限,超了就分卷 logRetentionDays: 14 # 保留天数,0 = 不清理

运行日志(本地)

插件把自己的功能调用和错误写成 JSONL,只落本地文件,设置页里看不到任何东西:

$DSH_HOME/lazy-toolbox/logs/plugin-YYYYMMDD.log # 超 2 MB 分卷成 .1 .2 …

一行一条,字段固定 ts / level / event / pid,其余按事件附带:

| event | 记录内容 |
| plugin.start / plugin.stop | 版本、数据目录、生效配置、运行时长 |
| toolbox.call | 每次 toolbox 调用:action、ids、ok、ms,失败带 error.stack |
| toolbox.failed | guard() 兜住的写操作失败(add/remove/enable/disable) |
| inject.load / inject.unload | 逐条注入/移除结果(成功与否、注入了几个工具定义) |
| mcp.connect / mcp.close | 连的哪个 MCP、传输方式、命令;连不上带堆栈 |
| api.request | 设置页的 HTTP 调用:方法、op、id、状态码、耗时 |
| scan.failed / migrate. | 自动导入与迁移的结果/失败 |

写日志失败会被静默吞掉(日志不能拖垮插件),超长字符串截断到 2000 字符,按天分文件、超限分卷、按 logRetentionDays 自动清理。看日志:

dsh-lazy-toolbox logs # 最近 100 条,人类可读 dsh-lazy-toolbox logs --lines 20 --raw # 原样 JSONL,方便 grep / jq dsh-lazy-toolbox logs --path # 只打印今天的文件路径

命令行

dsh-lazy-toolbox status # 插件库概况 dsh-lazy-toolbox list # 目录 dsh-lazy-toolbox migrate [--dry-run] [--project] dsh-lazy-toolbox restore [--skills-only|--mcp-only] dsh-lazy-toolbox add-skill <path> [--name n] [--summary "一句话"] dsh-lazy-toolbox add-mcp <name> --command "npx" --args "-y some-mcp" [--verify] dsh-lazy-toolbox remove skill:<name>|mcp:<server> dsh-lazy-toolbox enable skill:<name>|mcp:<server> # 打开(等同设置页的开关) dsh-lazy-toolbox disable skill:<name>|mcp:<server> # 关闭:不进目录、不能 load,文件还在 dsh-lazy-toolbox wire-profile [--profile <dir>] dsh-lazy-toolbox unwire-profile [--profile <dir>] dsh-lazy-toolbox discover [--dry-run] # 扫插件自带的 skill / MCP dsh-lazy-toolbox update check|download|install # 云更新三步 dsh-lazy-toolbox mode skill:<名字> lazy|skip # 加载方式:懒加载 / 跳过 dsh-lazy-toolbox skill <名字> [--section <id>|all] # 看大纲 / 取某一节 dsh-lazy-toolbox logs [--lines N] [--raw] [--path] # 本地运行日志 dsh-lazy-toolbox doctor # 自检:数据目录、存储、链接状态

--data-dir 可指向别的插件库(测试用)。

为什么能做到「只影响当前会话」

DSH 的工具注册表按 agent 作用域分层(@deepseek-ai/dsh-scope)。agent.ctx.tools.register(def) 注册的定义只对该 agent 可见,返回值是精确的撤销函数;agent 销毁时作用域整体回收。
本插件不碰全局注册表,只往当前 agent 的作用域里加/减,所以:

- 会话 A 加载的 MCP 工具,会话 B 看不到;
- 卸载只影响发起卸载的会话;
- 进程重启后一切回到「只有目录」。

设计取舍

- 零运行时依赖:MCP 客户端(stdio + streamable-http)、YAML 子集解析、schema 收敛都在仓库内实现。
不 import 任何 @deepseek-ai/,避免 profile 的 .pnpm 提升与 asar 解析问题;与 DSH 的全部交互都走 ctx 服务。
- schema 有损降级:DSH 只接受 type/oneOf/properties/required/additionalProperties/items/enum/const 加注解,MCP 常见的 $ref、anyOf、format 会被拒绝。这里统一收敛,宁可丢约束也不让整个服务加载失败。
- 卸载是卸载:不删用户文件,只搬走再搬回。

兼容性

- DSH Desktop 0.2.1-rc.x(inject: [systemPrompt, tools],tools.register 需要 output.schema + render)
- Node.js >= 20

开发

node --test --test-force-exit "test/*.test.mjs" # 21 个测试
node bin/cli.mjs doctor

测试里有一个真实的 stdio MCP 样本(test/fixtures/fake-mcp-server.mjs),MCP 客户端、注入、卸载、回合结束清理、schema 收敛都是真跑的,不打桩。

目录结构

lib/
index.js 插件入口:注册 toolbox、目录 section、迁移与钩子 tools.js 常驻工具 toolbox 的动作实现 inject.js 按会话注入/卸载 mcp.js MCP 连接池、工具名规范化、定义包装 mcp-client.js stdio / streamable-http 传输 skills.js skill 发现、搬入、加载、还原 migrate.js 迁移与还原(MCP 行 + skill 目录) profile.js profile / cordis.patch.yml 的文本级读写 schema.js 上游 JSON Schema → DSH 子集 store.js 插件库(store.json + skills/) discover.js 插件内置 skill / MCP 的发现与接管(原地引用) outline.js skill 大纲:骨架 + 每节一句话 + 按需取节 denylist.js 「不做懒加载」名单(破甲类插件) update.js 云更新:检查 / 下载 / 覆盖安装(先备份,装完提示重启) tool-groups.js 插件工具托管:别的插件把工具交出来,目录里只留一行 + 全局符号桥 log.js 本地运行日志(JSONL,按天分卷 + 保留期清理) util.js 文件、路径、frontmatter 工具 bin/cli.mjs 命令行 scripts/ postinstall / preuninstall 钩子

License

MIT,见 LICENSE。
预览分享卡片长什么样 ↓anyi-520/dsh-lazy-toolbox
分享 · DeepSeek Harness Hub
anyi-520/dsh-lazy-toolbox

按需注入技能与 MCP 定义,用完即卸,省下每轮对话的 token

这是你的仓库?认领条目

回到顶部