claude_code_acp/mcp/tools/
slash_command.rs1use async_trait::async_trait;
9use serde::Deserialize;
10use serde_json::{Value, json};
11
12use crate::mcp::{Tool, ToolContext, ToolResult};
13
14#[derive(Debug, Default)]
16pub struct SlashCommandTool;
17
18impl SlashCommandTool {
19 pub fn new() -> Self {
20 Self
21 }
22}
23
24#[derive(Debug, Deserialize)]
26struct SlashCommandInput {
27 command: String,
29 #[serde(default)]
31 args: String,
32}
33
34#[async_trait]
35impl Tool for SlashCommandTool {
36 fn name(&self) -> &str {
37 "SlashCommand"
38 }
39
40 fn description(&self) -> &str {
41 "Execute a slash command. Available commands are sent to the client via available_commands_update."
42 }
43
44 fn input_schema(&self) -> Value {
45 json!({
46 "type": "object",
47 "title": "slash_command",
48 "description": "Execute a user-invocable slash command",
49 "properties": {
50 "command": {
51 "type": "string",
52 "description": "The slash command to execute (e.g., 'commit', 'review-pr')"
53 },
54 "args": {
55 "type": "string",
56 "description": "Optional arguments for the command"
57 }
58 },
59 "required": ["command"]
60 })
61 }
62
63 async fn execute(&self, input: Value, _context: &ToolContext) -> ToolResult {
64 let params: SlashCommandInput = match serde_json::from_value(input) {
66 Ok(p) => p,
67 Err(e) => return ToolResult::error(format!("Invalid input: {}", e)),
68 };
69
70 let full_command = if params.args.is_empty() {
72 format!("/{}", params.command)
73 } else {
74 format!("/{} {}", params.command, params.args)
75 };
76
77 ToolResult::success(format!("Slash command: '{}'", full_command)).with_metadata(json!({
79 "command": params.command,
80 "args": params.args,
81 "full_command": full_command
82 }))
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_slash_command_tool_properties() {
92 let tool = SlashCommandTool;
93 assert_eq!(tool.name(), "SlashCommand");
94 assert!(tool.description().contains("slash command"));
95 }
96
97 #[test]
98 fn test_slash_command_input_schema() {
99 let tool = SlashCommandTool;
100 let schema = tool.input_schema();
101
102 assert_eq!(schema["type"], "object");
103 assert_eq!(schema["title"], "slash_command");
104 assert!(schema["properties"]["command"].is_object());
105 assert!(
106 schema["required"]
107 .as_array()
108 .unwrap()
109 .contains(&json!("command"))
110 );
111 }
112}