1use crate::mcp::models::{McpConfig, McpServerConfig};
2use anyhow::{Context, Result};
3use std::collections::HashMap;
4use std::path::Path;
5
6impl McpConfig {
7 pub fn load_or_default(path: &Path) -> Result<Self> {
12 if path.exists() {
13 crate::utils::read_json_file(path).with_context(|| {
15 format!(
16 "Failed to parse MCP configuration file: {}\n\
17 The file may be malformed or contain invalid JSON.",
18 path.display()
19 )
20 })
21 } else {
22 Ok(Self::default())
23 }
24 }
25
26 pub fn save(&self, path: &Path) -> Result<()> {
30 if path.exists() {
32 let backup_path = crate::utils::generate_backup_path(path, "claude-code")?;
34
35 if let Some(backup_dir) = backup_path.parent() {
37 if !backup_dir.exists() {
38 std::fs::create_dir_all(backup_dir).with_context(|| {
39 format!("Failed to create directory: {}", backup_dir.display())
40 })?;
41 }
42 }
43
44 std::fs::copy(path, &backup_path).with_context(|| {
45 format!(
46 "Failed to create backup of MCP configuration at: {}",
47 backup_path.display()
48 )
49 })?;
50 }
51
52 crate::utils::write_json_file(path, self, true)
54 .with_context(|| format!("Failed to write MCP configuration to: {}", path.display()))?;
55
56 Ok(())
57 }
58
59 pub fn update_managed_servers(
66 &mut self,
67 updates: HashMap<String, McpServerConfig>,
68 ) -> Result<()> {
69 let updating_names: std::collections::HashSet<_> = updates.keys().cloned().collect();
71
72 self.mcp_servers.retain(|name, config| {
74 config
78 .agpm_metadata
79 .as_ref()
80 .is_none_or(|meta| !meta.managed || updating_names.contains(name))
81 });
82
83 for (name, config) in updates {
85 self.mcp_servers.insert(name, config);
86 }
87
88 Ok(())
89 }
90
91 #[must_use]
96 pub fn check_conflicts(&self, new_servers: &HashMap<String, McpServerConfig>) -> Vec<String> {
97 let mut conflicts = Vec::new();
98
99 for name in new_servers.keys() {
100 if let Some(existing) = self.mcp_servers.get(name) {
101 if existing.agpm_metadata.is_none()
103 || !existing.agpm_metadata.as_ref().unwrap().managed
104 {
105 conflicts.push(name.clone());
106 }
107 }
108 }
109
110 conflicts
111 }
112
113 pub fn remove_all_managed(&mut self) {
117 self.mcp_servers
118 .retain(|_, config| config.agpm_metadata.as_ref().is_none_or(|meta| !meta.managed));
119 }
120
121 #[must_use]
123 pub fn get_managed_servers(&self) -> HashMap<String, &McpServerConfig> {
124 self.mcp_servers
125 .iter()
126 .filter(|(_, config)| config.agpm_metadata.as_ref().is_some_and(|meta| meta.managed))
127 .map(|(name, config)| (name.clone(), config))
128 .collect()
129 }
130}