Skip to main content
Glama

MCP Server for FTP Access

index.ts6.29 kB
#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import { FtpClient, FtpConfig } from "./ftp-client.js"; // Get FTP config from environment variables const ftpConfig: FtpConfig = { host: process.env.FTP_HOST || "localhost", port: parseInt(process.env.FTP_PORT || "21"), user: process.env.FTP_USER || "anonymous", password: process.env.FTP_PASSWORD || "", secure: process.env.FTP_SECURE?.toLowerCase() === "true" }; // Initialize FTP client const ftpClient = new FtpClient(ftpConfig); // Create server instance const server = new McpServer({ name: "mcp-server-ftp", version: "1.0.0", }); // Register list-directory tool server.tool( "list-directory", "List contents of an FTP directory", { remotePath: z.string().describe("Path of the directory on the FTP server"), }, async ({ remotePath }) => { try { const listing = await ftpClient.listDirectory(remotePath); // Format the output const formatted = listing.map((item) => `${item.type === "directory" ? "[DIR]" : "[FILE]"} ${item.name} ${item.type === "file" ? `(${formatSize(item.size)})` : ""} - ${item.modifiedDate}` ).join("\n"); const summary = `Total: ${listing.length} items (${listing.filter(i => i.type === "directory").length} directories, ${listing.filter(i => i.type === "file").length} files)`; return { content: [ { type: "text", text: `Directory listing for: ${remotePath}\n\n${formatted}\n\n${summary}` } ] }; } catch (error) { return { isError: true, content: [ { type: "text", text: `Error listing directory: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Register download-file tool server.tool( "download-file", "Download a file from the FTP server", { remotePath: z.string().describe("Path of the file on the FTP server"), }, async ({ remotePath }) => { try { const { content } = await ftpClient.downloadFile(remotePath); return { content: [ { type: "text", text: `File content of ${remotePath}:\n\n${content}` } ] }; } catch (error) { return { isError: true, content: [ { type: "text", text: `Error downloading file: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Register upload-file tool server.tool( "upload-file", "Upload a file to the FTP server", { remotePath: z.string().describe("Destination path on the FTP server"), content: z.string().describe("Content to upload to the file"), }, async ({ remotePath, content }) => { try { await ftpClient.uploadFile(remotePath, content); return { content: [ { type: "text", text: `File successfully uploaded to ${remotePath}` } ] }; } catch (error) { return { isError: true, content: [ { type: "text", text: `Error uploading file: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Register create-directory tool server.tool( "create-directory", "Create a new directory on the FTP server", { remotePath: z.string().describe("Path of the directory to create"), }, async ({ remotePath }) => { try { await ftpClient.createDirectory(remotePath); return { content: [ { type: "text", text: `Directory successfully created at ${remotePath}` } ] }; } catch (error) { return { isError: true, content: [ { type: "text", text: `Error creating directory: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Register delete-file tool server.tool( "delete-file", "Delete a file from the FTP server", { remotePath: z.string().describe("Path of the file to delete"), }, async ({ remotePath }) => { try { await ftpClient.deleteFile(remotePath); return { content: [ { type: "text", text: `File successfully deleted from ${remotePath}` } ] }; } catch (error) { return { isError: true, content: [ { type: "text", text: `Error deleting file: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Register delete-directory tool server.tool( "delete-directory", "Delete a directory from the FTP server", { remotePath: z.string().describe("Path of the directory to delete"), }, async ({ remotePath }) => { try { await ftpClient.deleteDirectory(remotePath); return { content: [ { type: "text", text: `Directory successfully deleted from ${remotePath}` } ] }; } catch (error) { return { isError: true, content: [ { type: "text", text: `Error deleting directory: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Helper function to format file sizes function formatSize(bytes: number): string { if (bytes < 1024) return bytes + " B"; else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + " KB"; else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + " MB"; else return (bytes / (1024 * 1024 * 1024)).toFixed(2) + " GB"; } // Initialize and run the server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("FTP MCP Server running on stdio"); } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });

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/alxspiker/mcp-server-ftp'

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