ssh-mcp-server

Runs shell commands and moves files on remote machines over SSH, with command allow and deny lists

By Junki (individual) TypeScript Local · stdio, Streamable HTTP DevOps and monitoringFiles and storage

75 popularity score ★ 1.0k ↓ 4.1k/wk

Connect your client

Local (once it is running)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

Claude CodeTerminal
claude mcp add --transport http ssh http://127.0.0.1:3000/mcp --header 'Authorization: Bearer <SSH_MCP_HTTP_TOKEN>'
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "ssh": {
      "url": "http://127.0.0.1:3000/mcp",
      "headers": {
        "Authorization": "Bearer <SSH_MCP_HTTP_TOKEN>"
      }
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "ssh": {
      "type": "http",
      "url": "http://127.0.0.1:3000/mcp",
      "headers": {
        "Authorization": "Bearer <SSH_MCP_HTTP_TOKEN>"
      }
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.ssh]
url = "http://127.0.0.1:3000/mcp"
http_headers = { "Authorization" = "Bearer <SSH_MCP_HTTP_TOKEN>" }
Gemini CLITerminal
gemini mcp add --scope user --transport http --header 'Authorization: Bearer <SSH_MCP_HTTP_TOKEN>' ssh http://127.0.0.1:3000/mcp
Local (npm)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

Claude CodeTerminal
claude mcp add ssh -- npx -y @fangjunjie/ssh-mcp-server --host '<HOST>' --port 22 --username '<USERNAME>' --password '<PASSWORD>'
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": [
        "-y",
        "@fangjunjie/ssh-mcp-server",
        "--host",
        "<HOST>",
        "--port",
        "22",
        "--username",
        "<USERNAME>",
        "--password",
        "<PASSWORD>"
      ]
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": [
        "-y",
        "@fangjunjie/ssh-mcp-server",
        "--host",
        "<HOST>",
        "--port",
        "22",
        "--username",
        "<USERNAME>",
        "--password",
        "<PASSWORD>"
      ]
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "ssh": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "@fangjunjie/ssh-mcp-server",
        "--host",
        "<HOST>",
        "--port",
        "22",
        "--username",
        "<USERNAME>",
        "--password",
        "<PASSWORD>"
      ]
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.ssh]
command = "npx"
args = ["-y", "@fangjunjie/ssh-mcp-server", "--host", "<HOST>", "--port", "22", "--username", "<USERNAME>", "--password", "<PASSWORD>"]
Gemini CLITerminal
gemini mcp add --scope user ssh npx -- -y @fangjunjie/ssh-mcp-server --host '<HOST>' --port 22 --username '<USERNAME>' --password '<PASSWORD>'

Settings 3

Set together: 2fa
SSH_MCP_2FA_CODE secret Optional: Verification code answered to keyboard-interactive 2FA prompts when --try-keyboard is set. For --try-keyboard.
SSH_MCP_HTTP_TOKEN secret Optional: Bearer token the HTTP endpoint requires. Used only with --mcp-transport http, and --http-token wins when both are set. For --mcp-transport http.
SSH_MCP_PASSPHRASE secret Optional: Passphrase for the private key when --passphrase is not given.

What it does

ssh-mcp-server is a local Node.js process that holds SSH connections to one or more remote hosts and exposes them to an MCP client. The assistant can run a command on a host and get its output, start long tasks as background jobs and poll them, read or write remote text files, and copy files or whole directories in either direction over SFTP. The SSH password or key stays in the server's own configuration and is never passed to the model.

Connections are set with command-line flags, a JSON config file, or host aliases from ~/.ssh/config; several hosts can be registered under names and picked per call with connectionName. It can tunnel through a SOCKS5, HTTP or HTTPS proxy, answer keyboard-interactive 2FA prompts, wrap every command in a template such as `sudo bash -c <quotedCommand>`, and switch to a persistent shell session (`--transport-mode shell`) for bastion hosts and network devices that refuse plain exec.

By default it talks to the client over stdio. With `--mcp-transport http` the same process serves Streamable HTTP at http://127.0.0.1:3000/mcp, and `--http-host`, `--http-port` and `--http-path` move it. In the source, each HTTP request gets a fresh MCP server with no session id, while the SSH connections are shared across requests.

