diff --git a/src-tauri/src/mcp_tools.rs b/src-tauri/src/mcp_tools.rs index ee16c45..5f21718 100644 --- a/src-tauri/src/mcp_tools.rs +++ b/src-tauri/src/mcp_tools.rs @@ -246,6 +246,17 @@ pub fn tools_list_result() -> Value { "description": "扫描已登记项目的父目录,找出存在于文件系统但尚未在炼境注册的项目目录。返回每个未注册目录的路径、是否有 .git、技术栈特征文件(package.json / Cargo.toml / go.mod)、是否有 AGENTS.md。用于日常发现漏网项目并决定是否接入炼境。", "inputSchema": { "type": "object", "properties": {}, "required": [] } }, + { + "name": "unregister_project", + "description": "从炼境删除一条项目登记(等价 UI 删除项目按钮的 agent 投影):清理产品组 MCP 配置、关联表、workspace 与孤儿 profile。绝不删除本地文件(该能力不对 agent 开放)。适用:scan_unregistered_projects 的反向操作——清理目录已消失或已无 .git 的死登记。删除不可逆,调用前先向用户列出目标清单确认。", + "inputSchema": { + "type": "object", + "properties": { + "project_id": { "type": "string", "description": "要删除登记的项目 workspace ID" } + }, + "required": ["project_id"] + } + }, { "name": "ingest_git_history", "description": "全量导入 git 历史到飞轮(等价 UI「全量导入」按钮的 agent 投影):解析最近 500 条 commit 的 conventional 指标、Rules-Applied trailer 与触碰文件,UPSERT 幂等(存量行自动回填 trailer)。不传 project_id 时对所有已登记 Windows 路径项目执行。适用:trailer 存量回填、新项目接入后初始化飞轮数据。", @@ -486,6 +497,16 @@ pub async fn tools_call(group_id: &str, params: Option<&Value>) -> Value { } "list_all_projects" => list_all_projects(), "scan_unregistered_projects" => scan_unregistered_projects(), + "unregister_project" => { + let pid = args.get("project_id").and_then(|v| v.as_str()).unwrap_or(""); + if pid.is_empty() { + Err("project_id 不能为空".to_string()) + } else { + // delete_local 硬编码 false:MCP 侧永不删除本地文件 + crate::commands::projects::delete_project(pid.to_string(), Some(false)) + .map(|_| format!("已删除登记:{}(本地文件未动)", pid)) + } + } "ingest_git_history" => { let pid = args.get("project_id").and_then(|v| v.as_str()); let conn = db::pool().get().map_err(|e| e.to_string())?; @@ -1127,6 +1148,7 @@ mod tests { assert!(names.contains(&"poll_now"), "缺少 poll_now"); assert!(names.contains(&"predict_task_risk"), "缺少 predict_task_risk"); assert!(names.contains(&"ingest_git_history"), "缺少 ingest_git_history"); + assert!(names.contains(&"unregister_project"), "缺少 unregister_project"); // 每个工具都有 description 和 inputSchema for tool in tools { let name = tool["name"].as_str().unwrap_or("?");