| name | ssh-mcp-cli |
| version | 1.6.2 |
| description | ssh-mcp CLI — MUST USE when the user mentions SSH, ssh-mcp, remote servers, or asks to run commands on, upload/download files to, check status of, or port-forward to remote/server machines via the ssh-mcp tool. Covers exec (foreground + background jobs), SFTP transfers, connection status, jump hosts, port forwarding, and server config discovery. |
| requires | {"bins":["ssh-mcp"]} |
ssh-mcp CLI Usage Guide
Run commands, transfer files, and forward ports on user-configured SSH servers via ssh-mcp. Servers are defined in config (~/.ssh-mcp/config.json, plus optional per-project .ssh-mcp.json overlay) — never ask the user for host/credentials; discover server IDs with ssh-mcp servers.
Version Guard — read this first
This guide is version-matched to the version: in the frontmatter. Before relying on the reference, sync skill and binary — never use a mismatched copy silently:
-
Compare: ssh-mcp --version vs the frontmatter version: above.
-
If they differ, fix both directions:
- Binary newer (frontmatter < binary): the binary carries the current guide — refresh this file:
ssh-mcp skill > <skill-path>
- Binary older (frontmatter > binary): bring the binary up first:
ssh-mcp update — then refresh this file as above.
-
Locate <skill-path> — the file you loaded this skill from. Skill locations vary by agent (opencode, Claude Code, Cursor, and others each differ), so:
- If you know your agent's skills directory, refresh the copy there:
ssh-mcp skill > <skills-dir>/ssh-mcp-cli/SKILL.md
- If this file was loaded from a path you can determine (session config, skill registry), refresh that exact path
- Multiple copies on the machine (agents often mirror the same file)? Refresh them all.
- No copy locatable? Ask the user which agent/skills directory to install into — do not invent paths.
-
ssh-mcp binary missing? npm install -g ssh-mcp-cli (package name differs from the ssh-mcp bin), then refresh as above.
-
Stale copies fail safe: unknown commands/flags error loudly and every command supports --help — so verify anything suspicious against live help instead of trusting the file.
Agent Guidance
Key Principles
- Always discover first.
ssh-mcp servers --json lists available server IDs with host/user. If the user's target isn't listed, show them the list — don't invent servers.
- Use
--json for parsing. Every command supports it; human mode is for display only.
exec joins arguments with spaces (like ssh). For shell operators, pipes, or quotes, pass the command as ONE quoted string: ssh-mcp exec srv "sh -c 'exit 7'".
- Exit code = remote exit code. Non-zero means the remote command failed — check
stderr in the JSON payload, don't retry blindly.
- Long-running or silent commands: add
--stall-timeout 0 (disables the 10s no-output timeout). For commands >5min, use background jobs (below).
- Errors are structured.
server_not_found → re-run servers. connection_failed → host/port issue, surface the reason. Never print config contents (contains credentials).
Command Reference
ssh-mcp servers [--json]
ssh-mcp status <id> [--json]
ssh-mcp exec <id> <cmd...> [--json]
--timeout <sec>
--stall-timeout <sec>
--max-output <chars>
--stdin
--bg [--stall-timeout 0]
--agent-forward
ssh-mcp job list [serverId] [--json]
ssh-mcp job check <jobId> [--json]
[--max-output <chars>]
ssh-mcp job cancel <jobId>
ssh-mcp upload <id> <local> <remote>
ssh-mcp download <id> <remote> <local>
ssh-mcp jump <jumpId> <targetId> [cmd...]
ssh-mcp forward <id> <remoteHost> <remotePort>
[--local-host <iface>] [--local-port <port>]
[--via <jumpId>]
ssh-mcp rforward <id> <localHost> <localPort>
[--remote-host <iface>] [--remote-port <port>]
ssh-mcp forwards [--json]
ssh-mcp forward-close <localPort> [--local-host <iface>]
ssh-mcp rforward-close <> <remotePort> [--remote-host <iface>]
ssh-mcp update [--json]
Background Job Pattern (>5min tasks)
ssh-mcp exec build-srv "npm run build" --bg --stall-timeout 0
ssh-mcp job check job_xxx --json
ssh-mcp job check job_xxx --json | jq '.result.exitCode'
Poll every 10-30s (not in a tight loop). Jobs survive the CLI exiting; msSinceLastOutput high + status running may mean a stall.
Common Workflows
- Diagnose a server:
status → exec <id> "uptime && df -h" (chained, one string)
- Read a remote file:
ssh-mcp exec <id> "cat /var/log/app.log" --json | jq -r .stdout
- Write a remote file:
printf 'content' | ssh-mcp exec <id> "cat > /path/file" --stdin
- Deploy:
upload artifact → exec "systemctl restart x" → exec "systemctl is-active x"
- DB access:
ssh-mcp forward db-srv localhost 5432 --local-port 15432 & then connect to localhost:15432; stop with forward-close 15432
- Private network via bastion:
jump for one-shots; forward --via <jumpId> for tunnels
Config Facts
- Central:
~/.ssh-mcp/config.json (0600 enforced). Project overlay: .ssh-mcp.json walked up from CWD — servers override by id, keys/defaults merge; disabled when config is pinned.
- Auth options per server:
{ "password": "..." }, { "privateKey": "alias-or-path-or-inline-PEM" } (keys aliases may point to file paths), { "agent": true } (SSH agent; not macOS Keychain).
SSH_MCP_CONFIG=<path> env or --config <path> pin the config explicitly.
Adding a project config (.ssh-mcp.json)
When the working project needs its own servers (or different credentials than central), create .ssh-mcp.json in the repo root:
{
"servers": [
{ "id": "staging", "host": "10.0.0.9", "port": 22,
"username": "deploy", "auth": { "privateKey": "~/.ssh/staging_key" } }
]
}
Rules:
- Same schema as central; servers override central entries with the same
id, new ids are added
- Git-tracked is fine (0644 allowed; no group/other WRITE) — but if it contains passwords or inline keys, it belongs in
.gitignore (private repo + deliberate choice, otherwise)
- Prefer machine-local keys (
~/.ssh/... paths or { "agent": true }) so no secrets are committed
- Takes effect on the next command — no restart, no env vars; verify with
ssh-mcp servers
- One-shot per invocation: no cwd/env persistence between
exec calls. Chain with && in one quoted command when state matters.
- Self-updates automatically at most once/24h (background, never blocks). Opt out:
SSH_MCP_AUTO_UPDATE=0. State: ~/.ssh-mcp/update-state.json.
- No
ssh-mcp binary? npm install -g ssh-mcp-cli (package name differs from bin name).
Hard Limits
- File transfer: 100MB (
upload/download). Larger: exec with split/base64.
exec output: truncated to 10MB; use --max-output <chars> or remote-side filtering (| tail, grep).
- Forwards run in the foreground of their own process — background the shell command or use a separate terminal.