The README's tool table groups the four job tools in one row, but src/tools/index.ts registers 10 tools in all. A non-zero exit comes back as the output plus `[exit code] N` rather than as an error. Captured output is capped at 10 MiB per command by default (`maxOutputBytes`).

What it needs

RuntimeNode.js
Runs onmacOS, Windows, Linux
SSHYour own instanceAn SSH account on each target host, reached by password, private key, SSH agent or a ~/.ssh/config alias

Node.js with npx on the machine running the client (package.json sets no minimum version). An SSH account on each target host, reached with a password, a private key (optionally with a passphrase, also read from SSH_MCP_PASSPHRASE), an SSH agent, or a ~/.ssh/config alias. Background jobs need a POSIX sh on the remote host. For 2FA, the code goes in the SSH_MCP_2FA_CODE environment variable before connecting. For HTTP mode, start the process yourself with `--mcp-transport http` plus the SSH flags, set SSH_MCP_HTTP_TOKEN first, and point the client at the URL with an `Authorization: Bearer` header.

Limits

  • Not covered In shell transport mode, upload, download, read-file and write-file are unavailable because SFTP is not used
  • Limit Commands time out after 30000 ms by default. A per-call timeout or commandTimeoutMs changes it, and longer work should go through job-start
  • Size cap Captured command output is capped at 10 MiB by default (maxOutputBytes)
  • Size cap read-file returns 65536 bytes per call by default and refuses binary files
  • Size cap Directory uploads and downloads stop at 2000 files per call and skip symlinks
  • Limit Blacklist and whitelist patterns are case-sensitive regular expressions
  • Limit The legacy comma-separated --ssh format can break on passwords containing =, comma, { or }. Use the JSON form or a config file
  • Limit HTTP mode is stateless: no MCP session id is issued, so each request is handled by a new MCP server instance
  • Rate limit Its own security notes say there is no built-in rate limiting

In shell transport mode, upload, download, read-file and write-file are unavailable because SFTP is not used. Commands time out after 30000 ms by default (per-call `timeout` or `commandTimeoutMs` changes it); longer work should go through job-start. read-file returns 65536 bytes per call by default and refuses binary files. Directory transfers stop at 2000 files per call and skip symlinks. Blacklist patterns are case-sensitive regular expressions. The legacy comma-separated --ssh format can break on passwords containing `=`, `,`, `{` or `}`. Its own docs note there is no built-in rate limiting.

Who it suits

Suits developers and operators who want an assistant to inspect or administer servers they already reach over SSH, including through jump hosts, proxies or 2FA, from a local MCP client. It runs on your machine with your SSH credentials and can change anything that account can, so it fits best with a whitelist and allowedRemotePaths set, or with a low-privilege account. Someone who only needs files on the local machine, or a cloud provider's own management API, should look for a server built for that instead.

Tools 10

4 only read, 2 change things, 4 can delete or overwrite. A ? marks an optional parameter.

execute-command deletes
Run a command on a remote host and return its output, with a non-zero exit shown as [exit code] NcmdString: stringdirectory?: stringconnectionName?: stringtimeout?: number
job-start deletes
Start a command in the background on the host and return a job idcmdString: stringdirectory?: stringconnectionName?: string
job-status
Report a background job's state, exit code and output, pageable by byte offsetjobId: stringoffset?: integertailBytes?: integermaxBytes?: integerconnectionName?: string
job-kill changes
Stop a background job and its child processes with SIGTERM, then SIGKILL after 5 sjobId: stringconnectionName?: string
job-list
List recent background jobs with their state. Finished jobs are pruned after 7 dayslimit?: integerconnectionName?: string
upload deletes
Copy a local file or directory to the remote host over SFTPlocalPath: stringremotePath: stringconnectionName?: string
download changes
Copy a remote file or directory to the local machine over SFTPremotePath: stringlocalPath: stringconnectionName?: string
read-file
Read a byte range of a remote text file over SFTPremotePath: stringoffset?: integerlength?: integerconnectionName?: string
write-file deletes
Overwrite or append to a remote text file over SFTP without shell quotingremotePath: stringcontent: stringappend?: booleanmode?: integerconnectionName?: string
list-servers
List the SSH connections the server has configured

Similar servers