mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 21:30:17 +08:00
75e7f9d731
- Remove unused `read_mcp_json` from gemini_mcp.rs - Remove unused `normalize_server_keys` from mcp/claude.rs - Remove unused `validate_mcp_entry` from mcp/validation.rs - Remove unused `write_codex_live`, `write_claude_live`, `app_not_found` from services/provider/mod.rs - Clean up unused imports
132 lines
4.2 KiB
Rust
132 lines
4.2 KiB
Rust
//! Claude MCP 同步和导入模块
|
||
|
||
use serde_json::Value;
|
||
use std::collections::HashMap;
|
||
|
||
use crate::app_config::{McpApps, McpConfig, McpServer, MultiAppConfig};
|
||
use crate::error::AppError;
|
||
|
||
use super::validation::{extract_server_spec, validate_server_spec};
|
||
|
||
/// 返回已启用的 MCP 服务器(过滤 enabled==true)
|
||
fn collect_enabled_servers(cfg: &McpConfig) -> HashMap<String, Value> {
|
||
let mut out = HashMap::new();
|
||
for (id, entry) in cfg.servers.iter() {
|
||
let enabled = entry
|
||
.get("enabled")
|
||
.and_then(|v| v.as_bool())
|
||
.unwrap_or(false);
|
||
if !enabled {
|
||
continue;
|
||
}
|
||
match extract_server_spec(entry) {
|
||
Ok(spec) => {
|
||
out.insert(id.clone(), spec);
|
||
}
|
||
Err(err) => {
|
||
log::warn!("跳过无效的 MCP 条目 '{id}': {err}");
|
||
}
|
||
}
|
||
}
|
||
out
|
||
}
|
||
|
||
/// 将 config.json 中 enabled==true 的项投影写入 ~/.claude.json
|
||
pub fn sync_enabled_to_claude(config: &MultiAppConfig) -> Result<(), AppError> {
|
||
let enabled = collect_enabled_servers(&config.mcp.claude);
|
||
crate::claude_mcp::set_mcp_servers_map(&enabled)
|
||
}
|
||
|
||
/// 从 ~/.claude.json 导入 mcpServers 到统一结构(v3.7.0+)
|
||
/// 已存在的服务器将启用 Claude 应用,不覆盖其他字段和应用状态
|
||
pub fn import_from_claude(config: &mut MultiAppConfig) -> Result<usize, AppError> {
|
||
let text_opt = crate::claude_mcp::read_mcp_json()?;
|
||
let Some(text) = text_opt else { return Ok(0) };
|
||
|
||
let v: Value = serde_json::from_str(&text)
|
||
.map_err(|e| AppError::McpValidation(format!("解析 ~/.claude.json 失败: {e}")))?;
|
||
let Some(map) = v.get("mcpServers").and_then(|x| x.as_object()) else {
|
||
return Ok(0);
|
||
};
|
||
|
||
// 确保新结构存在
|
||
let servers = config.mcp.servers.get_or_insert_with(HashMap::new);
|
||
|
||
let mut changed = 0;
|
||
let mut errors = Vec::new();
|
||
|
||
for (id, spec) in map.iter() {
|
||
// 校验:单项失败不中止,收集错误继续处理
|
||
if let Err(e) = validate_server_spec(spec) {
|
||
log::warn!("跳过无效 MCP 服务器 '{id}': {e}");
|
||
errors.push(format!("{id}: {e}"));
|
||
continue;
|
||
}
|
||
|
||
if let Some(existing) = servers.get_mut(id) {
|
||
// 已存在:仅启用 Claude 应用
|
||
if !existing.apps.claude {
|
||
existing.apps.claude = true;
|
||
changed += 1;
|
||
log::info!("MCP 服务器 '{id}' 已启用 Claude 应用");
|
||
}
|
||
} else {
|
||
// 新建服务器:默认仅启用 Claude
|
||
servers.insert(
|
||
id.clone(),
|
||
McpServer {
|
||
id: id.clone(),
|
||
name: id.clone(),
|
||
server: spec.clone(),
|
||
apps: McpApps {
|
||
claude: true,
|
||
codex: false,
|
||
gemini: false,
|
||
},
|
||
description: None,
|
||
homepage: None,
|
||
docs: None,
|
||
tags: Vec::new(),
|
||
},
|
||
);
|
||
changed += 1;
|
||
log::info!("导入新 MCP 服务器 '{id}'");
|
||
}
|
||
}
|
||
|
||
if !errors.is_empty() {
|
||
log::warn!("导入完成,但有 {} 项失败: {:?}", errors.len(), errors);
|
||
}
|
||
|
||
Ok(changed)
|
||
}
|
||
|
||
/// 将单个 MCP 服务器同步到 Claude live 配置
|
||
pub fn sync_single_server_to_claude(
|
||
_config: &MultiAppConfig,
|
||
id: &str,
|
||
server_spec: &Value,
|
||
) -> Result<(), AppError> {
|
||
// 读取现有的 MCP 配置
|
||
let current = crate::claude_mcp::read_mcp_servers_map()?;
|
||
|
||
// 创建新的 HashMap,包含现有的所有服务器 + 当前要同步的服务器
|
||
let mut updated = current;
|
||
updated.insert(id.to_string(), server_spec.clone());
|
||
|
||
// 写回
|
||
crate::claude_mcp::set_mcp_servers_map(&updated)
|
||
}
|
||
|
||
/// 从 Claude live 配置中移除单个 MCP 服务器
|
||
pub fn remove_server_from_claude(id: &str) -> Result<(), AppError> {
|
||
// 读取现有的 MCP 配置
|
||
let mut current = crate::claude_mcp::read_mcp_servers_map()?;
|
||
|
||
// 移除指定服务器
|
||
current.remove(id);
|
||
|
||
// 写回
|
||
crate::claude_mcp::set_mcp_servers_map(¤t)
|
||
}
|