Prototype · Preview: every server in the official registry, synced every 30 minutes. Reviews and accounts come in a later step.
PopNx MCPMCP servers for people who use AI · explained in plain words

SSH — policy-gated remote access

by tufantuncversion 2.23.1i★ –iRuns on your computer
Registry nameio.github.tufantunc/ssh-mcp

Install

Overview

Description from the maker (original English)

Policy-gated, audited SSH for Linux and Windows hosts: roles, approvals, and an audit log.

PopNx MCP’s three pillars

These three are never merged into one score: opinions, measurements and popularity are different things.

What you can do with it

We have not written a plain-language summary for this one yet. Below are the facts we read from the registry.

  • Connection: Runs on your computer
  • Transport: stdio
  • Category: Developer tools
  • You need to fill in: SSH_MCP_PASSWORD, SSH_MCP_PASSPHRASE, SSH_MCP_SUDO_PASSWORD

Install

Pick the AI app you use, then copy the settings.

Before you install

  • Basic checks: 1 of 1 passed
  • Runs on your computer with your user’s permissions (files, network, apps).
  • You fill in yourself: SSH_MCP_PASSWORD, SSH_MCP_KEY, SSH_MCP_PASSPHRASE, SSH_MCP_SUDO_PASSWORD

Values marked secret are keys to your account. Never share them or paste them into a chat.

You need

  • npmNode.js installed (for the npx command)

Which app do you use?

Pick your app above. We remember it, so next time the button says “Install in …”.

Open Claude Desktop → Settings → Developer → Edit Config, and paste this into claude_desktop_config.json

{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": [
        "-y",
        "ssh-mcp"
      ],
      "env": {
        "SSH_MCP_PASSWORD": "your-value",
        "SSH_MCP_KEY": "your-value",
        "SSH_MCP_PASSPHRASE": "your-value",
        "SSH_MCP_SUDO_PASSWORD": "your-value"
      }
    }
  }
}

Run this in your terminal

claude mcp add ssh --env SSH_MCP_PASSWORD=your-value --env SSH_MCP_KEY=your-value --env SSH_MCP_PASSPHRASE=your-value --env SSH_MCP_SUDO_PASSWORD=your-value -- npx -y ssh-mcp

Fill in the empty values before running it.

Open in Cursor

Or copy the settings yourself

Paste into .cursor/mcp.json in your project, or ~/.cursor/mcp.json

{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": [
        "-y",
        "ssh-mcp"
      ],
      "env": {
        "SSH_MCP_PASSWORD": "your-value",
        "SSH_MCP_KEY": "your-value",
        "SSH_MCP_PASSPHRASE": "your-value",
        "SSH_MCP_SUDO_PASSWORD": "your-value"
      }
    }
  }
}

Your browser asks to open the app, then the app shows the settings and asks you to confirm. Key values are left empty for you to fill in.

Open in VS Code

Or copy the settings yourself

Paste into .vscode/mcp.json in your project

{
  "servers": {
    "ssh": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "ssh-mcp"
      ],
      "env": {
        "SSH_MCP_PASSWORD": "your-value",
        "SSH_MCP_KEY": "your-value",
        "SSH_MCP_PASSPHRASE": "your-value",
        "SSH_MCP_SUDO_PASSWORD": "your-value"
      }
    }
  }
}

Your browser asks to open the app, then the app shows the settings and asks you to confirm. Key values are left empty for you to fill in.

This one runs on your computer, and ChatGPT can only connect to servers on the internet. Pick another app.

Your choice stays on this device in a cookie; no account needed.

Values you fill in

  • SSH_MCP_PASSWORD secret env
    Password for the configured profile; a per-profile SSH_MCP_ _PASSWORD takes precedence. Credentials are never accepted as CLI arguments.
  • SSH_MCP_KEY env
    Path to the private key file to authenticate with — the path, not the key material. A per-profile SSH_MCP_ _KEY takes precedence.
  • SSH_MCP_PASSPHRASE secret env
    Passphrase for an encrypted private key.
  • SSH_MCP_SUDO_PASSWORD secret env
    Password the sudo tool escalates with, when the policy in force allows the privileged class.

