Files
CC-Switch/src-tauri/src/mcp/gemini.rs
T
Jason 81af0a57f9 feat: add Hermes Agent as 6th supported app type (Phase 1)
Register AppType::Hermes across the entire Rust backend:
- Add Hermes variant to AppType enum with additive mode and MCP support
- Add hermes field to McpApps, SkillApps, CommonConfigSnippets, and all
  per-app structs (McpRoot, PromptRoot, VisibleApps, AppSettings)
- Create minimal hermes_config.rs with get_hermes_dir() respecting
  settings override, matching the pattern of other app config modules
- Update all match arms in commands, services, deeplink, proxy, mcp,
  session_manager, and test files
- Extract shared build_additive_app_settings() to eliminate duplication
  between OpenClaw and Hermes deep link handling
- Combine identical OpenClaw/Hermes proxy match arms into unified arms
2026-04-21 11:57:06 +08:00

144 lines
4.4 KiB
Rust
Raw 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.
//! 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,
opencode: false,
hermes: 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 服务器同步到 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(&current)
}
/// 从 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(&current)
}