# 发布说明 v0.4.0(自 v0.3.1 以来的累积变化) [← 返回 README](../README.zh.md) | 相关:[v0.3.1 发布说明](v0.3.1.md) **发布日期**:2026-09-09 | **区间**:`v0.3.1 → v0.4.0` **规模**:11 commits;源码 7 文件 +1043 / −525(全量 22 文件 +3702 / −3109,含删除约 3000 行的陈旧 `package-lock.json`);新增源码模块 2 个(`src/json-file.ts`、`src/json-write.ts`);测试套件 6 套 v0.4.0 把插件的定位从「Claude 兼容层」改成「**DSH 自有配置层**」:不再读取任何 Claude 用户态文件,新增与生态一致的 JSON 配置位置,并把用户层从「按项目扇出」改为「宿主级 **全局装载**」;同时把依赖对齐到 dsh 0.1.2-rc.1。 --- ## 亮点速览 | 主题 | 一句话 | |---|---| | DSH 自有 JSON 配置层 | `.dsh/mcp.json`、`~/.dsh/mcp.json`、`~/.dsh/profiles//mcp.json`,`{"mcpServers":{…}}` 方言 | | ⚠️ 用户层改全局装载 | 宿主级一条连接,不再按项目各挂一份 | | 项目侧压制 | 项目行遮蔽全局行时,只对该项目的会话 deny 全局工具 | | CLI 双格式 + profile 作用域 | `--format yml\|json`、`DSH_MCP_CLI_FORMAT`、`--scope profile --profile ` | | ⚠️ 移除 Claude 用户态读取 | `~/.claude.json` 不再读取,两个开关与哈希门删除 | | 依赖对齐宿主 | `dsh-mcp-client 0.1.2-rc.1` + 同版 peer;改用 pnpm 锁文件 | | 实机修复 | 家目录即项目根时不再重复装载用户层 | --- ## 新功能 ### DSH 自有 JSON 配置层(`src/json-file.ts`、`src/json-write.ts`) - 三个位置:`/.dsh/mcp.json`(项目层)、`~/.dsh/mcp.json`(通用用户层)、 `~/.dsh/profiles/<当前 profile>/mcp.json`(profile 用户层)。 - 方言与生态一致(Cursor / Claude Code 的 `mcpServers` 写法):stdio 用 `command`/`args`/`env`/`cwd`,远程用 `url`/`headers`;可选 `type` (`stdio`|`http`|`streamable-http`,`sse` 逐条拒绝)、DSH 透传键 `toolCallTimeoutMs`/`failOnStartupError`/`reconnect`、`enabled:false`(静默跳过、不占名) 与 `disabled:true`(占名但不装载)。未知键容忍、名字须匹配 `[A-Za-z0-9_-]{1,32}`、 坏条目逐条报错不影响其余;`${VAR}` 与其他来源同语义,装载时展开。 - **JSON 文件由 `dsh-mcp` CLI 独占**:写入保留其他顶层键与键序,但 JSON 没有注释, 排版/注释不被保留;解析失败拒绝覆盖(错误消息不含文件内容);锁内读-改-写 + 原子写。 插件侧只读,宿主永不写配置文件。 ### CLI:`--format` / `DSH_MCP_CLI_FORMAT` / `--scope profile` - `--format yml|json` 优先于环境变量 `DSH_MCP_CLI_FORMAT`(缺省 `yml`);`--format json` 时 project/user 分别写 `.dsh/mcp.json` 与 `~/.dsh/mcp.json`。 - `--scope profile --profile ` 写 `~/.dsh/profiles//mcp.json`(只支持 JSON; 缺 `--profile` 或 profile 不存在时报错并列出可用 profile)。 - `remove` 按优先序在 yml/json 两个文件中查找命中项;只读层命中仍给编辑指引。 ### profile 名解析 - `DSH_MCP_PROFILE=` 显式覆盖;否则从 loader 根 include 的 `config.path` (`~/.dsh/profiles//cordis.yml`)或 `ctx.baseUrl` 推导;解析不出时不读 profile 层 (其余层照常),不报错。 --- ## 行为与边界变更 ### ⚠️ 破坏性一:用户层改为全局装载 `~/.dsh/mcp.yml`、`~/.dsh/mcp.json`、`~/.dsh/profiles//mcp.json` 现在**宿主级只挂 一条连接**,与项目数量无关、对所有会话可见,不再按项目 fan-out(此前 N 个项目 = N 条 连接/进程)。 - **项目侧压制**:某个项目的自身行(精确同名、归一化同名或同服务身份)遮蔽了某条用户层 行时,**该项目的会话**会 deny 掉那条全局服务器的工具,其他项目照常可见;全局实例不卸载。 - 与 profile patch 行里的全局 mcp-client 服务器同名时,用户层行**跳过**并记 `skipReason: "name-taken"`(不改名,避免 `serverName` 预留冲突)。 - 全局行**保持原名**;只有项目行在同名冲突时改名 `p_<原名>`。 ### ⚠️ 破坏性二:分层来源名 DSH 化 六层读取顺序(逐行先到先得,同名/同服务只装高优先级一条): | 序 | 来源 | 路径 | 语义 | |---|---|---|---| | 1 | `dsh-project` | `/.dsh/mcp.yml` | 项目层 | | 2 | `dsh-project-json` | `/.dsh/mcp.json` | 项目层 | | 3 | `cc-project` | `/.mcp.json` | 项目层,遗留只读 | | 4 | `dsh-profile-user` | `~/.dsh/profiles/<当前 profile>/mcp.json` | 全局 | | 5 | `dsh-user-yml` | `~/.dsh/mcp.yml` | 全局 | | 6 | `dsh-user` | `~/.dsh/mcp.json` | 全局 | 旧名 `yml` / `user-yml` 已废弃;诊断、快照与 CLI 标签均报新名(`cc-project` 保持原名, 因为它就是 Claude 的文件)。 ### ⚠️ 破坏性三:不再读取 `~/.claude.json` cc-user 层、`DSH_MCP_READ_CLAUDE_USER`、`DSH_MCP_IGNORE_CLAUDE_JSON` 与 `mcpServers` 子树内容哈希门全部移除;`DSH_MCP_IGNORE_MCP_JSON=1` 仍可停用遗留的项目 `.mcp.json` 层。`/.mcp.json` 继续被读取(层 3,低优先级),CC 用户无需迁移。 ### 诊断与状态 - 项目诊断仍在 `/.dsh/.mcp-diag.json`;**全局层诊断移到 `$DSH_HOME/.mcp-diag.json`**(保留最近 30 条、原子写、串行于对账链)。 - 快照的全局分区补齐 `fiberPhase`/`toolCount`/`skipReason`;新增 `skipReason: "name-taken"`。 --- ## 修复 - **家目录即项目根时重复装载用户层**(`6d4b173`):宿主 cwd 为家目录时,该目录被当作 已知项目,`/.dsh/mcp.yml|json` 同时是用户层文件与该项目层的文件,同一行被挂两次 (全局一条 + `p_` 一条)并多出一个子进程。现在项目层读取、行查找与快照分区都比对 用户层路径,命中即跳过项目层。 - `npm run build` 现在先清空 `lib/` 再编译,删除的模块不再残留为陈旧产物。 --- ## 依赖与工具链 - `@deepseek-ai/dsh-mcp-client` `^0.1.1-rc.2` → **`^0.1.2-rc.1`**:旧范围**不会**升级到 0.1.2-rc.1(npm semver 要求 prerelease 候选与比较符的 major.minor.patch 元组一致), 插件此前在 0.1.2-rc.1 宿主里加载自带的 0.1.1-rc.2 副本及其 0.1.1-rc.2 peer。升级后 mcp-client 与全部 peer(`dsh-scope` 取代 `dsh-invariants`)解析到 0.1.2-rc.1。 - 开发依赖 `@deepseek-ai/cordis` → `^4.0.2`(仅类型,编译产物无 cordis 运行时 import)。 - 包管理器统一为 pnpm:提交 `pnpm-lock.yaml`,删除停留在 v0.1.1 的 `package-lock.json`, `package.json` 声明 `packageManager: pnpm@12.3.4`。 --- ## 实机验证(dsh 0.1.2-rc.1) | 场景 | 结果 | |---|---| | 项目 `.dsh/mcp.json` 热装载 + 工具调用 | `scan ok:true` → `attempt` → `active`;`mcp____probe` → `pong` | | 全局 `~/.dsh/mcp.json` | 只挂一条(无 `p_` 重复);工具可调用 | | profile `~/.dsh/profiles/web/mcp.json` | profile 名解析为 `web`,全局挂载并可调用 | | 项目侧压制 | 项目同名行改名 `p0b0ea5_<名>` 可调用;全局同名工具对该会话返回 unknown tool | | 配置热重载 | 改动 args 后 `attempt`→`active` 重挂,进程数不增 | | 卸载与清理 | 删除行后进程数回到 1,无残留 | | headless 宿主 | 同上(含 cwd=家目录场景,验证重复挂载修复) | --- ## 升级指引 1. **用户层语义变化**:若你依赖「用户层按项目各挂一条」,请改为依赖全局单实例;需要 在某个项目里屏蔽某台全局服务器时,在该项目 `.dsh/mcp.yml` 写同名/同服务行即可 (只影响该项目的会话)。 2. **`~/.claude.json` 迁移**:把顶层 `mcpServers` 里的条目搬到 `~/.dsh/mcp.json`(或 `~/.dsh/profiles//mcp.json`);旧开关已失效。 3. **依赖**:`pnpm install`(锁文件已提交)。 4. **插件激活**(dsh ≥ 0.1.2):`dsh plugin --profile

add link:<本仓库>`,或先 `pnpm link` 再跑一次任意 `dsh plugin --profile

<子命令>` 触发 bundle reconcile; 之后重启宿主。 ## 组件版本 - `dsh-project-mcp-manager` v0.4.0 | 依赖 `@deepseek-ai/dsh-mcp-client ^0.1.2-rc.1`、 `chokidar ^5`、`yaml ^2`、`zod ^4`(开发:`@deepseek-ai/cordis ^4.0.2`、`typescript ^7`) - 实测宿主:`@deepseek-ai/dsh@0.1.2-rc.1` **Full Changelog**:https://github.com/wldxiaobai/dsh-project-mcp-manager/compare/v0.3.1...v0.4.0