tsafe-mcp 0.1.0

First-party MCP server for tsafe โ€” exposes action-shaped tools to MCP-aware hosts over stdio JSON-RPC.
Documentation
//! Cursor install writer โ€” JSON, `mcpServers` shape.
//!
//! Per design ยง5.3 row 2:
//! - Project: `<repo>/.cursor/mcp.json`
//! - Global: `~/.cursor/mcp.json`

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");
    }
}