Skip to main content
Glama

ssh_execute

Execute commands on remote hosts via SSH with predefined connections. Configure SSH details in config.json and use connection IDs to send commands securely.

Instructions

Execute a command on a remote host via SSH

Example usage:

{ "connectionId": "raspberry-pi", "command": "uname -a" }

Configuration required in config.json:

{ "ssh": { "enabled": true, "connections": { "raspberry-pi": { "host": "raspberrypi.local", "port": 22, "username": "pi", "password": "raspberry" } } } }

Input Schema

NameRequiredDescriptionDefault
commandYesCommand to execute
connectionIdYesID of the SSH connection to use

Input Schema (JSON Schema)

{ "properties": { "command": { "description": "Command to execute", "type": "string" }, "connectionId": { "description": "ID of the SSH connection to use", "enum": [], "type": "string" } }, "required": [ "connectionId", "command" ], "type": "object" }

Implementation Reference

  • Main handler logic for 'ssh_execute' tool: checks SSH enabled, parses arguments, retrieves connection config, validates command, gets SSH connection from pool, executes command, handles history logging, returns output and metadata.
    case "ssh_execute": { if (!this.config.ssh.enabled) { throw new McpError( ErrorCode.InvalidRequest, "SSH support is disabled in configuration" ); } const args = z.object({ connectionId: z.string(), command: z.string() }).parse(request.params.arguments); const connectionConfig = this.config.ssh.connections[args.connectionId]; if (!connectionConfig) { throw new McpError( ErrorCode.InvalidRequest, `Unknown SSH connection ID: ${args.connectionId}` ); } try { // Validate command this.validateCommand('cmd', args.command); const connection = await this.sshPool.getConnection(args.connectionId, connectionConfig); const { output, exitCode } = await connection.executeCommand(args.command); // Store in history if enabled if (this.config.security.logCommands) { this.commandHistory.push({ command: args.command, output, timestamp: new Date().toISOString(), exitCode, connectionId: args.connectionId }); if (this.commandHistory.length > this.config.security.maxHistorySize) { this.commandHistory = this.commandHistory.slice(-this.config.security.maxHistorySize); } } return { content: [{ type: "text", text: output || 'Command completed successfully (no output)' }], isError: exitCode !== 0, metadata: { exitCode, connectionId: args.connectionId } }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); if (this.config.security.logCommands) { this.commandHistory.push({ command: args.command, output: `SSH error: ${errorMessage}`, timestamp: new Date().toISOString(), exitCode: -1, connectionId: args.connectionId }); } throw new McpError( ErrorCode.InternalError, `SSH error: ${errorMessage}` ); } }
  • Input schema and description for the 'ssh_execute' tool, defining required parameters connectionId and command, dynamically using configured SSH connections.
    name: "ssh_execute", description: `Execute a command on a remote host via SSH Example usage: \`\`\`json { "connectionId": "raspberry-pi", "command": "uname -a" } \`\`\` Configuration required in config.json: \`\`\`json { "ssh": { "enabled": true, "connections": { "raspberry-pi": { "host": "raspberrypi.local", "port": 22, "username": "pi", "password": "raspberry" } } } } \`\`\``, inputSchema: { type: "object", properties: { connectionId: { type: "string", description: "ID of the SSH connection to use", enum: Object.keys(this.config.ssh.connections) }, command: { type: "string", description: "Command to execute" } }, required: ["connectionId", "command"] } },
  • src/index.ts:271-533 (registration)
    The 'ssh_execute' tool is registered in the list of available tools returned by ListToolsRequestSchema handler.
    tools: [ { name: "execute_command", description: `Execute a command in the specified shell (powershell, cmd, or gitbash) Example usage (PowerShell): \`\`\`json { "shell": "powershell", "command": "Get-Process | Select-Object -First 5", "workingDir": "C:\\Users\\username" } \`\`\` Example usage (CMD): \`\`\`json { "shell": "cmd", "command": "dir /b", "workingDir": "C:\\Projects" } \`\`\` Example usage (Git Bash): \`\`\`json { "shell": "gitbash", "command": "ls -la", "workingDir": "/c/Users/username" } \`\`\``, inputSchema: { type: "object", properties: { shell: { type: "string", enum: Object.keys(this.config.shells).filter(shell => this.config.shells[shell as keyof typeof this.config.shells].enabled ), description: "Shell to use for command execution" }, command: { type: "string", description: "Command to execute" }, workingDir: { type: "string", description: "Working directory for command execution (optional)" } }, required: ["shell", "command"] } }, { name: "get_command_history", description: `Get the history of executed commands Example usage: \`\`\`json { "limit": 5 } \`\`\` Example response: \`\`\`json [ { "command": "Get-Process", "output": "...", "timestamp": "2024-03-20T10:30:00Z", "exitCode": 0 } ] \`\`\``, inputSchema: { type: "object", properties: { limit: { type: "number", description: `Maximum number of history entries to return (default: 10, max: ${this.config.security.maxHistorySize})` } } } }, { name: "ssh_execute", description: `Execute a command on a remote host via SSH Example usage: \`\`\`json { "connectionId": "raspberry-pi", "command": "uname -a" } \`\`\` Configuration required in config.json: \`\`\`json { "ssh": { "enabled": true, "connections": { "raspberry-pi": { "host": "raspberrypi.local", "port": 22, "username": "pi", "password": "raspberry" } } } } \`\`\``, inputSchema: { type: "object", properties: { connectionId: { type: "string", description: "ID of the SSH connection to use", enum: Object.keys(this.config.ssh.connections) }, command: { type: "string", description: "Command to execute" } }, required: ["connectionId", "command"] } }, { name: "ssh_disconnect", description: `Disconnect from an SSH server Example usage: \`\`\`json { "connectionId": "raspberry-pi" } \`\`\` Use this to cleanly close SSH connections when they're no longer needed.`, inputSchema: { type: "object", properties: { connectionId: { type: "string", description: "ID of the SSH connection to disconnect", enum: Object.keys(this.config.ssh.connections) } }, required: ["connectionId"] } }, { name: "create_ssh_connection", description: "Create a new SSH connection", inputSchema: { type: "object", properties: { connectionId: { type: "string", description: "ID of the SSH connection" }, connectionConfig: { type: "object", properties: { host: { type: "string", description: "Host of the SSH connection" }, port: { type: "number", description: "Port of the SSH connection" }, username: { type: "string", description: "Username for the SSH connection" }, password: { type: "string", description: "Password for the SSH connection" }, privateKeyPath: { type: "string", description: "Path to the private key for the SSH connection" } }, required: ["connectionId", "connectionConfig"] } } } }, { name: "read_ssh_connections", description: "Read all SSH connections", inputSchema: { type: "object", properties: {} // No input parameters needed } }, { name: "update_ssh_connection", description: "Update an existing SSH connection", inputSchema: { type: "object", properties: { connectionId: { type: "string", description: "ID of the SSH connection to update" }, connectionConfig: { type: "object", properties: { host: { type: "string", description: "Host of the SSH connection" }, port: { type: "number", description: "Port of the SSH connection" }, username: { type: "string", description: "Username for the SSH connection" }, password: { type: "string", description: "Password for the SSH connection" }, privateKeyPath: { type: "string", description: "Path to the private key for the SSH connection" } }, required: ["connectionId", "connectionConfig"] } } } }, { name: "delete_ssh_connection", description: "Delete an existing SSH connection", inputSchema: { type: "object", properties: { connectionId: { type: "string", description: "ID of the SSH connection to delete" } }, required: ["connectionId"] } }, { name: "get_current_directory", description: "Get the current working directory", inputSchema: { type: "object", properties: {} // No input parameters needed } } ] }));
  • Implements the core SSH command execution in SSHConnection class using ssh2 Client.exec, capturing stdout and stderr, handling connection state.
    async executeCommand(command: string): Promise<{ output: string; exitCode: number }> { this.lastActivity = Date.now(); // Check connection and attempt reconnect if needed if (!this.isConnected) { await this.connect(); } return new Promise((resolve, reject) => { this.client.exec(command, (err, stream) => { if (err) { reject(err); return; } let output = ''; let errorOutput = ''; stream .on('data', (data: Buffer) => { output += data.toString(); }) .stderr.on('data', (data: Buffer) => { errorOutput += data.toString(); }); stream.on('close', (code: number) => { this.lastActivity = Date.now(); resolve({ output: output || errorOutput, exitCode: code || 0 }); }); }); }); }
  • SSHConnectionPool manages persistent SSH connections, providing getConnection method used by the handler to obtain or create connections.
    export class SSHConnectionPool { private connections: Map<string, SSHConnection> = new Map(); async getConnection(connectionId: string, config: SSHConnectionConfig): Promise<SSHConnection> { let connection = this.connections.get(connectionId); if (!connection) { connection = new SSHConnection(config); this.connections.set(connectionId, connection); await connection.connect(); } else if (!connection.isActive()) { await connection.connect(); } return connection; } async closeConnection(connectionId: string): Promise<void> { const connection = this.connections.get(connectionId); if (connection) { connection.disconnect(); this.connections.delete(connectionId); } } closeAll(): void { for (const connection of this.connections.values()) { connection.disconnect(); } this.connections.clear(); } }

Other Tools

Related 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/simon-ami/win-cli-mcp-server'

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