use clap::{Parser, Subcommand, ValueEnum};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(name = "magick-mcp")]
#[command(version = env!("CARGO_PKG_VERSION"))]
pub struct Args {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand, Debug)]
pub enum Commands {
Check,
Mcp,
Install {
#[arg(long, value_enum, default_value = "both")]
r#type: ClientTypeArg,
},
Magick {
command: String,
},
Func {
#[command(subcommand)]
func_command: FuncCommands,
},
}
#[derive(Subcommand, Debug)]
pub enum FuncCommands {
List,
Print {
name: String,
},
Execute {
name: String,
#[arg(long)]
input: Option<String>,
},
Save {
#[arg(long)]
file: PathBuf,
},
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum ClientTypeArg {
Cursor,
Claude,
Both,
}
impl From<ClientTypeArg> for crate::ClientType {
fn from(arg: ClientTypeArg) -> Self {
match arg {
ClientTypeArg::Cursor => crate::ClientType::Cursor,
ClientTypeArg::Claude => crate::ClientType::Claude,
ClientTypeArg::Both => crate::ClientType::Both,
}
}
}
pub fn handle_command(command: Commands) {
match command {
Commands::Check => match crate::check() {
Ok(output) => {
println!("{output}");
std::process::exit(0);
}
Err(e) => {
eprintln!("Error: {e}");
std::process::exit(1);
}
},
Commands::Mcp => {
let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime");
if let Err(e) = rt.block_on(crate::mcp::run_server()) {
eprintln!("Error running MCP server: {e}");
std::process::exit(1);
}
}
Commands::Install { r#type } => {
let client_type: crate::ClientType = r#type.into();
let config_paths = match crate::ConfigPaths::from_home_dir() {
Ok(paths) => paths,
Err(e) => {
eprintln!("Error getting config paths: {e}");
std::process::exit(1);
}
};
match crate::install(client_type, config_paths) {
Ok(_) => {
println!("Successfully installed magick-mcp to MCP configuration");
std::process::exit(0);
}
Err(e) => {
eprintln!("Error installing magick-mcp: {e}");
std::process::exit(1);
}
}
}
Commands::Magick { command } => match crate::magick(&command, None) {
Ok(output) => {
println!("{output}");
std::process::exit(0);
}
Err(e) => {
eprintln!("Error executing magick command: {e}");
std::process::exit(1);
}
},
Commands::Func { func_command } => handle_func_command(func_command),
}
}
fn handle_func_command(func_command: FuncCommands) {
match func_command {
FuncCommands::List => match crate::list_functions() {
Ok(functions) => {
if functions.is_empty() {
println!("No functions found");
} else {
for name in functions {
println!("{name}");
}
}
std::process::exit(0);
}
Err(e) => {
eprintln!("Error listing functions: {e}");
std::process::exit(1);
}
},
FuncCommands::Print { name } => match crate::load_function(&name) {
Ok(function) => {
println!("Name: {}", function.name);
println!("Commands:");
for command in &function.commands {
println!(" - {command}");
}
std::process::exit(0);
}
Err(e) => {
eprintln!("Error loading function '{name}': {e}");
std::process::exit(1);
}
},
FuncCommands::Execute { name, input } => {
let function = match crate::load_function(&name) {
Ok(f) => f,
Err(e) => {
eprintln!("Error loading function '{name}': {e}");
std::process::exit(1);
}
};
let input_ref = input.as_deref();
match crate::run_function(&function, None, input_ref) {
Ok(outputs) => {
for output in outputs {
println!("{output}");
}
std::process::exit(0);
}
Err(e) => {
eprintln!("Error executing function '{name}': {e}");
std::process::exit(1);
}
}
}
FuncCommands::Save { file } => {
let contents = match std::fs::read_to_string(&file) {
Ok(c) => c,
Err(e) => {
eprintln!("Error reading file '{}': {e}", file.display());
std::process::exit(1);
}
};
let function: crate::Function = match serde_json::from_str(&contents) {
Ok(f) => f,
Err(e) => {
eprintln!("Error parsing JSON from '{}': {e}", file.display());
std::process::exit(1);
}
};
match crate::save_function(function) {
Ok(_) => {
println!("Function saved successfully");
std::process::exit(0);
}
Err(e) => {
eprintln!("Error saving function: {e}");
std::process::exit(1);
}
}
}
}
}