The command blocklist and the tunnel port allowlist both stand between an agent and the fleet, and a blocked command runs only when the call passes skip_policy: true — a deliberate act rather than an accident. MCP_ALLOWED_ROOTS is the one that starts open: empty means file operations reach anywhere the SSH user can, so set it before pointing an agent at a production box. The rest of the design is about surviving interruption — a command longer than two minutes moves into a persistent queue, tmux keeps sessions and tunnels alive across a dropped connection, and file_edit refuses when the hash no longer matches what you read, with snapshots as the way back when it changed for a reason.
An SSH and SFTP orchestration server. One call runs a command on a named server, on a list of them, or on the whole fleet; transfers go server to server; long jobs move into a persistent queue rather than blocking; and tmux-backed sessions and tunnels outlive the process that started them. Commands pass a blocklist and tunnels a port allowlist before anything happens.
- task_exec runs a one-shot command against one alias, a list of aliases, or "all"; task_exec_interactive handles prompts and task_exec_sequence runs commands in order
- task_transfer moves files over SFTP including server_to_server, and task_transfer_multi does bulk transfers with glob patterns
- server_add, server_list and server_remove manage aliases, infra_overview gives the fleet view with roles, services and warnings, and server_note_set, get, list and remove keep documented context against each server
- file_read returns content with a SHA-256 hash, and file_edit takes that expectedHash so a surgical edit refuses if the file moved underneath you — with dryRun to preview and backup to keep the original; file_write carries the same two options
- diff_files and diff_folders compare across machines, and compare_all_sources detects drift across N servers at once
- snapshot_create captures file state with deduplication, and snapshot_list, snapshot_diff, snapshot_restore (dryRun by default) and snapshot_delete with orphan cleanup turn that into a rollback path
- tmux_create, tmux_exec, tmux_read, tmux_list and tmux_kill give sessions that survive a dropped connection, with shell_exec, shell_list and shell_close for the lighter case
- tunnel_create opens local, remote or SOCKS5 tunnels kept alive through tmux, and tunnel_list, tunnel_close and tunnel_allowlist_add and remove control which ports are permitted at all
- Monitoring and logs: get_system_resources, get_services_status across systemd, Docker and PM2 with graceful fallback, get_fail2ban_status, check_api_health, get_pm2_logs, get_docker_logs and tail_file
- The queue is addressable rather than opaque: task_queue, task_status, task_history, task_retry, task_wait and task_logs, with queue_stats and pool_stats behind them
- policy_blocklist_list, add and remove hold the blocked command patterns, and a call passes skip_policy: true to step around them deliberately
- Help and guide are written for the agent rather than for you, the guide split into index, workflows, audit and security sections
Node.js 18.0.0 or newer, run as npx @fkom13/mcp-sftp-orchestrator. Every setting is optional: MCP_DATA_DIR defaults to ~/.config/mcp-orchestrator and holds servers.json, apis.json and queue.json; a command runs synchronously until MCP_SYNC_TIMEOUT_S at 120 seconds and then continues in the background, with MCP_DEFAULT_CMD_TIMEOUT_S at 600 and 0 meaning unlimited; MAX_CONNECTIONS_PER_SERVER pools 5 connections with a 300000 ms idle close and a 30000 ms keepalive; MAX_QUEUE_SIZE holds 1000 jobs saved to disk every 5000 ms. MCP_ALLOWED_ROOTS is empty by default, which means file operations are not restricted to any path — set it to fence them in. MIT.
One command — npx @fkom13/mcp-sftp-orchestrator
