Skip to main content
Glama

sftp_tool

Connect to an SSH server to upload or download files between local and remote paths using this automation tool from the ToolBox MCP Server.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction: upload or download
localPathYesLocal file path (absolute)
remotePathYesRemote file path
serverNameYesSSH server name

Implementation Reference

  • Main execution logic for the sftp_tool. Parses arguments, validates inputs, establishes SSH connection and SFTP session, performs upload or download, handles cleanup, and returns formatted response or error.
    export default async (request: any) => { try { // 解析请求参数 const { serverName, action, localPath, remotePath } = request.params.arguments; // 验证参数 if (!serverName || !action || !localPath || !remotePath) { throw new Error("Missing required parameters: serverName, action, localPath, remotePath"); } if (action !== 'upload' && action !== 'download') { throw new Error('Invalid action. Must be "upload" or "download".'); } // 获取SSH连接 const conn = await getSSHConnection(serverName); // 获取SFTP会话 const sftp = await getSFTPSession(conn); let result; try { // 执行文件操作 if (action === 'upload') { result = await uploadFile(sftp, localPath, remotePath); } else { result = await downloadFile(sftp, remotePath, localPath); } } finally { // 关闭SFTP会话 sftp.end(); } // 返回成功结果 return { content: [ { type: "text", text: JSON.stringify({ message: result, action: action, localPath: localPath, remotePath: remotePath }, null, 2) } ] }; } catch (error) { // 返回错误结果 return { content: [ { type: "text", text: JSON.stringify({ error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } };
  • JSON schema defining the input parameters for sftp_tool: serverName, action (upload/download), localPath, remotePath.
    export const schema = { name: "sftp_tool", description: "Connect to SSH server and upload/download files", type: "object", properties: { serverName: { type: "string", description: "SSH server name", }, action: { type: "string", description: "Action: upload or download", enum: ["upload", "download"], }, localPath: { type: "string", description: "Local file path (absolute)", }, remotePath: { type: "string", description: "Remote file path", }, }, required: ["serverName", "action", "localPath", "remotePath"] };
  • Dynamic loader and registration function that scans src/tools for *_tool.ts files, imports them (including sftp_tool.ts), extracts default handler, schema, destroy, sets toolName from filename ('sftp_tool'), and registers in tools array and handlers map.
    export async function loadTools(reload: boolean = false): Promise<{ [key: string]: (request: ToolRequest) => Promise<ToolResponse> }> { // 如果是初始加载且已加载,则直接返回 if (!reload && isLoaded) return; // 如果是重新加载,则重置状态 if (reload) { for (const tool of tools) { await tool?.destroy?.(); delete handlers[tool.name]; } tools.length = 0; isLoaded = false; } // 获取所有工具文件 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; }
  • Core helper to manage SSH connections: caches connections per serverName, parses URI from env var SSH_{serverName}_URI (format user:pass@host:port), creates ssh2 Client if not cached.
    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 }); }); }
  • Destroy function called on tool unload to close all cached SSH connections and clear the cache.
    export async function destroy() { console.log("Destroy sftp_tool"); // 关闭所有SSH连接 for (const serverName in sshConnections) { if (sshConnections[serverName]) { try { if (sshConnections[serverName].end) { sshConnections[serverName].end(); } } catch (error) { console.error(`Failed to close SSH connection for ${serverName}: ${error}`); } finally { delete sshConnections[serverName]; } } } sshConnections = {}; }

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

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