JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 212
  • Score
    100M100P100Q101025F
  • License MIT

Token-efficient SSH MCP server with hash-verified file operations. 6 tools: remote-ssh, ssh-read-lines, ssh-edit-block, ssh-search-code, ssh-write-chunk, ssh-verify.

Package Exports

  • @levnikolaevich/hex-ssh-mcp
  • @levnikolaevich/hex-ssh-mcp/server.mjs

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@levnikolaevich/hex-ssh-mcp) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

hex-ssh-mcp

Token-efficient SSH MCP server with hash-verified remote file editing.

npm License

Every remote file read returns FNV-1a hash-annotated lines and range checksums. Edits verify those checksums before applying changes -- preventing stale-context corruption across SSH boundaries. Command output is normalized and deduplicated for minimal token usage.

Features

6 MCP Tools

Tool Description Key Feature
remote-ssh Execute shell commands on remote servers Output normalization + deduplication
ssh-read-lines Read remote file with hash-annotated lines Partial reads via startLine/endLine/maxLines
ssh-edit-block Hash-verified text replacement in remote files Checksum verification + compact diff output
ssh-search-code Search remote files with grep Deduplicated results with (xN) counts
ssh-write-chunk Write or append to remote files Auto-creates parent directories
ssh-verify Check if held checksums are still valid Single-line response avoids full re-read

Output Normalization

Built into remote-ssh and ssh-search-code. Pipeline:

  1. Normalize -- replaces UUIDs, timestamps, IPs, hex IDs, large numbers with placeholders
  2. Deduplicate -- collapses identical normalized lines with (xN) counts
  3. Truncate -- keeps first 40 + last 20 lines, omits the middle

Install

claude mcp add -s user hex-ssh -e ALLOWED_HOSTS=server1,server2 -- node path/to/mcp/hex-ssh-mcp/server.mjs

Then install dependencies:

cd mcp/hex-ssh-mcp && npm install

Requires Node.js >= 18.0.0.

Security

Comma-separated list of permitted hostnames/IPs. When set, connections to unlisted hosts are rejected.

ALLOWED_HOSTS=prod-web,prod-db,10.0.0.5

When unset, all hosts are permitted.

ALLOWED_DIRS (optional)

Comma-separated list of permitted remote directory prefixes. When set, file operations outside these paths are rejected.

ALLOWED_DIRS=/home/deploy,/var/www,/etc/nginx

When unset, all remote paths are permitted.

SSH Key Authentication

Key-only authentication (no passwords). Resolution order:

  1. privateKeyPath tool parameter (explicit per-call)
  2. SSH_PRIVATE_KEY env var (path or raw key content starting with -----)
  3. Default paths: ~/.ssh/id_rsa, ~/.ssh/id_ed25519, ~/.ssh/id_ecdsa

Supported key types: RSA, ED25519, ECDSA.

Tools Reference

remote-ssh

Execute shell commands on remote servers. Output is normalized and deduplicated.

Parameter Type Required Description
host string yes Remote hostname or IP
user string yes SSH username
command string yes Shell command to execute
privateKeyPath string no Path to SSH private key
port number no SSH port (default: 22)

ssh-read-lines

Read remote file with FNV-1a hash-annotated lines and range checksums. Always prefer over remote-ssh cat -- returns edit-ready hashes.

Parameter Type Required Description
host string yes Remote hostname or IP
user string yes SSH username
filePath string yes Path to file on remote server
startLine number no Start line, 1-based (default: 1)
endLine number no End line (reads to limit if not set)
maxLines number no Max lines to read (default: 200)
plain boolean no Omit hashes, output lineNum|content instead
privateKeyPath string no Path to SSH private key
port number no SSH port (default: 22)

Output format:

File: /etc/nginx/nginx.conf (85 lines) [showing 1-50] (35 more below)

ab.1    worker_processes auto;
cd.2    error_log /var/log/nginx/error.log;
...
checksum: 1-50:f7e2a1b0

ssh-edit-block

Edit text blocks in remote files with optional hash verification. Use ssh-read-lines first to get checksums.

Parameter Type Required Description
host string yes Remote hostname or IP
user string yes SSH username
filePath string yes Path to file on remote server
oldText string yes Text to find and replace
newText string yes Replacement text
checksum string no Range checksum from ssh-read-lines (e.g. 1-50:f7e2a1b0)
expectedReplacements number no Expected occurrence count (default: 1)
privateKeyPath string no Path to SSH private key
port number no SSH port (default: 22)

Returns a compact diff of applied changes. If checksum is stale, returns an error with the current checksum.

ssh-search-code

