fix(mcp): resolve sync-to-other-side functionality failure
This commit implements a three-layer fix to restore the "Sync to other side" feature when adding or editing MCP servers across Claude and Codex. Root Cause Analysis: 1. Frontend issue: New MCP entries had their `enabled` field deleted 2. Backend issue: Default value was `false` when `enabled` was missing 3. Core issue: MCP entries were never copied to the other app's servers Changes: Frontend (McpFormModal.tsx): - Set `enabled=true` by default for new MCP entries - Preserve existing `enabled` state when editing Backend (services/mcp.rs): - Change default value from `unwrap_or(false)` to `unwrap_or(true)` - Implement cross-app MCP replication when `sync_other_side=true` - Clone MCP entry to other app's servers before syncing to live files Impact: - "Sync to Codex" checkbox now correctly adds MCP to both Claude and Codex - "Sync to Claude" checkbox now correctly adds MCP to both Codex and Claude - Both config.json and live files (~/.claude.json, ~/.codex/config.toml) are updated - Fixes regression introduced during project restructure Tested: - TypeScript type checking passed - Rust clippy linting passed - Manual testing: MCP sync works bidirectionally
This commit is contained in:
@@ -39,18 +39,41 @@ impl McpService {
|
|||||||
let mut cfg = state.config.write()?;
|
let mut cfg = state.config.write()?;
|
||||||
let changed = mcp::upsert_in_config_for(&mut cfg, &app, id, spec)?;
|
let changed = mcp::upsert_in_config_for(&mut cfg, &app, id, spec)?;
|
||||||
|
|
||||||
|
// 修复:默认启用(unwrap_or(true))
|
||||||
|
// 新增的 MCP 如果缺少 enabled 字段,应该默认为启用状态
|
||||||
let enabled = cfg
|
let enabled = cfg
|
||||||
.mcp_for(&app)
|
.mcp_for(&app)
|
||||||
.servers
|
.servers
|
||||||
.get(id)
|
.get(id)
|
||||||
.and_then(|entry| entry.get("enabled"))
|
.and_then(|entry| entry.get("enabled"))
|
||||||
.and_then(|v| v.as_bool())
|
.and_then(|v| v.as_bool())
|
||||||
.unwrap_or(false);
|
.unwrap_or(true);
|
||||||
|
|
||||||
let mut sync_claude = matches!(app, AppType::Claude) && enabled;
|
let mut sync_claude = matches!(app, AppType::Claude) && enabled;
|
||||||
let mut sync_codex = matches!(app, AppType::Codex) && enabled;
|
let mut sync_codex = matches!(app, AppType::Codex) && enabled;
|
||||||
|
|
||||||
|
// 修复:sync_other_side=true 时,先将 MCP 复制到另一侧,然后强制同步
|
||||||
|
// 这才是"同步到另一侧"的正确语义:将 MCP 跨应用复制
|
||||||
if sync_other_side {
|
if sync_other_side {
|
||||||
|
// 获取当前 MCP 条目的克隆(刚刚插入的,不可能失败)
|
||||||
|
let current_entry = cfg
|
||||||
|
.mcp_for(&app)
|
||||||
|
.servers
|
||||||
|
.get(id)
|
||||||
|
.cloned()
|
||||||
|
.expect("刚刚插入的 MCP 条目必定存在");
|
||||||
|
|
||||||
|
// 将该 MCP 复制到另一侧的 servers
|
||||||
|
let other_app = match app {
|
||||||
|
AppType::Claude => AppType::Codex,
|
||||||
|
AppType::Codex => AppType::Claude,
|
||||||
|
};
|
||||||
|
|
||||||
|
cfg.mcp_for_mut(&other_app)
|
||||||
|
.servers
|
||||||
|
.insert(id.to_string(), current_entry);
|
||||||
|
|
||||||
|
// 强制同步另一侧
|
||||||
match app {
|
match app {
|
||||||
AppType::Claude => sync_codex = true,
|
AppType::Claude => sync_codex = true,
|
||||||
AppType::Codex => sync_claude = true,
|
AppType::Codex => sync_claude = true,
|
||||||
|
|||||||
@@ -365,10 +365,13 @@ const McpFormModal: React.FC<McpFormModalProps> = ({
|
|||||||
server: serverSpec,
|
server: serverSpec,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 修复:新增 MCP 时默认启用(enabled=true)
|
||||||
|
// 编辑模式下保留原有的 enabled 状态
|
||||||
if (initialData?.enabled !== undefined) {
|
if (initialData?.enabled !== undefined) {
|
||||||
entry.enabled = initialData.enabled;
|
entry.enabled = initialData.enabled;
|
||||||
} else if (!initialData) {
|
} else {
|
||||||
delete entry.enabled;
|
// 新增模式:默认启用
|
||||||
|
entry.enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nameTrimmed = (formName || trimmedId).trim();
|
const nameTrimmed = (formName || trimmedId).trim();
|
||||||
|
|||||||
Reference in New Issue
Block a user