use crate::mcp::server::MagickServerHandler;
use rmcp::handler::server::router::tool::ToolRoute;
use rmcp::handler::server::tool::ToolCallContext;
use rmcp::model::{CallToolResult, ErrorCode, ErrorData, Tool};
use serde_json::json;
use std::path::Path;
async fn func_execute_tool(
context: ToolCallContext<'_, MagickServerHandler>,
) -> Result<CallToolResult, ErrorData> {
let name = context
.arguments
.as_ref()
.and_then(|args| args.get("name"))
.and_then(|v| v.as_str())
.ok_or_else(|| ErrorData {
code: ErrorCode::INVALID_PARAMS,
message: "Missing required parameter: name".to_string().into(),
data: None,
})?;
let workspace = context
.arguments
.as_ref()
.and_then(|args| args.get("workspace"))
.and_then(|v| v.as_str())
.map(Path::new);
let input = context
.arguments
.as_ref()
.and_then(|args| args.get("input"))
.and_then(|v| v.as_str());
let function = match crate::load_function(name) {
Ok(f) => f,
Err(e) => {
let error_result = json!({
"error": format!("Failed to load function '{}': {}", name, e),
"success": false
});
return Ok(CallToolResult::structured_error(error_result));
}
};
match crate::run_function(&function, workspace, input) {
Ok(outputs) => {
let result = json!({
"outputs": outputs,
"success": true,
"function_name": name
});
Ok(CallToolResult::structured(result))
}
Err(e) => {
let error_result = json!({
"error": format!("Failed to execute function '{}': {}", name, e),
"success": false
});
Ok(CallToolResult::structured_error(error_result))
}
}
}
pub fn func_execute_tool_route() -> ToolRoute<MagickServerHandler> {
let input_schema: serde_json::Value = json!({
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of the function to execute"
},
"workspace": {
"type": "string",
"description": "Workspace path to set as the working directory for commands"
},
"input": {
"type": "string",
"description": "Optional input value to replace $input placeholders in commands"
}
},
"required": ["name", "workspace"]
});
let tool = Tool::new(
"func_execute",
"Execute a magick function by name, running all commands in sequence",
input_schema.as_object().unwrap().clone(),
);
ToolRoute::new_dyn(tool, |context| Box::pin(func_execute_tool(context)))
}