These settings are generated from the maker’s registry entry. If the README says otherwise, follow the README.

What it can do

Runs on your computer; the tool list appears in your AI app after you install it.

Basic checksi

We check information anyone can see; we have not read the code. Checks that do not apply are left out of the count. · Checked Nov 7, 2026

  • ✓ Pass

    Maker matches the repo

    The registry name was verified with the GitHub account tufantunc, which owns the repo

  • … Not checked yet

    Still maintained

    We have not read this repo from GitHub yet

  • … Not checked yet

    Has a licence

    We have not read this repo from GitHub yet

  • – Not applicable

    Endpoint responds

    This one runs on your computer; there is no internet endpoint

  • – Not applicable

    Sign-in with OAuth

    Runs on your computer and uses local settings instead

  • … Not checked yet

    No hidden instructions in tool descriptions

    Runs on your computer; we can only read tool lists from internet endpoints

Compared with others in Developer toolsi

  • More stars than 0% of the other 4907 servers in this category
  • Published to the registry more recently than 96% of the other 4907 servers in this category
  • Basic checks equal to or better than 100% of the other 4907 servers in this category

Compared with every active server in this category in the registry. Stars count only when the publisher owns the repo.

Common questions

Is SSH — policy-gated remote access safe?

It passed 1 of 1 applicable basic checks. We have not read the code. Before adding a key or token, see what access the server asks for and use a key with only the permissions you need.

What keys or codes does it need?

You need to fill in: SSH_MCP_PASSWORD, SSH_MCP_PASSPHRASE, SSH_MCP_SUDO_PASSWORD

Does it run on my computer or in the cloud?

It runs on your computer. Your AI app starts it when needed, and data does not pass through the maker’s servers (unless it calls an online service itself).

Is it still maintained?

The GitHub repo last changed –, and the latest version (2.23.1) reached the registry yesterday.

Which apps can use it?

Apps that support MCP, such as Claude Desktop, Claude Code, Cursor and VS Code. You also need Node.js on your computer.

What can I use instead?

In the same category: GitHub, Desktop Commander, Cloudflare MCP

Alternatives

Servers in the same category from other makers, sorted by stars.

Reading a card:★ GitHub starsiThree pillars: reviews · checks · usageiUpdated = latest version published to the registryi

GitHub

by github

GitHub’s official server lets AI read and manage code, issues and pull requests in your account. Use GitHub’s hosted version or run it locally with Docker.

Computer or cloud★ 34,245MITUpdated 4 days ago
Install

Desktop Commander

by wonderwhy-er

MCP server for terminal commands, file operations, and process management

Runs on your computer★ 10,225MITUpdated 16 days ago
Install

Cloudflare MCP

by cloudflare

Cloudflare MCP servers

Runs in the cloud★ 4,446Apache-2.0Updated 14 months ago
Install

README from the maker

Open the README

Copied from the maker’s repo as written. PopNx MCP has not reviewed or endorsed it. HTML, images and scripts are removed. Links lead off this site.

SSH MCP Server v2

SSH MCP Server is a security-first Model Context Protocol server that gives LLM agents controlled SSH access to remote hosts — with command classification, policy-based authorization, human-in-the-loop approval, and full audit logging.

The risk this server exists to manage. Giving an LLM shell access on a remote host puts private data, untrusted input and network egress in one place — Simon Willison's "lethal trifecta". Prompt injection has no general fix, so ssh-mcp assumes any command may be attacker-influenced: it classifies before executing, authorizes against a role × host-group matrix, gates destructive work behind approval, and records the decision either way. That narrows the blast radius; it does not remove the risk. Two things stay yours: never point it at a root account, and never set `auto` approval on a production profile. SECURITY.md has the full threat model.


Quick Start

1. Install
npm install -g ssh-mcp
2. Configure

