use crate::ipc::{config_update_path, open_restricted_write};
use serde_json::Value;
use std::io::Write;
pub fn handle_config_update(params: &Value) -> Value {
let arguments = match params.get("arguments") {
Some(args) => args,
None => {
return super::tool_error("Missing 'arguments' in tools/call params");
}
};
let updates = match arguments.get("updates") {
Some(u) if u.is_object() => u,
Some(_) => {
return super::tool_error("'updates' must be a JSON object");
}
None => {
return super::tool_error("Missing 'updates' in tool arguments");
}
};
let path = config_update_path();
write_config_updates(updates, &path)
}
pub fn write_config_updates(updates: &Value, path: &std::path::Path) -> Value {
if let Some(parent) = path.parent()
&& let Err(e) = std::fs::create_dir_all(parent)
{
return super::tool_error(&format!(
"Failed to create config directory {}: {e}",
parent.display()
));
}
let temp_path = path.with_extension("json.tmp");
let json_bytes = match serde_json::to_vec_pretty(updates) {
Ok(bytes) => bytes,
Err(e) => {
return super::tool_error(&format!("Failed to serialize updates: {e}"));
}
};
match open_restricted_write(&temp_path) {
Ok(mut f) => {
if let Err(e) = f.write_all(&json_bytes) {
return super::tool_error(&format!(
"Failed to write temp file {}: {e}",
temp_path.display()
));
}
}
Err(e) => {
return super::tool_error(&format!(
"Failed to create temp file {}: {e}",
temp_path.display()
));
}
}
if let Err(e) = std::fs::rename(&temp_path, path) {
let _ = std::fs::remove_file(&temp_path);
return super::tool_error(&format!(
"Failed to rename temp file to {}: {e}",
path.display()
));
}
let keys: Vec<&str> = updates
.as_object()
.map(|obj| obj.keys().map(|k| k.as_str()).collect())
.unwrap_or_default();
eprintln!(
"[mcp-server] config_update: wrote {} key(s) to {}",
keys.len(),
path.display()
);
serde_json::json!({
"content": [{
"type": "text",
"text": format!(
"Successfully applied config update ({} key(s): {})",
keys.len(),
keys.join(", ")
)
}]
})
}