Featured

Deploy OpenClaw in 60 seconds β€” 20% off logoDeploy OpenClaw in 60 seconds β€” 20% off

Launch OpenClaw on Hostinger in about 60 seconds and keep your agent live 24/7. Our referral link gives you 20% off, no coupon code needed.

Launch on Hostinger β†’
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed

Launch Hermes on Hostinger in one click, fully managed, no VPS knowledge needed. Use code ZACAARON10 for 10% off.

Launch on Hostinger β†’
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off

Firecrawl crawls and scrapes any site into clean markdown for your agent. Get 1,000 free credits, and new users get 10% off their first purchase.

Try Firecrawl free β†’
6,000+ web scrapers for your AI agent, start free logo6,000+ web scrapers for your AI agent, start free

Apify gives your agent live web data: 6,000+ prebuilt scrapers and actors, MCP-ready. Sign up free with $5 in usage credits.

Try Apify free β†’
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.

Context.dev gives your agents a single API to scrape, enrich, and extract live web data β€” no proxies, no parsers, no maintenance.

Start building free β†’
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams

White-glove OpenClaw for founders and exec teams (4–50+ employees): we install, harden, integrate your tools, and maintain it β€” secured from day one.

Get it set up for you β†’
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit

DataForSEO gives your agent live access to SERP results, keyword data, backlinks, and on-page SEO data through one API. New accounts get a $1 credit, good for up to 20,000 keyword or backlink lookups.

Try DataForSEO free β†’
Reach 48,000+ AI builders

A flat monthly placement in front of developers actively installing AI tools. No lock-in, cancel anytime.

Advertise here β†’

Works with

Claude CodeClaude DesktopCursorVS CodeClineCodex CLIOpenClaw+ any MCP client

Install to Claude Code

This server doesn't publish a one-line install command. Follow the setup in the source repository.

Summary

