use std::path::PathBuf;
use crate::errors::{McpError, McpErrorKind};
use crate::install::{InstallOpts, Scope};
pub fn write(opts: &InstallOpts) -> Result<(), McpError> {
let path = config_path(&opts.scope)?;
super::shared_json::write_mcp_servers_entry(&path, "Cursor", opts)
}
pub fn config_path(scope: &Scope) -> Result<PathBuf, McpError> {
match scope {
Scope::Project { dir } => Ok(dir.join(".cursor").join("mcp.json")),
Scope::Global => {
let home = directories::BaseDirs::new()
.map(|b| b.home_dir().to_path_buf())
.ok_or_else(|| {
McpError::new(
McpErrorKind::InternalError,
"could not resolve home directory",
)
})?;
Ok(home.join(".cursor").join("mcp.json"))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::install::Scope;
use serde_json::Value;
#[test]
fn project_scope_writes_under_cursor_dir() {
let tmp = tempfile::tempdir().unwrap();
let opts = InstallOpts {
profile: "demo".to_string(),
allowed_keys: vec!["demo/*".to_string()],
denied_keys: vec![],
contract: None,
allow_reveal: false,
name: Some("testsrv".to_string()),
scope: Scope::Project {
dir: tmp.path().to_path_buf(),
},
dry_run: false,
uninstall: false,
audit_source: None,
};
write(&opts).unwrap();
let path = tmp.path().join(".cursor").join("mcp.json");
let raw = std::fs::read_to_string(&path).unwrap();
let v: Value = serde_json::from_str(&raw).unwrap();
assert_eq!(v["mcpServers"]["testsrv"]["command"], "tsafe-mcp");
}
}