Search remote files with grep. Results are deduplicated (identical normalized lines collapsed with (xN) counts).

Parameter Type Required Description
host string yes Remote hostname or IP
user string yes SSH username
path string yes Directory to search on remote server
pattern string yes Text or regex pattern
filePattern string no Glob filter (e.g. "*.js", "*.py")
ignoreCase boolean no Case-insensitive search (default: false)
maxResults number no Max result lines (default: 50)
contextLines number no Context lines around matches (default: 0)
privateKeyPath string no Path to SSH private key
port number no SSH port (default: 22)

ssh-write-chunk

Write content to remote files (rewrite or append). Creates parent directories. For existing files, prefer ssh-edit-block (shows diff, verifies hashes).

Parameter Type Required Description
host string yes Remote hostname or IP
user string yes SSH username
filePath string yes Path to file on remote server
content string yes Content to write
mode string no "rewrite" or "append" (default: "rewrite")
privateKeyPath string no Path to SSH private key
port number no SSH port (default: 22)

ssh-verify

Verify range checksums from prior ssh-read-lines calls without re-reading full content.

Parameter Type Required Description
host string yes Remote hostname or IP
user string yes SSH username
filePath string yes Path to file on remote server
checksums string yes JSON array of checksum strings, e.g. ["1-50:f7e2a1b0"]
privateKeyPath string no Path to SSH private key
port number no SSH port (default: 22)

Returns a single-line confirmation when all valid, or lists changed ranges with current checksums.

Output Normalization

The normalize.mjs module reduces token waste in command output. Applied automatically by remote-ssh and used internally by ssh-search-code.

Normalization Rules

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>
Trace IDs trace_id=<TRACE> trace_id=f7e2a1b0 -> trace_id=<TRACE>

Deduplication

Identical lines (after normalization) are collapsed into a single line with (xN) count, sorted by frequency descending.

Smart Truncation

Output exceeding 60 lines (40 head + 20 tail) is truncated with a gap indicator showing the number of omitted lines.

Architecture

hex-ssh-mcp/
  server.mjs          MCP server (stdio transport, 6 tools)
  package.json
  lib/
    ssh-client.mjs    SSH connection, host/path validation, key resolution
    hash.mjs          FNV-1a hashing, 2-char tags, range checksums
    normalize.mjs     Output normalization, deduplication, truncation

Relationship to hex-line-mcp

Both servers share the same FNV-1a hash format and line annotation convention (tag.lineNum\tcontent). Checksums from ssh-read-lines are structurally identical to those from hex-line's read_file.

Key differences:

Aspect hex-ssh-mcp hex-line-mcp
Target Remote servers via SSH Local filesystem
Security model ALLOWED_HOSTS + ALLOWED_DIRS (explicit allowlists for remote trust boundary) Claude Code sandbox (local trust)
Output normalization Built into remote-ssh tool Separate PostToolUse hook
Outline tool Not available (no tree-sitter on remote) AST-based via tree-sitter WASM
Hook None (hex-line hook handles reminders) Unified hook.mjs (reminder + RTK filter)
SSH library ssh2 (key-only auth) N/A (direct filesystem access)

Hash Format

ab.42    const x = calculateTotal(items);
  • ab -- 2-char FNV-1a tag derived from content (whitespace-normalized)
  • 42 -- line number (1-indexed)
  • Tab separator, then original content
  • Tag alphabet: abcdefghijklmnopqrstuvwxyz234567 (32 symbols, bitwise selection)

Range Checksums

checksum: 1-50:f7e2a1b0

FNV-1a accumulator over all line hashes in the range (little-endian byte feed). Detects changes to any line, even ones not being edited.

FAQ

Does it support password authentication?

No. Key-only authentication (RSA, ED25519, ECDSA). This is a security design decision -- passwords in agent prompts are a leak risk. Configure SSH keys via SSH_PRIVATE_KEY env var or default paths (~/.ssh/).

Can I connect to multiple servers in one session?

Yes. Each tool call specifies host and user independently. There is no persistent connection -- each call opens a new SSH session. This avoids stale connection issues but adds ~1s overhead per call.

How does output normalization differ from hex-line's RTK?

Same concept, different trigger. hex-ssh normalizes inside the remote-ssh tool itself (always active). hex-line's RTK is a PostToolUse hook that filters Bash output (only triggers above 50 lines). Both use the same normalization patterns.

What if ALLOWED_HOSTS is not set?

All hosts are permitted. Setting ALLOWED_HOSTS is recommended for production use -- it restricts which remote servers the agent can connect to, preventing lateral movement if prompts are manipulated.

License

MIT