mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 21:30:17 +08:00
7997b2c7b3
- Add import_opencode_providers_from_live command to provider.rs - Register new command in lib.rs invoke_handler - Update commands/mcp.rs: include OpenCode in sync_other_side logic - Add McpService::import_from_opencode to import_mcp_from_apps - Implement MCP sync/remove for OpenCode in services/mcp.rs - sync_server_to_app_no_config now calls sync_single_server_to_opencode - remove_server_from_app now calls remove_server_from_opencode
207 lines
6.4 KiB
Rust
207 lines
6.4 KiB
Rust
#![allow(non_snake_case)]
|
||
|
||
use indexmap::IndexMap;
|
||
use std::collections::HashMap;
|
||
|
||
use serde::Serialize;
|
||
use tauri::State;
|
||
|
||
use crate::app_config::AppType;
|
||
use crate::claude_mcp;
|
||
use crate::services::McpService;
|
||
use crate::store::AppState;
|
||
|
||
/// 获取 Claude MCP 状态
|
||
#[tauri::command]
|
||
pub async fn get_claude_mcp_status() -> Result<claude_mcp::McpStatus, String> {
|
||
claude_mcp::get_mcp_status().map_err(|e| e.to_string())
|
||
}
|
||
|
||
/// 读取 mcp.json 文本内容
|
||
#[tauri::command]
|
||
pub async fn read_claude_mcp_config() -> Result<Option<String>, String> {
|
||
claude_mcp::read_mcp_json().map_err(|e| e.to_string())
|
||
}
|
||
|
||
/// 新增或更新一个 MCP 服务器条目
|
||
#[tauri::command]
|
||
pub async fn upsert_claude_mcp_server(id: String, spec: serde_json::Value) -> Result<bool, String> {
|
||
claude_mcp::upsert_mcp_server(&id, spec).map_err(|e| e.to_string())
|
||
}
|
||
|
||
/// 删除一个 MCP 服务器条目
|
||
#[tauri::command]
|
||
pub async fn delete_claude_mcp_server(id: String) -> Result<bool, String> {
|
||
claude_mcp::delete_mcp_server(&id).map_err(|e| e.to_string())
|
||
}
|
||
|
||
/// 校验命令是否在 PATH 中可用(不执行)
|
||
#[tauri::command]
|
||
pub async fn validate_mcp_command(cmd: String) -> Result<bool, String> {
|
||
claude_mcp::validate_command_in_path(&cmd).map_err(|e| e.to_string())
|
||
}
|
||
|
||
#[derive(Serialize)]
|
||
pub struct McpConfigResponse {
|
||
pub config_path: String,
|
||
pub servers: HashMap<String, serde_json::Value>,
|
||
}
|
||
|
||
/// 获取 MCP 配置(来自 ~/.cc-switch/config.json)
|
||
use std::str::FromStr;
|
||
|
||
#[tauri::command]
|
||
#[allow(deprecated)] // 兼容层命令,内部调用已废弃的 Service 方法
|
||
pub async fn get_mcp_config(
|
||
state: State<'_, AppState>,
|
||
app: String,
|
||
) -> Result<McpConfigResponse, String> {
|
||
let config_path = crate::config::get_app_config_path()
|
||
.to_string_lossy()
|
||
.to_string();
|
||
let app_ty = AppType::from_str(&app).map_err(|e| e.to_string())?;
|
||
let servers = McpService::get_servers(&state, app_ty).map_err(|e| e.to_string())?;
|
||
Ok(McpConfigResponse {
|
||
config_path,
|
||
servers,
|
||
})
|
||
}
|
||
|
||
/// 在 config.json 中新增或更新一个 MCP 服务器定义
|
||
/// [已废弃] 该命令仍然使用旧的分应用API,会转换为统一结构
|
||
#[tauri::command]
|
||
pub async fn upsert_mcp_server_in_config(
|
||
state: State<'_, AppState>,
|
||
app: String,
|
||
id: String,
|
||
spec: serde_json::Value,
|
||
sync_other_side: Option<bool>,
|
||
) -> Result<bool, String> {
|
||
use crate::app_config::McpServer;
|
||
|
||
let app_ty = AppType::from_str(&app).map_err(|e| e.to_string())?;
|
||
|
||
// 读取现有的服务器(如果存在)
|
||
let existing_server = {
|
||
let servers = state.db.get_all_mcp_servers().map_err(|e| e.to_string())?;
|
||
servers.get(&id).cloned()
|
||
};
|
||
|
||
// 构建新的统一服务器结构
|
||
let mut new_server = if let Some(mut existing) = existing_server {
|
||
// 更新现有服务器
|
||
existing.server = spec.clone();
|
||
existing.apps.set_enabled_for(&app_ty, true);
|
||
existing
|
||
} else {
|
||
// 创建新服务器
|
||
let mut apps = crate::app_config::McpApps::default();
|
||
apps.set_enabled_for(&app_ty, true);
|
||
|
||
// 尝试从 spec 中提取 name,否则使用 id
|
||
let name = spec
|
||
.get("name")
|
||
.and_then(|v| v.as_str())
|
||
.unwrap_or(&id)
|
||
.to_string();
|
||
|
||
McpServer {
|
||
id: id.clone(),
|
||
name,
|
||
server: spec,
|
||
apps,
|
||
description: None,
|
||
homepage: None,
|
||
docs: None,
|
||
tags: Vec::new(),
|
||
}
|
||
};
|
||
|
||
// 如果 sync_other_side 为 true,也启用其他应用
|
||
if sync_other_side.unwrap_or(false) {
|
||
new_server.apps.claude = true;
|
||
new_server.apps.codex = true;
|
||
new_server.apps.gemini = true;
|
||
new_server.apps.opencode = true;
|
||
}
|
||
|
||
McpService::upsert_server(&state, new_server)
|
||
.map(|_| true)
|
||
.map_err(|e| e.to_string())
|
||
}
|
||
|
||
/// 在 config.json 中删除一个 MCP 服务器定义
|
||
#[tauri::command]
|
||
pub async fn delete_mcp_server_in_config(
|
||
state: State<'_, AppState>,
|
||
_app: String, // 参数保留用于向后兼容,但在统一结构中不再需要
|
||
id: String,
|
||
) -> Result<bool, String> {
|
||
McpService::delete_server(&state, &id).map_err(|e| e.to_string())
|
||
}
|
||
|
||
/// 设置启用状态并同步到客户端配置
|
||
#[tauri::command]
|
||
#[allow(deprecated)] // 兼容层命令,内部调用已废弃的 Service 方法
|
||
pub async fn set_mcp_enabled(
|
||
state: State<'_, AppState>,
|
||
app: String,
|
||
id: String,
|
||
enabled: bool,
|
||
) -> Result<bool, String> {
|
||
let app_ty = AppType::from_str(&app).map_err(|e| e.to_string())?;
|
||
McpService::set_enabled(&state, app_ty, &id, enabled).map_err(|e| e.to_string())
|
||
}
|
||
|
||
// ============================================================================
|
||
// v3.7.0 新增:统一 MCP 管理命令
|
||
// ============================================================================
|
||
|
||
use crate::app_config::McpServer;
|
||
|
||
/// 获取所有 MCP 服务器(统一结构)
|
||
#[tauri::command]
|
||
pub async fn get_mcp_servers(
|
||
state: State<'_, AppState>,
|
||
) -> Result<IndexMap<String, McpServer>, String> {
|
||
McpService::get_all_servers(&state).map_err(|e| e.to_string())
|
||
}
|
||
|
||
/// 添加或更新 MCP 服务器
|
||
#[tauri::command]
|
||
pub async fn upsert_mcp_server(
|
||
state: State<'_, AppState>,
|
||
server: McpServer,
|
||
) -> Result<(), String> {
|
||
McpService::upsert_server(&state, server).map_err(|e| e.to_string())
|
||
}
|
||
|
||
/// 删除 MCP 服务器
|
||
#[tauri::command]
|
||
pub async fn delete_mcp_server(state: State<'_, AppState>, id: String) -> Result<bool, String> {
|
||
McpService::delete_server(&state, &id).map_err(|e| e.to_string())
|
||
}
|
||
|
||
/// 切换 MCP 服务器在指定应用的启用状态
|
||
#[tauri::command]
|
||
pub async fn toggle_mcp_app(
|
||
state: State<'_, AppState>,
|
||
server_id: String,
|
||
app: String,
|
||
enabled: bool,
|
||
) -> Result<(), String> {
|
||
let app_ty = AppType::from_str(&app).map_err(|e| e.to_string())?;
|
||
McpService::toggle_app(&state, &server_id, app_ty, enabled).map_err(|e| e.to_string())
|
||
}
|
||
|
||
/// 从所有应用导入 MCP 服务器(复用已有的导入逻辑)
|
||
#[tauri::command]
|
||
pub async fn import_mcp_from_apps(state: State<'_, AppState>) -> Result<usize, String> {
|
||
let mut total = 0;
|
||
total += McpService::import_from_claude(&state).unwrap_or(0);
|
||
total += McpService::import_from_codex(&state).unwrap_or(0);
|
||
total += McpService::import_from_gemini(&state).unwrap_or(0);
|
||
total += McpService::import_from_opencode(&state).unwrap_or(0);
|
||
Ok(total)
|
||
}
|