lean_ctx/tools/registered/
shell_alias.rs1use rmcp::ErrorData;
2use rmcp::model::Tool;
3use serde_json::{Map, Value, json};
4
5use crate::server::tool_trait::{McpTool, ToolContext, ToolOutput, get_str};
6use crate::tool_defs::tool_def;
7
8pub struct ShellAliasTool;
19
20impl McpTool for ShellAliasTool {
21 fn name(&self) -> &'static str {
22 "shell"
23 }
24
25 fn tool_def(&self) -> Tool {
26 tool_def(
27 "shell",
28 "Shell command with auto-compression (~95 patterns). Alias for ctx_shell.\n\
29 Output is compressed for token savings. For verbatim output pass raw=true.\n\
30 Use when your MCP client prefers shell/bash over ctx_shell — transparently\n\
31 delegates to ctx_shell internals.",
32 json!({
33 "type": "object",
34 "properties": {
35 "command": {
36 "type": "string",
37 "description": "Shell command"
38 },
39 "cwd": {
40 "type": "string",
41 "description": "Working dir"
42 },
43 "raw": {
44 "type": "boolean",
45 "description": "Return verbatim output (skip compression). Default false — pass true for the exact bytes."
46 }
47 },
48 "required": ["command"]
49 }),
50 )
51 }
52
53 fn handle(
54 &self,
55 args: &Map<String, Value>,
56 ctx: &ToolContext,
57 ) -> Result<ToolOutput, ErrorData> {
58 let command = get_str(args, "command")
59 .ok_or_else(|| ErrorData::invalid_params("command is required", None))?;
60
61 if let Some(rejection) = crate::tools::ctx_shell::validate_command(&command) {
62 return Ok(ToolOutput::simple(rejection));
63 }
64
65 if let Err(msg) = crate::core::shell_allowlist::check_shell_allowlist(&command) {
66 return Ok(ToolOutput::simple(msg));
67 }
68
69 tokio::task::block_in_place(|| {
70 let cwd = get_str(args, "cwd");
71 let raw = args.get("raw").and_then(Value::as_bool).unwrap_or(false);
75 let mut shell_args = Map::new();
76 shell_args.insert("command".to_string(), Value::String(command));
77 if let Some(dir) = cwd {
78 shell_args.insert("cwd".to_string(), Value::String(dir));
79 }
80 shell_args.insert("raw".to_string(), Value::Bool(raw));
81
82 crate::tools::registered::ctx_shell::CtxShellTool.handle(&shell_args, ctx)
83 })
84 }
85}