belowthetree/dsh-mcp-setting

dsh-mcp-setting

在「设置」界面管理 DSH 配置文件里的 MCP 服务器。setup mcp server in setting panel

미분류deepseekdeepseek-harnessdsh

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.40.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 文件。