Skip to main content
Glama
vilasone455

SSH MCP Server

by vilasone455

secure_execute_command

Execute read-only shell commands on remote systems via SSH to retrieve output without modifying state.

Instructions

Run a read‑only shell command (i.e., one that does not mutate state) in an existing SSH session and return stdout/stderr/exitCode.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
connection_idYes
commandYesRead‑only shell command to execute (e.g., ls, cat).

Implementation Reference

  • The handler logic for the 'secure_execute_command' tool. Extracts arguments, validates connection and command, performs security check with isCommandDangerous, executes the command via wrapExec on the SSH client, and returns stdout, stderr, exitCode.
    if (name === "secure_execute_command") {
      const { connection_id, command } = args;
      if (!command?.trim()) throw new Error("Command cannot be empty.");
      const conn = connections.get(connection_id);
      if (!conn) throw new Error(`connection_id '${connection_id}' not found.`);
    
      // More refined security check - focus on actually dangerous operations
      if (isCommandDangerous(command)) {
        throw new Error("Command contains potentially dangerous operations and is not allowed.");
      }
    
      const { stdout, stderr, exitCode } = await wrapExec(conn.client, command);
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify({ stdout, stderr, exitCode }, null, 2),
          },
        ],
      };
    
    }
  • The input schema definition for the 'secure_execute_command' tool, advertised in the ListTools response.
    {
      name: "secure_execute_command",
      description:
        "Run a **read‑only** shell command (i.e., one that does not mutate state) in an existing SSH session and return stdout/stderr/exitCode.",
      inputSchema: {
        type: "object",
        required: ["connection_id", "command"],
        properties: {
          connection_id: { type: "string" },
          command: { type: "string", description: "Read‑only shell command to execute (e.g., ls, cat)." },
        },
        additionalProperties: false,
      },
    },
  • src/index.ts:140-207 (registration)
    Registration of the tool via the ListToolsRequestSchema handler, which includes 'secure_execute_command' in the list of available tools.
    server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        {
          name: "get_available_connections",
          description:
            "List every SSH-capable machine this server knows about (but is NOT yet connected).",
          inputSchema: { type: "object", properties: {}, additionalProperties: false },
        },
        {
          name: "create_connection",
          description:
            "Open an SSH session to the given machine and track it in global state so subsequent tool calls can reuse it.",
          inputSchema: {
            type: "object",
            required: ["machine_id", "title"],
            properties: {
              machine_id: { type: "string", description: "ID from get_available_connections" },
              title: { type: "string", description: "Purpose of this session (displayed in UIs)" },
            },
            additionalProperties: false,
          },
        },
        {
          name: "get_connections",
          description: "Return every STILL-OPEN SSH session in global state.",
          inputSchema: { type: "object", properties: {}, additionalProperties: false },
        },
        {
          name: "execute_command",
          description:
            "Run a shell command in an existing SSH session and return stdout/stderr/exitCode.",
          inputSchema: {
            type: "object",
            required: ["connection_id", "command"],
            properties: {
              connection_id: { type: "string" },
              command: { type: "string", description: "Shell command to execute" },
            },
            additionalProperties: false,
          },
        },
        {
          name: "secure_execute_command",
          description:
            "Run a **read‑only** shell command (i.e., one that does not mutate state) in an existing SSH session and return stdout/stderr/exitCode.",
          inputSchema: {
            type: "object",
            required: ["connection_id", "command"],
            properties: {
              connection_id: { type: "string" },
              command: { type: "string", description: "Read‑only shell command to execute (e.g., ls, cat)." },
            },
            additionalProperties: false,
          },
        },
    
        {
          name: "close_connection",
          description: "Terminate an SSH session and remove it from global state.",
          inputSchema: {
            type: "object",
            required: ["connection_id"],
            properties: { connection_id: { type: "string" } },
            additionalProperties: false,
          },
        },
      ],
    }));
  • Helper function specifically used by secure_execute_command to validate if a command is safe (read-only) by checking against whitelisted read-only patterns and blacklisted dangerous regex patterns.
    function isCommandDangerous(command) {
      const cmd = command.trim().toLowerCase();
    
      // Allow common read-only systemctl operations
      if (/^systemctl\s+(status|show|list-units|list-unit-files|is-active|is-enabled|is-failed|cat|help)/.test(cmd)) {
        return false;
      }
    
      // Allow read-only git operations
      if (/^git\s+(status|log|show|diff|branch|remote|config\s+--list|ls-files|ls-remote)/.test(cmd)) {
        return false;
      }
    
      // Allow read-only package manager operations
      if (/^(apt|yum|dnf|pacman)\s+(list|search|show|info|query)/.test(cmd)) {
        return false;
      }
    
      // Allow read-only docker operations
      if (/^docker\s+(ps|images|inspect|logs|version|info|system\s+df|system\s+info)/.test(cmd)) {
        return false;
      }
    
      // Allow read-only kubectl operations
      if (/^kubectl\s+(get|describe|logs|explain|version|cluster-info|config\s+view)/.test(cmd)) {
        return false;
      }
    
      // Check for actually dangerous patterns
      const dangerousPatterns = [
        // File system destructive operations
        /\brm\s+(-[rf]*\s+)*(\/|\*|\$|~)/,  // rm with dangerous targets
        /\bmv\s+.*\s+(\/|\*)/,               // mv to dangerous locations
        /\bchmod\s+[0-7]*\s+(\/|~|\*)/,      // chmod on system locations
        /\bchown\s+.*\s+(\/|~|\*)/,          // chown on system locations
    
        // Output redirection that could overwrite files
        />[^|&]*\s*(\/|~|\*)/,               // Redirect to system locations
        /\bdd\s+.*of=/,                      // dd operations
        /\btruncate\s/,                      // truncate files
    
        // Process/service management (destructive)
        /\b(systemctl|service)\s+(stop|start|restart|disable|enable|mask|reload)/,
        /\b(kill|pkill|killall)\s/,
    
        // Package management (installation/removal)
        /\b(apt|yum|dnf|pacman)\s+(install|remove|update|upgrade|autoremove)/,
    
        // Network configuration
        /\b(iptables|ufw|firewall-cmd)\s/,
        /\bifconfig\s+.*\s+(up|down)/,
    
        // User/system modification
        /\b(useradd|userdel|usermod|passwd|su\s|sudo\s)/,
        /\bcrontab\s+-[er]/,
    
        // Dangerous git operations
        /\bgit\s+(push|pull|clone|reset\s+--hard|clean\s+-f|rm)/,
    
        // Container/orchestration destructive operations
        /\bdocker\s+(rm|rmi|kill|stop|exec|run|build|push|pull)/,
        /\bkubectl\s+(delete|apply|create|replace|patch|scale|rollout)/,
    
        // Text editors (could modify files)
        /\b(nano|vi|vim|emacs|code)\s/,
    
        // Archive operations that could overwrite
        /\b(tar|unzip|unrar)\s+.*-[xf]/,
    
        // System monitoring that could be used maliciously
        /\btcpdump\s/,
        /\bwireshark\s/,
    
        // Compilation (could create executables)
        /\b(gcc|g\+\+|make|cmake|javac|python\s+setup\.py\s+install)/,
    
        // Background processes
        /&\s*$/,                             // Commands ending with &
        /\bnohup\s/,
    
        // Pipes to dangerous commands
        /\|\s*(sh|bash|zsh|csh|tcsh|fish|python|perl|ruby|node)/,
      ];
    
      // Check against dangerous patterns
      return dangerousPatterns.some(pattern => pattern.test(cmd));
    }
  • Shared helper function to execute a command over SSH, capturing stdout, stderr, and exit code. Used by both execute_command and secure_execute_command.
    function wrapExec(client, command): any {
      return new Promise((resolve, reject) => {
        let stdout = "";
        let stderr = "";
        client.exec(command, (err, stream) => {
          if (err) return reject(err);
          stream
            .on("close", (code) => {
              resolve({ stdout, stderr, exitCode: code });
            })
            .on("data", (data) => {
              stdout += data.toString();
            })
            .stderr.on("data", (data) => {
              stderr += data.toString();
            });
        });
      });
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively communicates key traits: the command is read-only (non-mutating), executes in an SSH session, and returns specific outputs (stdout, stderr, exitCode). It does not cover aspects like error handling, timeouts, or security constraints, but provides a solid foundation for safe usage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-structured sentence that front-loads key information ('Run a read-only shell command') and efficiently covers execution context, behavior, and outputs. Every word earns its place, with no redundancy or fluff, making it highly concise and clear.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (2 parameters, no output schema, no annotations), the description is largely complete. It covers purpose, constraints, and outputs adequately. However, it lacks details on error cases (e.g., invalid connection_id) and does not reference the sibling tools for context, leaving minor gaps in full contextual understanding.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 50% (only the 'command' parameter has a description). The description adds value by clarifying that 'command' must be read-only (e.g., 'ls, cat'), which is not in the schema. It also implies the purpose of 'connection_id' (for an existing SSH session), partially compensating for the lack of schema description for that parameter. However, it does not fully detail parameter formats or constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the verb ('Run'), resource ('shell command'), and key constraint ('read-only' and 'does not mutate state'), with clear distinction from the sibling 'execute_command' (which presumably allows mutations). It specifies the execution context ('existing SSH session') and what is returned ('stdout/stderr/exitCode'), making the purpose highly specific and differentiated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: for read-only commands in an SSH session. It implies an alternative (the sibling 'execute_command' for non-read-only commands) but does not explicitly name it or detail exclusions. No guidance is given on prerequisites like needing an active connection, but the context is sufficiently clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vilasone455/ssh-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server