cc_switch_lib/database/dao/
mcp.rs1use crate::app_config::{McpApps, McpServer};
6use crate::database::{lock_conn, Database};
7use crate::error::AppError;
8use indexmap::IndexMap;
9use rusqlite::params;
10
11impl Database {
12 pub fn get_all_mcp_servers(&self) -> Result<IndexMap<String, McpServer>, AppError> {
14 let conn = lock_conn!(self.conn);
15 let mut stmt = conn.prepare(
16 "SELECT id, name, server_config, description, homepage, docs, tags, enabled_claude, enabled_codex, enabled_gemini, enabled_opencode, enabled_hermes
17 FROM mcp_servers
18 ORDER BY name ASC, id ASC"
19 ).map_err(|e| AppError::Database(e.to_string()))?;
20
21 let server_iter = stmt
22 .query_map([], |row| {
23 let id: String = row.get(0)?;
24 let name: String = row.get(1)?;
25 let server_config_str: String = row.get(2)?;
26 let description: Option<String> = row.get(3)?;
27 let homepage: Option<String> = row.get(4)?;
28 let docs: Option<String> = row.get(5)?;
29 let tags_str: String = row.get(6)?;
30 let enabled_claude: bool = row.get(7)?;
31 let enabled_codex: bool = row.get(8)?;
32 let enabled_gemini: bool = row.get(9)?;
33 let enabled_opencode: bool = row.get(10)?;
34 let enabled_hermes: bool = row.get(11)?;
35
36 let server = serde_json::from_str(&server_config_str).unwrap_or_default();
37 let tags = serde_json::from_str(&tags_str).unwrap_or_default();
38
39 Ok((
40 id.clone(),
41 McpServer {
42 id,
43 name,
44 server,
45 apps: McpApps {
46 claude: enabled_claude,
47 codex: enabled_codex,
48 gemini: enabled_gemini,
49 opencode: enabled_opencode,
50 hermes: enabled_hermes,
51 },
52 description,
53 homepage,
54 docs,
55 tags,
56 },
57 ))
58 })
59 .map_err(|e| AppError::Database(e.to_string()))?;
60
61 let mut servers = IndexMap::new();
62 for server_res in server_iter {
63 let (id, server) = server_res.map_err(|e| AppError::Database(e.to_string()))?;
64 servers.insert(id, server);
65 }
66 Ok(servers)
67 }
68
69 pub fn save_mcp_server(&self, server: &McpServer) -> Result<(), AppError> {
71 let conn = lock_conn!(self.conn);
72 conn.execute(
73 "INSERT INTO mcp_servers (
74 id, name, server_config, description, homepage, docs, tags,
75 enabled_claude, enabled_codex, enabled_gemini, enabled_opencode, enabled_hermes
76 ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)
77 ON CONFLICT(id) DO UPDATE SET
78 name = excluded.name,
79 server_config = excluded.server_config,
80 description = excluded.description,
81 homepage = excluded.homepage,
82 docs = excluded.docs,
83 tags = excluded.tags,
84 enabled_claude = excluded.enabled_claude,
85 enabled_codex = excluded.enabled_codex,
86 enabled_gemini = excluded.enabled_gemini,
87 enabled_opencode = excluded.enabled_opencode,
88 enabled_hermes = excluded.enabled_hermes",
89 params![
90 server.id,
91 server.name,
92 serde_json::to_string(&server.server).map_err(|e| AppError::Database(format!(
93 "Failed to serialize server config: {e}"
94 )))?,
95 server.description,
96 server.homepage,
97 server.docs,
98 serde_json::to_string(&server.tags)
99 .map_err(|e| AppError::Database(format!("Failed to serialize tags: {e}")))?,
100 server.apps.claude,
101 server.apps.codex,
102 server.apps.gemini,
103 server.apps.opencode,
104 server.apps.hermes,
105 ],
106 )
107 .map_err(|e| AppError::Database(e.to_string()))?;
108 Ok(())
109 }
110
111 pub fn delete_mcp_server(&self, id: &str) -> Result<(), AppError> {
113 let conn = lock_conn!(self.conn);
114 conn.execute("DELETE FROM mcp_servers WHERE id = ?1", params![id])
115 .map_err(|e| AppError::Database(e.to_string()))?;
116 Ok(())
117 }
118}