mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-28 08:44:41 +08:00
a8fd1f0dd2
Add guard functions to check if Claude/Codex/Gemini CLI has been initialized before attempting to sync MCP configurations. This prevents creating unwanted config files in directories that don't exist. - Claude: check ~/.claude dir OR ~/.claude.json file exists - Codex: check ~/.codex dir exists - Gemini: check ~/.gemini dir exists When the target app is not installed, sync operations now silently succeed without writing any files, allowing users to manage MCP servers for apps they actually use without side effects on others.
142 lines
4.3 KiB
Rust
142 lines
4.3 KiB
Rust
//! Gemini 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};
|
||
|
||
fn should_sync_gemini_mcp() -> bool {
|
||
// Gemini 未安装/未初始化时:~/.gemini 目录不存在。
|
||
// 按用户偏好:目录缺失时跳过写入/删除,不创建任何文件或目录。
|
||
crate::gemini_config::get_gemini_dir().exists()
|
||
}
|
||
|
||
/// 返回已启用的 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 中 Gemini 的 enabled==true 项写入 Gemini MCP 配置
|
||
pub fn sync_enabled_to_gemini(config: &MultiAppConfig) -> Result<(), AppError> {
|
||
if !should_sync_gemini_mcp() {
|
||
return Ok(());
|
||
}
|
||
let enabled = collect_enabled_servers(&config.mcp.gemini);
|
||
crate::gemini_mcp::set_mcp_servers_map(&enabled)
|
||
}
|
||
|
||
/// 从 Gemini MCP 配置导入到统一结构(v3.7.0+)
|
||
/// 已存在的服务器将启用 Gemini 应用,不覆盖其他字段和应用状态
|
||
pub fn import_from_gemini(config: &mut MultiAppConfig) -> Result<usize, AppError> {
|
||
let map = crate::gemini_mcp::read_mcp_servers_map()?;
|
||
if map.is_empty() {
|
||
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) {
|
||
// 已存在:仅启用 Gemini 应用
|
||
if !existing.apps.gemini {
|
||
existing.apps.gemini = true;
|
||
changed += 1;
|
||
log::info!("MCP 服务器 '{id}' 已启用 Gemini 应用");
|
||
}
|
||
} else {
|
||
// 新建服务器:默认仅启用 Gemini
|
||
servers.insert(
|
||
id.clone(),
|
||
McpServer {
|
||
id: id.clone(),
|
||
name: id.clone(),
|
||
server: spec.clone(),
|
||
apps: McpApps {
|
||
claude: false,
|
||
codex: false,
|
||
gemini: true,
|
||
},
|
||
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 服务器同步到 Gemini live 配置
|
||
pub fn sync_single_server_to_gemini(
|
||
_config: &MultiAppConfig,
|
||
id: &str,
|
||
server_spec: &Value,
|
||
) -> Result<(), AppError> {
|
||
if !should_sync_gemini_mcp() {
|
||
return Ok(());
|
||
}
|
||
// 读取现有的 MCP 配置
|
||
let mut current = crate::gemini_mcp::read_mcp_servers_map()?;
|
||
|
||
// 添加/更新当前服务器
|
||
current.insert(id.to_string(), server_spec.clone());
|
||
|
||
// 写回
|
||
crate::gemini_mcp::set_mcp_servers_map(¤t)
|
||
}
|
||
|
||
/// 从 Gemini live 配置中移除单个 MCP 服务器
|
||
pub fn remove_server_from_gemini(id: &str) -> Result<(), AppError> {
|
||
if !should_sync_gemini_mcp() {
|
||
return Ok(());
|
||
}
|
||
// 读取现有的 MCP 配置
|
||
let mut current = crate::gemini_mcp::read_mcp_servers_map()?;
|
||
|
||
// 移除指定服务器
|
||
current.remove(id);
|
||
|
||
// 写回
|
||
crate::gemini_mcp::set_mcp_servers_map(¤t)
|
||
}
|