Skip to main content
Glama

ssh_tool

Execute commands on SSH servers by specifying server names and commands to run remotely.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
serverNameYesSSH server name
commandYesCommand to execute

Implementation Reference

  • The default exported async function that serves as the main handler for the ssh_tool. It processes the request, validates parameters, establishes SSH connection, executes the command, and returns the result or error in the expected format.
    export default async (request: any) => {
        try {
            // 解析请求参数
            const { serverName, command } = request.params.arguments;
            
            // 验证参数
            if (!serverName || !command) {
                throw new Error("Missing required parameters: serverName, command");
            }
            
            // 获取SSH连接
            const conn = await getSSHConnection(serverName);
            
            // 执行命令
            const result = await executeCommand(conn, command);
            
            // 返回成功结果
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify({
                            server: serverName,
                            command: command,
                            ...result
                        }, null, 2)
                    }
                ]
            };
        } catch (error) {
            // 返回错误结果
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify({
                            error: error instanceof Error ? error.message : String(error)
                        }, null, 2)
                    }
                ],
                isError: true
            };
        }
    };
  • The input schema definition for the ssh_tool, specifying parameters serverName and command as required.
    export const schema = {
        name: "ssh_tool",
        description: "Connect to SSH server and execute commands",
        type: "object",
        properties: {
            serverName: {
                type: "string",
                description: "SSH server name",
            },
            command: {
                type: "string",
                description: "Command to execute",
            },
        },
        required: ["serverName", "command"]
    };
  • Dynamic registration of tools (including ssh_tool) in the loadTools function by scanning src/tools directory, importing modules, extracting schema, handler (default export), and destroy function, then storing in global tools and handlers maps.
      // 获取所有工具文件
      const toolFiles = fs.readdirSync(toolsDir).filter(file => file.endsWith('.js') || file.endsWith('.ts'));
    
      // 加载每个工具
      for (const file of toolFiles) {
        const toolPath = path.join(toolsDir, file);
        try {
          // 如果是重新加载,清除模块缓存
          if (reload) clearModuleCache(toolPath);
    
          // 导入模块,重新加载时添加时间戳防止缓存
          const importPath = 'file://' + toolPath + (reload ? `?update=${Date.now()}` : '');
          const { default: tool, schema, destroy } = await import(importPath);
          const toolName = path.parse(toolPath).name;
    
          // 注册工具
          tools.push({
            name: toolName,
            description: tool.description,
            inputSchema: schema,
            destroy: destroy
          });
    
          // 注册处理函数
          handlers[toolName] = async (request: ToolRequest) => { return await tool(request); };
        } catch (error) {
          console.error(`Failed to ${reload ? 'reload' : 'load'} tool ${file}:`, error);
        }
      }
    
      isLoaded = true;
      if (reload) console.log(`Successfully reloaded ${tools.length} tools`);
    
      return handlers;
    }
  • Helper function to retrieve or establish a new SSH connection using environment variables like SSH_{serverName}_URI.
    async function getSSHConnection(serverName: string): Promise<Client> {
        // 如果已有连接,直接返回
        if (sshConnections[serverName]) {
            return sshConnections[serverName];
        }
    
        // 从环境变量获取连接信息
        const sshUri = process.env[`SSH_${serverName}_URI`];
        if (!sshUri) {
            throw new Error(`SSH_${serverName}_URI environment variable must be set.`);
        }
    
        // 解析连接信息
        const [usernameAndpassword, HostAndport] = sshUri.split('@');
        const [username, password] = usernameAndpassword.split(':');
        const [host, port] = HostAndport.split(':');
    
        // 创建新连接
        return new Promise((resolve, reject) => {
            const conn = new Client();
            
            conn.on('ready', () => {
                sshConnections[serverName] = conn;
                resolve(conn);
            });
            
            conn.on('error', (err) => {
                delete sshConnections[serverName];
                reject(new Error(`SSH connection error: ${err.message}`));
            });
            
            conn.on('end', () => {
                delete sshConnections[serverName];
            });
            
            conn.connect({
                host: host,
                port: parseInt(port),
                username: username,
                password: password
            });
        });
    }
  • Helper function to execute a command over an established SSH connection and capture stdout, stderr, exit code, and signal.
    /**
     * 在SSH服务器上执行命令
     * @param conn SSH连接
     * @param command 要执行的命令
     * @returns 命令执行结果
     */
    async function executeCommand(conn: Client, command: string): Promise<{ stdout: string, stderr: string, code: number | null, signal: any }> {
        return new Promise((resolve, reject) => {
            conn.exec(command, (err, stream) => {
                if (err) {
                    reject(new Error(`Command execution failed: ${err.message}`));
                    return;
                }
                
                let stdout = '';
                let stderr = '';
                
                stream.on('close', (code, signal) => {
                    resolve({ stdout, stderr, code, signal });
                });
                
                stream.on('data', (data) => {
                    stdout += data.toString();
                });
                
                stream.stderr.on('data', (data) => {
                    stderr += data.toString();
                });
                
                stream.on('error', (err) => {
                    reject(new Error(`Stream error: ${err.message}`));
                });
            });
        });
    }

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/xiaoguomeiyitian/ToolBox'

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