Without a config the server still starts, so a client or directory can complete the MCP handshake and read tools/list — but every tool call is refused until you configure it, with a message naming the path below. Nothing runs on a host until this step is done. The one exception is reload-config: write the file, then call it with action: "reload" (or restart the server) to configure a server that is already running — see Reloading.

Create the config file at the path for your platform:

PlatformPath
Linux~/.config/ssh-mcp/config.toml (or $XDG_CONFIG_HOME/ssh-mcp/config.toml)
macOS~/Library/Application Support/ssh-mcp/config.toml
Windows%APPDATA%\ssh-mcp\config.toml
[defaults]

defaultProfile = "dev" approvalMode = "ask-destructive"

[[profiles]] name = "dev" host = "192.168.1.100" port = 22 user = "deploy" # NOT root! auth = "key" keyRef = "~/.ssh/id_ed25519" role = "admin" approvalPolicy = "auto" # dev is permissive

chmod 700 ~/.config/ssh-mcp && chmod 600 ~/.config/ssh-mcp/config.toml

The config decides which hosts, roles and policy rules this server honours, so it checks that nobody but you can read it — and treats the two platforms differently, because the question has a much clearer answer on one of them.

Linux and macOS: enforced. The mode check above, on the file *and* the directory — which is why chmod 700 is in that command, since mkdir -p under the default umask leaves the directory 0755. The server refuses to start otherwise. "Only the owner" is unambiguous here and chmod is a one-line fix.

Windows: split by what the ACL actually allows. There are no mode bits, so the ACL is read instead — and read exposure and write exposure are not treated alike, because Windows is much clearer about one of them than the other.

The ACL lets another account…Default
only read the configreported, and the server starts
change the configrefused
nothing (no ACL at all)refused — that is full control for everyone
…and if the ACL could not be readrefused, except when icacls is absent or the check timed out

A config under %APPDATA% inherits access for you, SYSTEM and Administrators and needs nothing done to it. One created elsewhere does not: a file under C:\ inherits *read* for every local account and *modify* for every authenticated one. The message names the two icacls commands that fix it either way.

