dsh-mcp-setting
v0.2.0
Published
DeepSeek Harness 设置界面管理 MCP 服务器:增删改 cordis.patch.yml 中的 @deepseek-ai/dsh-mcp-client 行,并可按会话工作区挂载
Readme
dsh-mcp-setting
DeepSeek Harness 插件:在「设置」界面管理 DSH 配置文件里的 MCP 服务器。
功能
设置面板新增「MCP 服务器」页面,直接增删改 cordis.patch.yml 中的
@deepseek-ai/dsh-mcp-client 行:
- 列表:展示
$DSH_HOME/cordis.patch.yml(主配置)与$DSH_HOME/profiles/<name>/cordis.patch.yml(各 profile 补丁)中的全部 MCP 服务器, 标注来源与端点摘要。 - 连接状态:每台服务器实时显示状态徽标(已连接 · 工具数 / 未连接 / 启动失败 /
加载中 / 其他 profile 未加载),页面每 5 秒静默刷新。状态由加载器 fiber 与工具
注册表(
mcp__<serverName>__*前缀)推断,不依赖 mcp-client 内部实现;断线重连的 退避窗口内可能短暂显示「已连接」。 - 开关 / 范围:每台服务器可选择全局(进程内加载一次)、工作区(只在匹配的
会话里挂载,见下节)或停用;全局/停用写入 loader 行的
disabled标志,DSH 的配置 热加载会即时生效(无需重启)。 - 工作区规则:选择「工作区」后填写路径规则(每行一条,支持
*、**、?), 规则存放在$DSH_HOME/dsh-mcp-setting.workspaces.json;页面显示规则文件路径与当前 生效的会话数。 - 项目配置:识别工作区自带的
.dsh/mcp.json(见下节),逐目录展示并需要显式「信任」 才会挂载;条目、解析错误与会话免于启动的执行命令都先在页面上可见。 - 会话信息条:输入框下方的信息条新增
MCP计数控件,显示当前会话可用的 MCP 服务器 数量;点击展开小窗,逐条列出服务器名、来源(全局 / 工作区 / 项目)、状态与已注册工具数、 以及启动命令或地址。点击其它控件或按 Esc 即关闭,与信息条上的统计控件一致。 - 重启:页面顶部「重启 DSH」按钮(两次点击确认),以原命令行重新拉起 DSH 进程,页面自动刷新等待应用恢复。
- 新增:写入主配置文件(
$DSH_HOME/cordis.patch.yml),自描述头注释自动补齐。 - 编辑 / 删除:作用于服务器所在文件;空掉的
insert补丁条目一并移除。 - 校验:与
@deepseek-ai/dsh-mcp-client的配置契约一致(id / serverName 唯一且 匹配命名规则,stdio 必须填写 command,streamable-http 必须填写 url),错误直接 拒绝写入并返回中文提示;编辑时保留表单未展示的字段(reconnect、 toolCallTimeoutMs 等),切换传输方式时自动清理另一侧的字段。 - 安全:所有写操作仅允许本机回环访问;每次写入前保留
.bak备份,临时文件 + 改名原子落盘;yaml文档级编辑,未触碰的注释与!!js表达式原样保留。
增删改与开关都会写入
cordis.patch.yml,DSH 的配置热加载(profile 与主配置的cordis.patch.yml监视)即时生效;完整重载可使用页面上的「重启 DSH」。
按会话工作区启用 MCP
DSH 的配置行是进程级的,没有「进入某个目录自动开关 MCP」的机制。本插件补上这一段:
把服务器设为工作区后,插件在每个新会话创建时读取该会话的工作目录,匹配则把
@deepseek-ai/dsh-mcp-client 挂进这个会话自己的作用域(@deepseek-ai/dsh-scope),
会话销毁时卸载。工具因此只对该会话可见,其它会话看不到、也不会启动对应的服务器进程。
| 模式 | 补丁文件中的行 | 何时加载 |
| --- | --- | --- |
| 全局 | disabled 不存在 | DSH 启动时加载一次,所有会话可见 |
| 工作区 | disabled: true(插件接管该标志) | 每个工作目录匹配的新会话,各自挂载 |
| 停用 | disabled: true | 不加载 |
工作目录规则:
- 每行一条路径,
*匹配单层、**跨层(**/也匹配零层)、?匹配一个字符; 写到目录时同时覆盖其子目录(E:/Project/ue也匹配E:/Project/ue/Source/Game)。 - 路径按正斜杠归一化,Windows 上大小写不敏感,
\与/等价。 - 规则文件:
$DSH_HOME/dsh-mcp-setting.workspaces.json({ "version": 2, "servers": { "<行 id>": { "patterns": ["E:/Project/**"] } }, "projects": { "<目录绝对路径>": { "trusted": true, "lastSeen": 0 } } }), 与补丁文件一样先备份.bak再原子落盘。可用插件行配置项workspaceStore改路径; 版本 1 的旧文件按缺少projects读取,下一次写入升到版本 2。
行为与限制:
- 在会话创建(含恢复)时确定:此后在同一会话里用
working_directory切换目录不会 重新判断;把一台服务器改成「工作区」后,已经在运行的会话也不会补挂,需要新建或 重新打开会话。插件被重载(HMR / 重启后重新装载)时会为仍然活着的会话补挂一次, 所以重载不会让这些会话丢掉工作区服务器。 - 子会话默认不挂载:挂载只对根会话生效。DSH 里子 agent 的作用域不会继承父会话的
作用域(只有 agent preset 会显式建立作用域父子关系),所以默认子 agent 看不到这些
MCP;需要时在插件行配置
workspaceSubagents: true,每个匹配的子会话会各自启动一份 服务器进程。 - 只挂载当前运行 profile 与主配置层里的行(主配置优先级更高);只存在于其它 profile 补丁里的行不会被挂载。
- 规则文件损坏时:列表仍可打开(该次读取按「无规则」处理并在日志报警一次),但任何 范围写入会被拒绝(HTTP 409,提示具体文件路径),避免静默覆盖其它规则。
- 服务器启动失败只记录日志,不阻断会话创建;该会话其余服务器照常挂载。
- 修改插件的行配置(
workspaceStore/workspaceSubagents)需要重载该插件行, 通常重启 DSH。
工作区自带的 .dsh/mcp.json
除了在设置界面里配置,工作区还可以自带一份 .dsh/mcp.json(形状与 Claude Code 的
.mcp.json 相同),让项目自己声明需要哪些 MCP 服务器:
{
"mcpServers": {
"ue-assets": { "command": "node", "args": ["tools/server.js"], "cwd": "tools", "env": { "TOKEN": "x" } },
"ue-remote": { "type": "http", "url": "http://127.0.0.1:8123/mcp", "headers": { "Authorization": "Bearer x" } }
}
}- 发现:新会话创建时,从其工作目录向上查找最近的一份
.dsh/mcp.json(最多 32 层), 嵌套项目覆盖父工作区。发现但不信任时只记录一条日志,不启动任何程序。 - 信任:
.dsh/mcp.json随仓库克隆而来,条目里写的是要执行的程序,因此必须先在 「设置 → MCP 服务器 → 项目配置」中信任该目录,其中的服务器才会挂载;也可以在插件行 配置trustedWorkspaces: [...]中预置受信任目录(用于无人值守部署)。 - 挂载:只对该工作区的会话生效,随会话销毁卸载;与「工作区规则」命中的服务器一起挂载,
serverName同名时以规则行优先并记录一条警告。 - 字段:stdio 用
command/args/env/cwd,http 用type(http或streamable-http,也可省略由url推断)/url/headers;cwd的相对路径按工作区 目录解析;toolCallTimeoutMs、failOnStartupError、maxInstructionBytes、reconnect原样透传;其余字段忽略;sse不受支持(该条会被跳过并在页面上给出原因)。 - 失败:单条声明非法只跳过该条;文件不是合法 JSON 时整份不可用,设置页直接显示解析错误。
- 开关:插件行配置
workspaceFiles: false可整体关闭检测(默认开启)。
行配置项
工作区相关的默认值都在插件行上,写在 $DSH_HOME/cordis.patch.yml(主配置层,优先级高于
profile 补丁);全部可省略,只有需要改默认值时才写:
- insert:
- id: dsh-mcp-setting
name: 'dsh-mcp-setting'
config:
workspaceSubagents: true # 匹配的子会话也各自挂载(默认 false)
workspaceFiles: true # 检测工作区自带的 .dsh/mcp.json(默认 true)
workspaceStore: 'D:/dsh/dsh-mcp-setting.workspaces.json' # 默认 $DSH_HOME/dsh-mcp-setting.workspaces.json
trustedWorkspaces: # 免点击「信任」的目录,用于无人值守部署
- 'E:/Project/myproj'dshHome 由宿主注入(配置文件的根目录),一般不需要写。修改这些键需要重载该插件行,
通常重启 DSH;设置界面里的三态与信任记录不需要重启,但要在新会话里才生效。
兼容性
当前版本面向 DSH 0.2.0-rc.2(npm 上的 next 发布线;桌面版 44.7.0 运行的
0.2.1-rc.2 同样落在下面的 peer 范围内):
| 依赖 | 声明 | 说明 |
| --- | --- | --- |
| @deepseek-ai/dsh-* | ^0.2.0-rc.2 | 随 DSH 发布线同步升级 |
| @deepseek-ai/dsh-mcp-client | ^0.2.0-rc.2 | 工作区范围在会话作用域里挂载它 |
| @deepseek-ai/dsh-scope | ^0.2.0-rc.2 | 为每个会话创建独立作用域并随会话释放 |
| @deepseek-ai/dsh-agent | ^0.2.0-rc.2 | 只用类型:agent/created、agent/disposed |
| @deepseek-ai/dsh-client-ui-conversation | ^0.2.0-rc.2 | 只用类型:conversation.composer.dock 槽位声明 |
| @deepseek-ai/dsh-client-ui-session | ^0.2.0-rc.2 | 只用类型:会话槽位携带的 sessionId |
| @deepseek-ai/dsh-client-ui-primitives | ^0.2.0-rc.2 | 信息条控件复用 Pill / StateDot |
| @deepseek-ai/cordis | ^4.0.4 | 0.2.0-rc.2 的 DSH 包要求 ~4.0.4 |
| @deepseek-ai/schemastery | ^3.18.4 | 同上,避免与宿主内的 schema 版本漂移 |
DSH 会拒绝安装或激活 DSH peer 依赖不满足当前运行版本的插件,并提示「……与 DSH x.y.z
不兼容(要求 …),运行它可能导致崩溃或数据丢失」。判定逻辑在
@deepseek-ai/dsh-app-boot 的 evaluatePluginCompatibility:逐个检查
@deepseek-ai/dsh / @deepseek-ai/dsh-* 形式的 peer 依赖,任一
semver.satisfies(运行时版本, 区间, { includePrerelease: true }) 为假即拒绝;
运行时版本取自 app-boot 包自身的 package.json。因此 0.1.3 声明的
^0.1.2-alpha.1 不接受任何 0.2.x 运行时,在 DSH 0.2.0-rc.2 上会被拒绝。
升级 DSH 后必须同步把本插件的 peer 区间改到同一发布线并重新发布。
兼容性由三道检查守住
pnpm test # tests/compatibility.spec.ts:用与 DSH 相同的判定复核 peer 声明
pnpm typecheck # 对着 node_modules 中真实的 0.2.0-rc.2 类型编译 src/
pnpm typecheck:tests # 再编译 tests/ 与 scripts/(夹具与契约同步,防漂移)
pnpm smoke # 真实 src/index.ts + 临时 DSH home,端到端跑一遍 API 路由
pnpm smoke:client # 真实 lib/client.js 走 __ModuleLoader__,核对平台模块表tests/compatibility.spec.ts用与 DSH 相同的判定复核package.json的 peer 声明,并校验dsh.client.inject中的每个 DSH 客户端包都有对应的 peer 声明, 避免同类不兼容再次漏到用户侧。pnpm smoke导入真实的src/index.ts,在一个临时$DSH_HOME上跑通 列表 / 新增 / 编辑 / 开关 / 删除 / 回环校验,覆盖ctx.webServer.register、ctx.effect、resolveDshHome等 0.2.0-rc.2 接口。pnpm smoke:client在 Node 中执行构建产物lib/client.js,断言它只从 平台模块表(react、react/jsx-runtime、@deepseek-ai/dsh-client-store) 取模块,并按 0.2.0-rc.2 的slots/locale契约注册设置页。
依赖安装有一条容易踩的坑:本仓库旁边若有
deepseek-harness检出,pnpm 默认会把@deepseek-ai/*链接到那份本地工作区,于是typecheck与test实际校验的 是另一条发布线(例如 0.1.7-rc.1)而不自知。仓库根的.npmrc用link-workspace-packages=false关掉了这个行为,auto-install-peers=false则避免为 peer 再装一份未钉版本的副本。
安装
快速安装(推荐)
插件已发布到 npm:dsh-mcp-setting。一条命令安装到目标 profile(如 web):
pnpm dsh plugin --profile web add dsh-mcp-setting该命令在 profile 目录执行 pnpm add,并自动把声明了 dsh.bundle 的
dsh-mcp-setting 加入 dsh.profile.bundles。重启 DSH 后插件随 bundles
自动装配(包内 cordis.patch.yml 自插入插件行),浏览器打开设置 →
MCP 服务器。
移除:
pnpm dsh plugin --profile web remove dsh-mcp-setting从旧版本升级:0.1.3 及更早的版本把 peer 区间声明为
^0.1.2-alpha.1,在 DSH 0.2.x 上会被判定为不兼容而拒绝激活。0.1.4 已修好区间;0.1.5 进一步对齐了 cordis 与 schemastery 的宿主版本;0.2.0 增加按会话工作区挂载,并新增三个 DSH peer (dsh-mcp-client、dsh-scope、dsh-agent),它们随 0.2.0-rc.2 一起发布, 目标 profile 无需手动安装。发布后在目标 profile 执行:pnpm dsh plugin --profile web add dsh-mcp-setting@^0.2.0重启 DSH 后生效;
~/.dsh/profiles/<name>/package.json中的版本号应变为 0.2.0。
本地开发挂载
pnpm install && pnpm build # 编译 lib/
# 或使用注入器生产线:dev_build_plugin → dev_install_package(web profile)挂载后浏览器刷新页面,设置 → MCP 服务器。
开发
pnpm test # vitest(patch-editor / 工作区规则纯逻辑 + controller fetch 桩 + 运行时挂载 + DSH 兼容性契约)
pnpm typecheck # tsc,对着 node_modules 中真实的 DSH 0.2.0-rc.2 类型
pnpm typecheck:tests # tsc,额外覆盖 tests/ 与 scripts/
pnpm build # tsc 编译 host + tsdown 打包 client
pnpm smoke # 真实 Host 半边 + 临时 DSH home,跑通 API 路由
pnpm smoke:client # 真实 client 产物,走 __ModuleLoader__ 载入(需先 pnpm build)结构
src/index.ts— Host 半边:/dsh-mcp-setting/api/*路由(webServer),文件读写与校验。src/workspaces.ts— 纯函数:工作区路径归一化/匹配、规则与信任记录文档的解析与序列化、模式推导。src/project-config.ts— 纯函数:.dsh/mcp.json的解析与逐条校验(stdio / http)。src/runtime.ts— 会话级挂载:监听agent/created,按工作目录匹配规则并读取受信任的 工作区配置,为该会话创建作用域挂载 mcp-client,会话销毁时释放(agent/disposed)。src/patch-editor.ts— 纯函数:patch 文档的增删改查与配置校验(可单测)。src/status.ts— 由 loader fiber 与工具注册表推断每行的实时状态。src/client/— Client 半边:settings.section槽位(MCP 服务器页)、conversation.composer.dock槽位(会话信息条计数与详情小窗)、fetch 传输、React 组件(zh/en)。src/client/— Client 半边:settings.section槽位注册、fetch 传输、 React 设置页(zh/en)。tests/— 单元测试(纯逻辑与契约,不导入插件主体)。scripts/— 冒烟脚本:smoke-host.spec.ts用桩上下文跑真实 Host 半边,smoke-client.mjs在 Node 中执行构建后的 client 产物。
协议
本项目以 MIT License 发布(Copyright © 2025 belowthetree),详见 LICENSE 文件。
