use std::collections::BTreeMap;
use crate::config::{self, McpServer};
use crate::error::LorumError;
use super::resolve_path;
pub fn run_mcp_add(
name: &str,
command: &str,
args: &[String],
env: &[String],
config_path: Option<&str>,
) -> Result<(), LorumError> {
let path = resolve_path(config_path)?;
let mut cfg = super::load_config_or_default(&path)?;
let env_map = parse_env_pairs(env);
let server = McpServer {
command: command.to_string(),
args: args.to_vec(),
env: env_map,
};
cfg.mcp.servers.insert(name.to_string(), server);
config::save_config(&path, &cfg)?;
println!("added server: {name}");
Ok(())
}
pub fn run_mcp_remove(name: &str, config_path: Option<&str>) -> Result<(), LorumError> {
let path = resolve_path(config_path)?;
let mut cfg = super::load_config_or_default(&path)?;
if cfg.mcp.servers.remove(name).is_none() {
return Err(LorumError::Other {
message: format!("server not found: {name}"),
});
}
config::save_config(&path, &cfg)?;
println!("removed server: {name}");
Ok(())
}
pub fn run_mcp_list(config_path: Option<&str>) -> Result<(), LorumError> {
let path = resolve_path(config_path)?;
let cfg = super::load_config_or_default(&path)?;
if cfg.mcp.servers.is_empty() {
println!("no MCP servers configured");
return Ok(());
}
#[allow(clippy::manual_unwrap_or)]
let max_name = if let Some(max) = cfg.mcp.servers.keys().map(|n| n.len()).max() {
max
} else {
4
};
println!("{:<width$} COMMAND", "NAME", width = max_name);
for (name, server) in &cfg.mcp.servers {
let args_str = if server.args.is_empty() {
String::new()
} else {
format!(" {}", server.args.join(" "))
};
println!(
"{:<width$} {}{}",
name,
server.command,
args_str,
width = max_name
);
}
Ok(())
}
pub fn run_mcp_edit(
name: &str,
command: Option<&str>,
args: Option<&[String]>,
env: Option<&[String]>,
config_path: Option<&str>,
) -> Result<(), LorumError> {
let path = resolve_path(config_path)?;
let mut cfg = super::load_config_or_default(&path)?;
let server = cfg
.mcp
.servers
.get_mut(name)
.ok_or_else(|| LorumError::Other {
message: format!("server not found: {name}"),
})?;
if let Some(cmd) = command {
server.command = cmd.to_string();
}
if let Some(new_args) = args {
server.args = new_args.to_vec();
}
if let Some(new_env) = env {
server.env = parse_env_pairs(new_env);
}
config::save_config(&path, &cfg)?;
println!("updated server: {name}");
Ok(())
}
pub fn parse_env_pairs(pairs: &[String]) -> BTreeMap<String, String> {
let mut map = BTreeMap::new();
for pair in pairs {
if let Some((k, v)) = pair.split_once('=') {
if !k.is_empty() {
map.insert(k.to_string(), v.to_string());
}
}
}
map
}