Read exposure is reported rather than refused because that is where Windows is genuinely muddier than POSIX, and refusing over it blocked a config at the documented location (#138). Write exposure is refused because it is not muddy at all: another account being able to rewrite the file that decides which hosts, roles and approval policy this server honours is an authorization bypass, not a disclosure.

Two flags move the whole thing: --strictConfigAcl refuses everything the check objects to, read-only grants included; --allowUncheckedConfigAcl reports everything and refuses nothing. Neither combination leaves you without an exit, which is the lesson of #138.

Exit statuses
StatusMeaning
0Clean shutdown
1A defect in the server — printed with a stack trace; please report it
2How it was invoked or configured — printed as a message, no stack

A supervisor that treats any non-zero status as a failure needs no change. One that matched on 1 to detect a startup problem should match on 2 as well.

Starting with nothing configured is not an exit-2 condition, as of the release that added introspection without a config: the server starts so it can be described, and refuses each tool call instead, except reload-config. A supervisor that used a non-zero exit to catch an unconfigured deployment should watch for starting unconfigured on stderr, or read configured from GET /health when running the HTTP transport.

3. Set credentials via environment variables
export SSH_MCP_PASSWORD="your-password"        # if using auth=password

OR use SSH agent (recommended):

export SSH_AUTH_SOCK="$SSH_AUTH_SOCK" # already set if agent running

4. Connect from your MCP client

Claude Code:

claude mcp add --transport stdio ssh-mcp -- ssh-mcp

Claude Desktop / Cursor / Windsurf:

{

"mcpServers": { "ssh-mcp": { "command": "ssh-mcp", "env": { "SSH_MCP_PASSWORD": "your-password" } } } }

Never pass passwords as CLI arguments — they're visible via ps aux. Use env vars, config files, SSH agent, or OS keychain.


Tools (15)

ToolPurposereadOnlydestructive
list-connectionsDiscover available hosts and connection status✅—
list-sessionsList active sessions per host✅—
open-sessionCreate a named interactive (stateful) or background session——
close-sessionClose a session. A background session's command is signalled (INT/TERM/KILL) before its channel is dropped—✅
read-session-outputRead output from background sessions (e.g., tail -f)✅—
read-commandExecute allowlisted read-only commands (ls, cat, grep, ...)✅—
run-commandExecute arbitrary commands (destructive/privileged need approval, unless approvalPolicy = "auto")——
privileged-commandExecute with sudo (needs approval, unless approvalPolicy = "auto")—✅
sftp-uploadUpload a file via SFTP (replaces the destination unconditionally)—✅
sftp-downloadDownload a file via SFTP✅—
sftp-listList a remote directory, bounded in entries and bytes✅—
sftp-upload-fileStream a local file to the remote host, never through model context—✅
sftp-download-fileStream a remote file to local disk, never through model context—✅
signal-processSend INT/TERM/KILL to a remote PID—✅
reload-configShow the config file's status, or re-read and apply it without a restart (see Reloading)—✅
Streaming file transfer

sftp-upload/sftp-download move file *contents* through the model's context: the text is an argument on the way out and a response on the way back. That is what you want for a config snippet and exactly what you do not want for a 200 MB tarball or anything binary.

The two also differ on what they do to an existing destination, and the approved string now says which is which. sftp-upload replaces unconditionally and spells --overwrite every time, because that is what it always does; sftp-upload-file refuses unless you pass overwrite: true, and only then carries the flag. Since sftp-upload takes its content as an argument rather than naming a local file, its string also carries --bytes= --sha256=<32 hex> — without that, two uploads to the same path are the same string, which means one approval covers both and an auditor cannot tell which set of bytes landed. The digest is 128 bits rather than a short prefix because that claim has to hold against a caller who picks both payloads, not only against an accidental repeat.

[policy].denylist patterns are tested against that whole string and, for every SFTP tool, against the remote path on its own — as given, lexically normalized, and read the way Windows reads it (see "Policy Engine"). A rule written for the path, such as authorized_keys$, therefore does not depend on where the string puts it or on how the file is spelled. A rule anchored on the *whole* string (^sftp:upload /root/.*$) still does: that layout is ours to change, so anchor on the path instead.

sftp-upload-file and sftp-download-file stream between the remote host and local disk instead. Neither the bytes nor a base64 encoding of them ever reaches the model — the response is a byte count and two paths.

The two transfer tools are off until you configure `defaults.transferRoot`, and refuse with an explanation until then. (sftp-list has no local side and needs none of this.) That directory is the whole of their local reach:

[defaults]

transferRoot = "/srv/ssh-mcp-transfers" transferMaxBytes = 268435456 # 256MB per transfer transferTimeoutMs = 300000 # 5min with no bytes moving

Checked on every call, and refused rather than degraded if any of it fails: the directory must be 0700 and owned by the account running this server, with no group- or world-writable parent, and must not overlap the ssh-mcp installation, the config directory, the audit log directory, or ~/.ssh. Caller paths are confined to it, symlinks are refused rather than followed, and a download is staged as a sibling .part file and published atomically, so a failed transfer never leaves a half-written file at the destination.

transferTimeoutMs is an idle budget, not a total one: it bounds one metadata round-trip, or one stretch of the copy with no bytes moving, and is re-armed on progress. A slow but live transfer of a large file survives it; a stalled channel still fails within one window. That is why the byte cap above does not have to be divided by it — a total budget would have made a 256MB cap mean "only if the link sustains 900 KB/s".

Not available on Windows, where the transfer root cannot yet be verified private; the two transfer tools refuse there rather than writing into a directory other accounts may be able to read.

sftp-upload-file takes an optional mode (1–511; setuid, setgid and the sticky bit are refused). Omitted, a new remote file is published 0600; an overwritten one inherits the replaced file's permission bits — its permission bits only, not its setuid or setgid.

What a transfer is authorized for includes

Only the beginning is shown; read the rest in the repo

Ask PopNx