ssh-mcp-rs 3.0.2

MCP server exposing SSH control for Linux systems via Model Context Protocol
Documentation

SSH MCP Server

Rust License: MIT Protocol: MCP crates.io

Capability-bound SSH MCP for autonomous DevOps agents: composable primitives, deterministic long-running jobs, bounded context, and atomic remote edits.

ssh-mcp is a Rust Model Context Protocol server that gives an AI agent secure, narrowly-scoped control of a remote Linux host over a single persistent SSH session. It exposes five base tools plus two explicitly privileged sudo variants and is built to keep agent context small and operations deterministic.

Why

  • Capability-bound surface. Five base tools and two optional sudo variants, no open-ended remote API. The agent can only run commands, read files, patch one file, transfer files, and inspect background jobs.
  • Deterministic long-running jobs. background=true returns {job_id, pid, log_path} immediately; output streams to a local log you poll with check_process, avoiding client RPC deadlines.
  • Bounded context. read defaults to a safe preview with token estimates; shell output is capped by --max-output-tokens. Large files cannot bomb the agent's context window.
  • Atomic remote edits. apply_patch edits as the SSH user; the separately gated sudo_apply_patch preserves the same conflict detection and atomic commit under sudo.

Tools

Tool Purpose
shell Run a command via POSIX sh as the connected user; background=true for long tasks.
sudo_shell Same, under sudo (uses --sudo-password); can be disabled with --disable-sudo.
check_process Poll a background job by job_id and read the tail of its local log.
read Read a remote UTF-8 file with preview / head / tail / full modes and token estimates.
apply_patch Create, update, or delete one remote UTF-8 file with an exact patch (atomic, conflict-checked).
sudo_apply_patch Same exact patch flow under sudo; can be disabled with --disable-sudo.
transfer Move files/directories (put/get) via autorsyncsftpscpexec-raw.

Full parameter schemas are served to the client at runtime; deeper references live in Docs/.

Installation

Pre-built binaries (recommended)

Download the latest rolling release from the Releases page:

Platform Download
Linux x86_64 ssh-mcp-linux-x86_64
Windows x86_64 ssh-mcp-windows-x86_64.exe
macOS ARM64 ssh-mcp-macos-aarch64
curl -L https://github.com/0FL01/ssh-mcp-rs/releases/download/rolling/ssh-mcp-linux-x86_64 -o ssh-mcp
chmod +x ssh-mcp && sudo mv ssh-mcp /usr/local/bin/
ssh-mcp --version

Cargo (crates.io)

cargo install ssh-mcp-rs   # installs the `ssh-mcp` binary to ~/.cargo/bin

Build from source

Requires the Rust toolchain plus pkg-config and OpenSSL headers (libssl-dev on Debian/Ubuntu).

git clone https://github.com/0FL01/ssh-mcp-rs.git && cd ssh-mcp-rs
cargo build --release

Adding to MCP clients

OpenCode

Add to opencode.jsonc (SSH key recommended; password auth uses the exec-raw transfer transport):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ssh-remote": {
      "type": "local",
      "command": [
        "/absolute/path/to/ssh-mcp",
        "--host=192.168.1.10",
        "--port=22",
        "--user=agent-nc",
        "--key=/path/to/private/key"
      ],
      "enabled": true
    }
  }
}

Use --password=your-password instead of --key=... for password authentication.

Add to your project's .mcp.json (shared via git) or to ~/.claude.json under the top-level mcpServers key:

{
  "mcpServers": {
    "ssh-remote": {
      "type": "stdio",
      "command": "/absolute/path/to/ssh-mcp",
      "args": [
        "--host=192.168.1.10",
        "--port=22",
        "--user=agent-nc",
        "--key=/path/to/private/key"
      ]
    }
  }
}

Set --strict-host-key-checking=yes and point at a pre-populated known_hosts file (works in any client config):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ssh-remote": {
      "type": "local",
      "command": [
        "/absolute/path/to/ssh-mcp",
        "--host=example.com",
        "--user=alice",
        "--key=/home/alice/.ssh/id_ed25519",
        "--strict-host-key-checking=yes",
        "--known-hosts=/home/alice/.ssh/known_hosts"
      ],
      "enabled": true
    }
  }
}

Configuration

Every flag also has an SSH_MCP_* environment variable. Required: --host, --user, and one of --password / --key.

Argument Env Description
--host SSH_MCP_HOST SSH host (required)
--user SSH_MCP_USER SSH username (required)
--port SSH_MCP_PORT SSH port (default: 22)
--password SSH_MCP_PASSWORD SSH password (alternative to key)
--key SSH_MCP_KEY Path to private key file
--sudo-password SSH_MCP_SUDO_PASSWORD Password for sudo commands
--timeout SSH_MCP_TIMEOUT Command timeout in ms (default: 300000)
--max-output-tokens SSH_MCP_MAX_OUTPUT_TOKENS Shell/read output token limit (default: 16000 ≈ 64KB; none to disable)
--disable-sudo SSH_MCP_DISABLE_SUDO Disable the sudo_shell and sudo_apply_patch tools

Run ssh-mcp --help for the full list (logging, keepalive, reconnect, host-key options).

SSH host key verification

ssh-mcp verifies the server host key before authentication to prevent silent man-in-the-middle replacement:

  • accept-new (default): trust and record an unknown key on first connection; reject later changes.
  • yes: require the key to already exist in known_hosts; reject unknown or changed keys.
  • no: disable verification; only for disposable test environments.

Long-running jobs

Start potentially long commands with background=true. A foreground timeout_ms controls SSH execution only and cannot extend the MCP client's own deadline. You immediately get {job_id, pid, log_path}, where log_path is a local log on the MCP server (default /tmp/ssh-mcp/<job_id>.log). Poll with check_process:

{"job_id": "abc123", "tail_lines": 50}

check_process returns a strict state — running, completed, failed, or state_lost — plus the log tail. Sleep between checks (2–5s, then 10–30s for long jobs) rather than tight-polling; a job is done when the state is terminal and an exit_code is present.

Background tracking requires the MCP server and its SSH session to remain alive; jobs are not guaranteed to survive an MCP server restart.

Safety

  • Stdio transport. JSON-RPC over stdin/stdout — no exposed network ports.
  • Credentials in memory only. Passwords and keys are never logged.
  • Logs to stderr. Internal logging stays off the MCP protocol channel.
  • Path validation. Rejects control characters, traversal (..), and shell-injection shapes.
  • Binary protection. Text tools reject non-UTF-8 content to prevent corruption.
  • Atomic edits. Staging with automatic cleanup and conflict detection; no silent overwrites.
  • Explicit elevation. apply_patch never retries under sudo; privileged edits require an explicit sudo_apply_patch call.

Documentation

Deeper references live in Docs/:

License

MIT — see LICENSE for details.