dev-manager-tauri/.blueprint/modules/mcp-single-server.md
lanrtop a05fb49347
All checks were successful
Push & PR Check / check (push) Successful in 49s
docs(blueprint): mcp-single-server 模块收官——T4 端到端终验通过
验证:~/.claude.json 仅剩 lian-jing(12 条旧注册清零)、3 项目抽查
新格式通过、新路由握手 + get_diagnostics 实调通过、旧路由 404。
T4 暴露 git-bash 硬编码存量 bug 已修(0d1427f)。
遗留:同路径重复登记(legacy id 与 uuid id 并存)待登记卫生清理。
2026-07-06 20:18:32 +09:00

110 lines
9.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MCP 单一服务器化
将组级挂载的 `lian-jing-{group_id}`(每产品组一个 MCP 服务器)收敛为单一全局 `lian-jing` 服务器。
## 为什么
- **摩擦随项目数复利增长,与飞轮方向相反**:每新增一个产品组 = 多一次 `claude mcp add` + 多一个授权单元 + 每个会话多一份重复工具清单(现状 12 组 × 28 工具 ≈ 300+ 工具注册)。炼境目标是"管理项目越多 → agent 辅助越强",客户端配置成本必须是 O(1)。
- **组级挂载没有真正的隔离价值**2026-07-06 实测任意组服务器可对任意项目执行 `inject_mcp`;组归属校验只覆盖部分工具(半吊子状态)。
- **消除 group_id 身份卡问题**:单一服务器后 `liangjing.json` 只需 `project_id`group_id 缺失/过期/移组同步这一整类问题从根上消失。
## 设计决策2026-07-06 /architect
### 方案选择
- A. 直接切换:加全局路由同时删旧路由 —— ❌ 所有存量会话立刻断链,故障静默
- **B. 双路由过渡(选定)**:新增全局 `/mcp` 路由,旧 `/mcp/group/:gid` 保留兼容;注入逻辑切到新名字;批量迁移后旧路由在后续版本删除
- C. 全局 alias 与组服务器并存 —— ❌ 不消除 O(N) 注册,白改
### 核心接口变更
1. **路由**`mcp_server.rs`):新增 `POST/GET /mcp` + `POST /mcp/messages``process_rpc` 的组上下文改为 `Option<String>`(旧路由 `Some(gid)`,新路由 `None`
2. **工具层**`mcp_tools.rs`
- `resolve_project_root(project_id)` 去组化——直查 `project_workspaces`,删除 JOIN `project_group_map` 的归属过滤
- `get_project_mentor_context` / `append_project_note` / `get_project_snapshots` 三处 membership check 删除(改为项目存在性检查)
- `list_group_projects` 新增可选参数 `group_id`:显式参数 > 挂载上下文(旧路由)> 报错提示传参;`tools_list_result` schema 同步
3. **注入层**`mcp_inject.rs`
- `inject_project_mcp(project_id)` 去掉 `group_id` 参数settings.json 写入 key `"lian-jing"`、URL `http://127.0.0.1:{port}/mcp`
- 注入时顺手删除同文件中所有 `lian-jing:group-*` 旧 key迁移内建于重注入`reinject_all_mcp` 即批量迁移器)
- `liangjing.json` 只写 `project_id` + `mcp_port`**主动删除**已有 `group_id` 键(避免过期数据)
- 全局注册收敛为一次 `claude mcp add lian-jing`;新增迁移函数清理旧注册——遍历 `product_groups`,对**完整 UUID 名和短 8 位名两种格式**各尝试 `claude mcp remove -s user`(幂等,失败仅记日志)
- `remove_group_member` 语义修正:项目退出某组时,仅当它不再属于任何组才移除 `"lian-jing"` key
4. **附带收益**`inject_mcp` 不再要求项目必须属于产品组("未加入任何产品组"报错可移除),未分组项目也能接入
### 受影响文件
- 修改:`src-tauri/src/mcp_server.rs` — 新增全局路由process_rpc 组上下文 Option 化
- 修改:`src-tauri/src/mcp_tools.rs` — resolve_project_root 去组化、3 处校验删除、list_group_projects 参数化、schema 更新、inject_mcp 分支简化
- 修改:`src-tauri/src/mcp_inject.rs` — key/URL/注册收敛、旧 key 清理、liangjing.json 瘦身、全局旧注册迁移函数
- 修改:`src-tauri/src/commands/groups.rs` — inject 调用签名、remove_group_member 条件移除
- 修改:`src/components/settings/SettingsPage.tsx:537` — URL 展示改为 `/mcp`
- 修改:`docs/ai-context/git-workflow.md` + `src-tauri/resources/onboarding/git-workflow.md.tmpl` — 寻址说明改写
- 修改:`.claude/skills/retro-catchup/SKILL.md` — 解析 `lian-jing:group-` 前缀的逻辑改为 `lian-jing`
- 修改:`.blueprint/modules/mcp-config-inject.md` — 补注记:组级 key 方案已被本模块取代
- 仓库外(执行阶段处理):`~/.claude.json` 12 条旧注册清理、~15 个项目 settings.json/liangjing.json 批量重注入、用户全局 `~/.claude/CLAUDE.md` 炼境规则段改写
### 迁移顺序(切换编排)
1. 代码落地(双路由并存,零破坏)→ cargo test + curl 冒烟新路由
2. 全局注册 `lian-jing` + 清理旧注册(新会话立即可用单服务器)
3. `reinject_all_mcp` 批量刷新存量项目settings.json 换 key、liangjing.json 去 group_id
4. 文档/模板/技能/用户全局规则同步
5. 抽查验证3 个项目文件内容 + `claude mcp list` 只剩 `lian-jing` + 新会话实调 `get_ci_status` 走通
6. (后置卡,下个版本)删除旧 `/mcp/group/:gid` 路由与 `Option` 兼容层
### 风险点
- 存量会话断链 → 双路由并存规避,旧路由删除后置一个版本
- `claude mcp remove` 部分失败 → best-effort + 日志,输出手动清理命令清单兜底
- 误删用户自有 mcpServers 配置 → 只删 `lian-jing:group-` 前缀 key沿用现有精确删除机制
- webhook 已核实不受影响(路由 `/webhook/gitea/:project_id` 不含 group_id
## 任务卡
### ✅ T1. 服务器层双路由:全局 /mcp + 组上下文 Option 化
- status: done
- complexity: M
- files: src-tauri/src/mcp_server.rs
- acceptance: "[HTTP] POST http://127.0.0.1:{port}/mcp (initialize) → 200 且 serverInfo.name=炼境GET /mcp 返回 SSE 事件流endpoint 指向 /mcp/messages"
- done_note: 2026-07-06 完成。process_rpc 驻军测试覆盖握手路径cargo test 全绿HTTP 层实测归入 T4需新二进制运行。注T6 随后并入同一发版,双路由过渡态只存在于中间 commit
### ✅ T2. 工具层去组化resolve_project_root 按 project_id 直查
- status: done
- complexity: M
- files: src-tauri/src/mcp_tools.rs
- depends: T1
- acceptance: "[HTTP] 经 /mcp 调 get_project_blueprint(project_id) → 返回 manifest 内容,无'不属于产品组'错误list_group_projects(group_id=xxx) 显式传参 → 返回成员列表cargo test 全绿"
- done_note: 2026-07-06 完成。resolve_project_root 直查 project_workspaces3 处组归属校验替换为 ensure_project_existslist_group_projects schema 改 required group_id。HTTP 实测归入 T4
### ✅ T3. 注入层收敛lian-jing 单 key + 旧配置清理 + liangjing.json 瘦身
- status: done
- complexity: M
- files: src-tauri/src/mcp_inject.rs, src-tauri/src/mcp_tools.rs, src-tauri/src/commands/groups.rs, src-tauri/src/commands/projects.rs, src-tauri/src/lib.rs
- depends: T1
- acceptance: "[Tauri command] inject_project_mcp(pid) → 项目 settings.json 含 key \"lian-jing\"URL 以 /mcp 结尾)且无 lian-jing:group-* 残留liangjing.json 含 project_id+mcp_port 且 group_id 键被删除remove_group_member 仅在项目不属于任何组时移除 keycargo test 全绿"
- done_note: 2026-07-06 完成。额外实现 migrate_to_single_server 启动时一次性迁移(标记位 mcp_single_migratedclaude CLI 缺失时不落标记等重试delete_group/remove_group_member 加"仍属其他组则保留"判断;文件实测归入 T4
### ✅ T4. 存量批量迁移执行 + 端到端验证
- status: done
- complexity: S
- files: src-tauri/src/mcp_inject.rs迁移暴露 git-bash 探测 bug修复见 0d1427f
- depends: T1, T2, T3, T6
- acceptance: "[CLI] claude mcp list → lian-jing-* 旧条目清零、仅剩 lian-jing[MCP] 抽查 3 个项目 settings.json/liangjing.json 符合新格式;经 /mcp 实调 get_diagnostics → 返回 JSON 无 error[HTTP] POST /mcp/group/{gid} → 404"
- done_note: 2026-07-06 完成。端到端验证暴露真 bugCLAUDE_CODE_GIT_BASH_PATH 回退路径硬编码 Program FilesScoop 安装的 Git 导致 claude mcp add/remove 全挂(存量 bug组级时代即存在——修复为多位置探测 + already exists 视为成功 + 迁移标记位以注册成功为条件0d1427f。首次迁移的全局注册部分手动补齐本会话 claude mcp remove ×12 + add lian-jing文件迁移由 migrate_to_single_server 自动完成。验证:~/.claude.json 仅剩 lian-jing、3 项目dev-manager-tauri/enterprise-system/life-memo配置全部新格式、新路由握手 + get_diagnostics 实调通过、旧路由 404。遗留同路径重复登记legacy id "dev-manager-tauri" 组 0001 与 2c5b54ef 并存)导致批量重注入时 liangjing.json project_id 翻转,待用户决定是否 unregister legacy 条目
### ✅ T5. 文档/模板/技能/UI 寻址说明同步
- status: done
- complexity: S
- files: docs/ai-context/git-workflow.md, src-tauri/resources/onboarding/git-workflow.md.tmpl, .claude/skills/retro-catchup/SKILL.md, src/components/settings/SettingsPage.tsx, .blueprint/modules/mcp-config-inject.md
- depends: T3
- acceptance: "[Bash] grep -rE 'lian-jing-\\{group_id\\}|lian-jing:group-' docs/ src/ src-tauri/resources/ → 零命中mcp-config-inject.md 保留历史注记除外pnpm typecheck 通过"
- done_note: 2026-07-06 完成。grep 零命中、typecheck 通过;用户全局 ~/.claude/CLAUDE.md 炼境规则段已同步改为单一 lian-jing 寻址
### ✅ T6. 删除旧 /mcp/group 路由与兼容层
- status: done
- complexity: S
- files: src-tauri/src/mcp_server.rs, src-tauri/src/mcp_tools.rs
- depends: T3
- acceptance: "cargo test 全绿grep 'mcp/group' src-tauri/src/ 零命中;[HTTP] POST /mcp/group/{gid} → 404归入 T4 实测)"
- done_note: 2026-07-06 完成。原计划后置一个版本经评估提前并入本次发版迁移在新版启动时自动重写全部客户端配置旧路由的实际消费者只剩升级前的存量会话服务重启后本就断开单人环境保留价值趋近于零。tools_call 签名去 Option 化list_group_projects 改 required 参数