Token-efficient SSH MCP server with hash-verified remote file editing and SFTP transfer
Your agent can read and edit local files — but what about the server running in production? hex-ssh-mcp brings the same hash-verified editing to remote machines over SSH, plus binary-safe SFTP upload and download. Every remote read returns FNV-1a hashes, every edit verifies them, and file transfers stage to temp paths before rename.
Your agent needs to read the nginx config on production — 200 lines, but only the upstream block matters. With raw ssh cat /etc/nginx/nginx.conf, the entire file floods your context. With ssh-read-lines, the agent requests lines 40–80 with hash annotations. Each line carries an FNV-1a tag, ready for immediate editing — no second read needed.
The agent read the file 5 minutes ago and wants to fix a typo on line 65. But someone deployed a hotfix since then — lines shifted. With a raw SSH command, the edit silently overwrites the wrong line. hex-ssh’s ssh-edit-block checks the range checksum before applying. Stale? Edit rejected, current checksum returned. The agent re-reads just the changed range and retries.
The agent greps 10,000 lines of application logs looking for “connection timeout.” Raw output: thousands of duplicate stack traces with different timestamps, UUIDs, and request IDs. ssh-search-code normalizes all dynamic values — UUIDs become <UUID>, timestamps become <TS>, IPs become <IP>. Identical normalized lines collapse with (xN) counts. 10K lines become 40 actionable ones.
The agent generates a new config and writes it to the staging server. But a typo in the path targets /etc/ instead of /home/deploy/etc/. With raw SSH, the file lands in the system directory — potentially breaking the server. hex-ssh checks against ALLOWED_DIRS before every write. Path outside the permitted list? Rejected immediately.
| Tool | What it does |
|---|---|
| remote-ssh | Execute shell commands. Disabled by default; set REMOTE_SSH_MODE=safe or open to enable |
| ssh-read-lines | Read remote files with hash-annotated lines. Partial reads via startLine/endLine |
| ssh-edit-block | Hash-verified anchor edits. Checksum verification + compact diff |
| ssh-search-code | Search remote files with grep. Deduplicated results with (xN) counts |
| ssh-write-chunk | Write or append to remote files. Rewrite is atomic; append is direct |
| ssh-upload | Upload a local file over SFTP. Binary-safe, overwrite-safe by default, and staged via the strongest available remote finalize path |
| ssh-download | Download a remote file over SFTP. Binary-safe, overwrite-safe by default, and staged to a verified local finalize path |
| ssh-verify | Check if held checksums are still valid. Single-line response |
Security is not optional when agents talk to production servers. hex-ssh verifies host fingerprints, restricts host/path reachability, enforces platform-aware absolute canonical paths, times out long commands, and keeps raw remote shell access disabled by default.
Connections fail closed unless the host fingerprint matches ALLOWED_HOST_FINGERPRINTS or a matching known_hosts record. Plain, hashed, and marker-prefixed entries are parsed for fingerprint matching.
Raw shell execution starts in REMOTE_SSH_MODE=disabled. Opt into safe or open explicitly.
Comma-separated permitted hostnames/IPs. When set, connections to unlisted hosts are rejected.
ALLOWED_HOSTS=prod-web,prod-db,10.0.0.5Comma-separated permitted remote directory prefixes. File operations outside these paths are rejected.
ALLOWED_DIRS=/home/deploy,/var/wwwOptional local allowlist for ssh-upload and ssh-download. When set, transfers outside these directories are rejected.
Remote file operations require absolute paths for their platform. POSIX shell tools stay POSIX-oriented; SFTP transfers also support Windows remote paths via remotePlatform. . and .. segments are resolved before allowlist checks.
rewrite uses temp file + rename. append writes directly and is intentionally non-atomic.
Long-running SSH commands are terminated after 120 seconds instead of hanging the agent indefinitely.
EXEC_TIMEOUT after 120sssh-upload and ssh-download fail fast when the file exceeds MAX_TRANSFER_BYTES (default 128 MiB).
SFTP uploads and downloads abort with TRANSFER_TIMEOUT when transfer activity stalls longer than TRANSFER_TIMEOUT_MS.
Key-only (no passwords) — RSA, ED25519, ECDSA. Resolution order:
privateKeyPath → SSH_PRIVATE_KEY env → ~/.ssh/id_*The package currently publishes a normalization diagnostic, not a comparative workflow benchmark. Command output from remote servers is often noisy — timestamps, UUIDs, IPs change on every run. The normalization pipeline reduces this noise automatically:
| Pattern | Replacement | Example |
|---|---|---|
| UUIDs | <UUID> | 550e8400-e29b-41d4-... → <UUID> |
| Timestamps | <TS> | 2026-03-19 14:30:00 → <TS> |
| IP addresses | <IP> | 192.168.1.100:8080 → <IP> |
| Hex IDs in paths | /<ID> | /a1b2c3d4e5 → /<ID> |
| Large numbers | <N> | 1234567 → <N> |
Diagnostic command
npm run benchmark:diagnostic
| ID | Scenario | Input | Output | Savings |
|---|---|---|---|---|
| 1 | Hash annotation overhead | 3,934 ch | 4,526 ch | -15% |
| 2 | Normalize: npm install | 11,219 ch | 2,953 ch | 74% |
| 3 | Normalize: server logs | 19,715 ch | 4,470 ch | 77% |
| 4 | Dedup: grep results | 5,799 ch | 3,199 ch | 45% |
| 5 | Smart truncate: large output | 22,281 ch | 2,717 ch | 88% |
Processing pipeline
This measures normalization, deduplication, and truncation efficiency only. It is not yet a benchmark against built-in remote workflows.