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_openclaw, 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_openclaw: bool = row.get(11)?;
35 let enabled_hermes: bool = row.get(12)?;
36
37 let server = serde_json::from_str(&server_config_str).unwrap_or_default();
38 let tags = serde_json::from_str(&tags_str).unwrap_or_default();
39
40 Ok((
41 id.clone(),
42 McpServer {
43 id,
44 name,
45 server,
46 apps: McpApps {
47 claude: enabled_claude,
48 codex: enabled_codex,
49 gemini: enabled_gemini,
50 opencode: enabled_opencode,
51 openclaw: enabled_openclaw,
52 hermes: enabled_hermes,
53 },
54 description,
55 homepage,
56 docs,
57 tags,
58 },
59 ))
60 })
61 .map_err(|e| AppError::Database(e.to_string()))?;
62
63 let mut servers = IndexMap::new();
64 for server_res in server_iter {
65 let (id, server) = server_res.map_err(|e| AppError::Database(e.to_string()))?;
66 servers.insert(id, server);
67 }
68 Ok(servers)
69 }
70
71 pub fn save_mcp_server(&self, server: &McpServer) -> Result<(), AppError> {
73 let conn = lock_conn!(self.conn);
74 conn.execute(
75 "INSERT INTO mcp_servers (
76 id, name, server_config, description, homepage, docs, tags,
77 enabled_claude, enabled_codex, enabled_gemini, enabled_opencode, enabled_openclaw, enabled_hermes
78 ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)
79 ON CONFLICT(id) DO UPDATE SET
80 name = excluded.name,
81 server_config = excluded.server_config,
82 description = excluded.description,
83 homepage = excluded.homepage,
84 docs = excluded.docs,
85 tags = excluded.tags,
86 enabled_claude = excluded.enabled_claude,
87 enabled_codex = excluded.enabled_codex,
88 enabled_gemini = excluded.enabled_gemini,
89 enabled_opencode = excluded.enabled_opencode,
90 enabled_openclaw = excluded.enabled_openclaw,
91 enabled_hermes = excluded.enabled_hermes",
92 params![
93 server.id,
94 server.name,
95 serde_json::to_string(&server.server).map_err(|e| AppError::Database(format!(
96 "Failed to serialize server config: {e}"
97 )))?,
98 server.description,
99 server.homepage,
100 server.docs,
101 serde_json::to_string(&server.tags)
102 .map_err(|e| AppError::Database(format!("Failed to serialize tags: {e}")))?,
103 server.apps.claude,
104 server.apps.codex,
105 server.apps.gemini,
106 server.apps.opencode,
107 server.apps.openclaw,
108 server.apps.hermes,
109 ],
110 )
111 .map_err(|e| AppError::Database(e.to_string()))?;
112 Ok(())
113 }
114
115 pub fn delete_mcp_server(&self, id: &str) -> Result<(), AppError> {
117 let conn = lock_conn!(self.conn);
118 conn.execute("DELETE FROM mcp_servers WHERE id = ?1", params![id])
119 .map_err(|e| AppError::Database(e.to_string()))?;
120 Ok(())
121 }
122}