faizbawa/mcp-remote-ssh MCP server](https://glama.ai/mcp/servers/faizbawa/mcp-remote-ssh/badges/score.svg)](https://glama.ai/mcp/servers/faizbawa/mcp-remote-ssh) 🐍 🏠 🍎 πŸͺŸ 🐧 - Full SSH access for AI agents with secret-safe environment injection and...

README.md

mcp-remote-ssh

![PyPI](https://pypi.org/project/mcp-remote-ssh/) ![Python](https://pypi.org/project/mcp-remote-ssh/) ![License: MIT](https://opensource.org/licenses/MIT)

MCP server giving AI agents full SSH access -- persistent sessions, structured command output, SFTP file transfer, port forwarding, and secret-safe environment variable injection with automatic output redaction.

Why this exists

Every other SSH MCP server is missing something: no password auth, no persistent sessions, no SFTP, no port forwarding, or no structured exit codes. This one has all of them -- plus the only MCP-level secret management that prevents AI agents from ever seeing your credentials.

Secret-Safe Environment Variables

The problem: When an AI agent needs to use API tokens, passwords, or keys on a remote server, the standard approach exposes secrets in the LLM's context window. The agent either reads the secret file (now it's in the conversation) or runs echo $TOKEN and sees the value in the output.

The solution: ssh_load_env_file reads secrets from a local file on your machine, injects them into the remote SSH session, and registers them for automatic output redaction. The AI agent can use the variables freely -- every tool response is scrubbed before it reaches the LLM.

# Agent calls this -- file is read from YOUR machine, not the remote host
ssh_load_env_file(session_id="abc", file_path="~/.secrets/prod.env")
β†’ "Loaded 3 variables from local:~/.secrets/prod.env: API_TOKEN, DB_PASS, SECRET_KEY"

# Agent tries to echo the value -- redacted automatically
ssh_execute(session_id="abc", command="echo $API_TOKEN")
β†’ {"stdout": "***\n", "exit_code": 0}

# Agent dumps the environment -- all secret values scrubbed
ssh_execute(session_id="abc", command="env | grep API_TOKEN")
β†’ {"stdout": "API_TOKEN=***\n", "exit_code": 0}

# Agent reads a file containing a secret -- also redacted
ssh_read_remote_file(session_id="abc", remote_path="/etc/app/config")
β†’ "db_password=***\ndb_host=localhost\n"

# Normal commands work perfectly -- no over-redaction
ssh_execute(session_id="abc", command="uname -a")
β†’ {"stdout": "Linux server 6.1.0 ...", "exit_code": 0}

How it works

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   LLM   β”‚ ←─JSON─ β”‚   MCP Server (your machine)  β”‚ ──SSH─→ β”‚ Remote Host β”‚
β”‚ (Agent) β”‚         β”‚                              β”‚         β”‚             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚  1. Reads ~/.secrets/prod.envβ”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚  2. Parses KEY=VALUE pairs   β”‚
                    β”‚  3. Stores values in memory  β”‚
                    β”‚  4. Injects into SSH session β”‚
                    β”‚  5. Redacts ALL tool output  β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. Local file read -- the env file lives on your machine, never on the remote host
  2. Shell injection via builtins -- uses read -r VAR <<< 'value' && export VAR (no process tree exposure)
  3. Stdin-based exec injection -- ssh_execute feeds secrets via stdin to a bash wrapper, so they never appear in /proc/*/cmdline
  4. Automatic redaction -- every tool response (ssh_execute, ssh_shell_send, ssh_shell_read, ssh_read_remote_file) is scrubbed before reaching the LLM
  5. Longest-first matching -- prevents partial-match corruption (e.g., abc123 is replaced before abc)

Security properties

| Threat | Mitigated? | How | |--------|-----------|-----| | Secret in LLM context window | Yes | Output redaction replaces values with ** | | Secret in remote process tree (shell) | Yes | Shell builtins (read/export) don't fork | | Secret in remote process tree (exec) | Yes | Secrets fed via stdin, never in /proc//cmdline | | LLM tries cat on the env file | N/A | File is local-only, doesn't exist on remote | | LLM tries echo $VAR | Yes | Output is redacted | | Encoded/transformed secret (base64) | No | Only literal matches are redacted | | MITM on first SSH connection | Accepted | AutoAddPolicy used β€” see note below |

Host key policy

This server uses Paramiko's AutoAddPolicy β€” unknown host keys are accepted without prompting. This is intentional for QE/lab environments where hosts are ephemeral (Beaker, cloud instances, CI machines). The trade-off:

  • Pro: Zero-friction connections to newly provisioned machines
  • Con: Vulnerable to MITM on the very first connection to an unknown host

If you operate on untrusted networks, consider wrapping connections through a VPN or SSH bastion with pre-distributed host keys. A host_key_policy parameter may be added in a future release for strict environments.

Env file format

Standard .env format:

# Comments are ignored
API_TOKEN=your-secret-token
DB_PASSWORD="quoted values work"
SECRET_KEY='single quotes too'
export ALSO_WORKS=yes

Installation

uvx mcp-remote-ssh        # or: pip install mcp-remote-ssh

Configuration

{
  "mcpServers": {
    "remote-ssh": {
      "command": "uvx",
      "args": ["mcp-remote-ssh"]
    }
  }
}

Tools (20)

Connection

| Tool | Description | |------|-------------| | ssh_connect | Connect with password, key, or agent auth. Returns session_id | | ssh_list_sessions | List active sessions | | ssh_close_session | Close a session and release resources |

Execution

| Tool | Description | |------|-------------| | ssh_execute | Run a command, returns {stdout, stderr, exit_code} | | ssh_sudo_execute | Run with sudo elevation |

Interactive Shell

| Tool | Description | |------|-------------| | ssh_shell_open | Open persistent shell (preserves cwd, env, processes) | | ssh_shell_send | Send text (with optional Enter) | | ssh_shell_read | Read current output buffer | | ssh_shell_send_control | Send Ctrl+C, Ctrl+D, etc. | | ssh_shell_wait | Wait for a pattern or output to stabilize |

Secrets Management

| Tool | Description | |------|-------------| | ssh_load_env_file | Load secrets from a local env file; values never returned to the LLM | | ssh_clear_secrets | Clear redaction registry (values become visible again) |

SFTP

| Tool | Description | |------|-------------| | ssh_upload_file | Upload local file to remote host | | ssh_download_file | Download remote file to local machine | | ssh_read_remote_file | Read a remote text file | | ssh_write_remote_file | Write/append to a remote file | | ssh_list_remote_dir | List directory with metadata |

Port Forwarding

| Tool | Description | |------|-------------| | ssh_forward_port | Create SSH tunnel (local -> remote) | | ssh_list_forwards | List active tunnels | | ssh_close_forward | Close a tunnel |

Quick start

ssh_connect(host="server.example.com", username="admin", password="secret")
β†’ {"session_id": "a1b2c3d4", "connected": true}

ssh_load_env_file(session_id="a1b2c3d4", file_path="~/.secrets/prod.env")
β†’ "Loaded 2 variables: API_TOKEN, DB_PASS"

ssh_execute(session_id="a1b2c3d4", command="curl -H \"Authorization: Bearer $API_TOKEN\" https://api.example.com")
β†’ {"stdout": "{\"status\": \"ok\"}", "exit_code": 0}  # token used but never visible

ssh_shell_open(session_id="a1b2c3d4")
ssh_shell_send(session_id="a1b2c3d4", data="cd /opt && make -j$(nproc)")
ssh_shell_wait(session_id="a1b2c3d4", pattern="$ ", timeout=600)

ssh_upload_file(session_id="a1b2c3d4", local_path="config.yaml", remote_path="/etc/app/config.yaml")
ssh_forward_port(session_id="a1b2c3d4", remote_port=5432, local_port=15432)

Design

Built on Paramiko (SSH) + FastMCP (MCP protocol).

  • ssh_execute uses exec_command() for clean structured output with real exit codes
  • When secrets are loaded, ssh_execute feeds exports via stdin to a bash wrapper, then execs the actual command -- secrets never appear in the process tree
  • ssh_shell_* uses invoke_shell() for persistent interactive sessions
  • All blocking Paramiko calls run in run_in_executor to stay async
  • Shell keeps a 500KB rolling buffer for shell_read polling
  • Secret redaction uses longest-first string replacement across all output paths

License

MIT

See related servers & alternatives β†’

Related MCP servers

Browse all β†’

Related guides

Hand-picked reading to help you choose and use AI & ML servers.