#ifndef HUMANUS_TOOL_BASH_H #define HUMANUS_TOOL_BASH_H #include "base.h" #include "mcp_stdio_client.h" #include "toml.hpp" #include "config.h" #include namespace humanus { // A tool for executing shell commands using MCP shell server // https://github.com/kevinwatt/shell-mcp.git struct Shell : BaseMCPTool { inline static const std::string name_ = "shell"; inline static const std::string description_ = "Execute a shell command in the terminal."; inline static const json parameters_ = json::parse(R"json({ "type": "object", "properties": { "command": { "type": "string", "description": "Command to execute. Available commands:\n- ls: List directory contents\n- cat: Concatenate and display file contents\n- pwd: Show current working directory\n- df: Show disk usage\n- echo: Display text\n- ps: Show process status\n- free: Show memory usage\n- uptime: Show system uptime\n- date: Show system date and time\n- grep: Search text patterns in files\n- w: Show who is logged on and what they are doing\n- whois: Query WHOIS domain registration information\n- find: Search for files in a directory hierarchy\n- netstat: Network connection information\n- lspci: List PCI devices\n- lsusb: List USB devices\n- dig: DNS lookup utility\n- nslookup: Query DNS records\n- ip: Show / manipulate routing, network devices, interfaces and tunnels\n- whereis: Locate the binary, source, and manual page files for a command", "enum": [ "ls", "cat", "pwd", "df", "echo", "ps", "free", "uptime", "date", "grep", "w", "whois", "find", "netstat", "lspci", "lsusb", "dig", "nslookup", "ip", "whereis" ] }, "args": { "type": "array", "description": "Additional arguments to pass to the command" }, "timeout": { "type": "number", "description": "Execution timeout in ms" } }, "required": ["command"] })json"); inline static std::set allowed_commands = { "ls", "cat", "pwd", "df", // "echo", // Not working now "ps", "free", "uptime", "date", "grep", "w", "whois", "find", "netstat", "lspci", "lsusb", "dig", "nslookup", "ip", "whereis" }; Shell() : BaseMCPTool(name_, description_, parameters_) {} ToolResult execute(const json& args) override { try { // Ensure client is initialized if (!_client) { return ToolError("Failed to initialize shell client"); } std::string command; if (args.contains("command")) { if (args["command"].is_string()) { command = args["command"].get(); } else { return ToolError("Invalid command format"); } } else { return ToolError("'command' is required"); } if (allowed_commands.find(command) == allowed_commands.end()) { return ToolError("Unknown command '" + command + "'. Please use one of the following commands: " + std::accumulate(allowed_commands.begin(), allowed_commands.end(), std::string(), [](const std::string& a, const std::string& b) { return a + (a.empty() ? "" : ", ") + b; })); } // Call shell tool json result = _client->call_tool("shell_" + command, args); bool is_error = result.value("isError", false); // Return different ToolResult based on whether there is an error if (is_error) { return ToolError(result.value("content", json::array())); } else { return ToolResult(result.value("content", json::array())); } } catch (const std::exception& e) { return ToolError("Error executing shell command: " + std::string(e.what())); } } }; } #endif // HUMANUS_TOOL_BASH_H