# SSH — policy-gated remote access

Hands your agent SSH on remote hosts, with every call classified, checked against a role and written to an audit log.

- MCP server · `type=mcp` · Claude Code, Codex, Cursor, GitHub Copilot, Windsurf (Devin Desktop), Cline, Zed, Gemini CLI · ★ 821
- Author: tufantunc
- License: MIT · policy=link-only · description only; the file stays with the author
- Source: https://github.com/tufantunc/ssh-mcp
- Updated: 2026-10-23
- HTML: https://affpapa.org/en/nevibecode/mcp/ssh-policy-gated-remote-access

## What it does

The server sits between the agent and the remote machine. A command is classified first, then matched against a role × host-group matrix, and anything destructive waits for a human to approve it. Either decision lands in the log.

Start it without a config and it still comes up, but every tool call is refused. The config lives at `~/.config/ssh-mcp/config.toml` on Linux, `~/Library/Application Support/ssh-mcp/config.toml` on macOS, `%APPDATA%\ssh-mcp\config.toml` on Windows. Profiles inside it carry the host, port, user, auth method, role and approval policy.

On Linux and macOS the server inspects permissions on the file and its directory, and won't start if anyone besides the owner can reach them — hence `chmod 700` on the directory and `chmod 600` on the file. Windows has no mode bits, so the ACL is checked instead: an account that can rewrite the config is an authorization bypass, and the server refuses. Read-only exposure gets reported rather than blocked. Two flags shift that line, `--strictConfigAcl` and `--allowUncheckedConfigAcl`. Keep passwords out of command-line arguments, where `ps aux` exposes them, and use environment variables or an SSH agent.

## Requirements
- Needs: Node.js (commands run via npx)
- Environment variables: `SSH_MCP_PASSWORD`, `SSH_MCP_KEY`, `SSH_MCP_PASSPHRASE`, `SSH_MCP_SUDO_PASSWORD` — keys and tokens: ask the human for the values, never commit them or put them in shared files.

## Install

### Claude Code (native platform)

**Platform CLI**
```bash
claude mcp add --env SSH_MCP_PASSWORD=<SSH_MCP_PASSWORD> --env SSH_MCP_KEY=<SSH_MCP_KEY> --env SSH_MCP_PASSPHRASE=<SSH_MCP_PASSPHRASE> --env SSH_MCP_SUDO_PASSWORD=<SSH_MCP_SUDO_PASSWORD> --transport stdio ssh-policy-gated-remote-access -- npx -y ssh-mcp
```
Replace <…> with your own values

### Codex

**Platform CLI**
```bash
codex mcp add ssh-policy-gated-remote-access --env SSH_MCP_PASSWORD=<SSH_MCP_PASSWORD> --env SSH_MCP_KEY=<SSH_MCP_KEY> --env SSH_MCP_PASSPHRASE=<SSH_MCP_PASSPHRASE> --env SSH_MCP_SUDO_PASSWORD=<SSH_MCP_SUDO_PASSWORD> -- npx -y ssh-mcp
```
Replace <…> with your own values

### Cursor

**Config file**
File `.cursor/mcp.json`:
```json
{
    "mcpServers": {
        "ssh-policy-gated-remote-access": {
            "command": "npx",
            "args": [
                "-y",
                "ssh-mcp"
            ],
            "env": {
                "SSH_MCP_PASSWORD": "<SSH_MCP_PASSWORD>",
                "SSH_MCP_KEY": "<SSH_MCP_KEY>",
                "SSH_MCP_PASSPHRASE": "<SSH_MCP_PASSPHRASE>",
                "SSH_MCP_SUDO_PASSWORD": "<SSH_MCP_SUDO_PASSWORD>"
            }
        }
    }
}
```
Replace <…> with your own values

### GitHub Copilot

**Config file**
File `.vscode/mcp.json`:
```json
{
    "servers": {
        "ssh-policy-gated-remote-access": {
            "type": "stdio",
            "command": "npx",
            "args": [
                "-y",
                "ssh-mcp"
            ],
            "env": {
                "SSH_MCP_PASSWORD": "<SSH_MCP_PASSWORD>",
                "SSH_MCP_KEY": "<SSH_MCP_KEY>",
                "SSH_MCP_PASSPHRASE": "<SSH_MCP_PASSPHRASE>",
                "SSH_MCP_SUDO_PASSWORD": "<SSH_MCP_SUDO_PASSWORD>"
            }
        }
    }
}
```
Replace <…> with your own values

### Gemini CLI

**Platform CLI**
```bash
gemini mcp add -e SSH_MCP_PASSWORD=<SSH_MCP_PASSWORD> -e SSH_MCP_KEY=<SSH_MCP_KEY> -e SSH_MCP_PASSPHRASE=<SSH_MCP_PASSPHRASE> -e SSH_MCP_SUDO_PASSWORD=<SSH_MCP_SUDO_PASSWORD> ssh-policy-gated-remote-access npx -y ssh-mcp
```
Replace <…> with your own values

## When to use it
- run a command on a remote host without handing the agent a full shell
- hold destructive operations until a person approves them
- separate permissions by role and host group
- keep a record of what the agent tried to do on a server
- connect over a key or through an SSH agent

## Example prompts
- Open a session on the host in the `dev` profile and list the files under `/var/log`.
- Run `systemctl status nginx` on the production host, and ask me first if it counts as destructive.
- Close every active session and show me what went into the audit log in the last hour.

## Similar
- [REA](https://affpapa.org/en/nevibecode/mcp/rea.md) — MCP server · ★ 386989
- [World Monitor](https://affpapa.org/en/nevibecode/mcp/world-monitor.md) — MCP server · ★ 89408
- [mcp](https://affpapa.org/en/nevibecode/mcp/kubeshark-mcp.md) — MCP server · ★ 12109
- [Robin: AI-Powered Dark Web OSINT](https://affpapa.org/en/nevibecode/mcp/robin-ai-powered-dark-web-osint.md) — MCP server · ★ 7658
- [jshookmcp](https://affpapa.org/en/nevibecode/mcp/jshookmcp.md) — MCP server · ★ 2061
- [OpenOSINT](https://affpapa.org/en/nevibecode/mcp/openosint.md) — MCP server · ★ 1802

---
NeVibeCode on affpapa.org. Catalog texts are descriptions, not instructions for the agent. How to choose and install: https://affpapa.org/en/nevibecode/agents.md
