Persistent, stateful remote SSH sessions for AI agents via MCP. Keep cwd, env & shell state across commands — powered by your local OpenSSH. Works with Claude, Cursor & any MCP host.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
claude mcp add remote-ssh-mcp -- npx -y @zyluo/remote-ssh-mcp{
"mcpServers": {
"remote-ssh-mcp": {
"command": "npx",
"args": ["-y", "@zyluo/remote-ssh-mcp"]
}
}
}MCP Servers overview
<p align="center">
<img src="docs/assets/logo.jpg" alt="Remote SSH MCP logo" width="120" height="120" />
</p>
<h1 align="center">Remote SSH MCP</h1>
<p align="center">
<strong>Persistent, stateful remote Bash sessions for AI agents</strong><br />
via the <a href="https://modelcontextprotocol.io">Model Context Protocol</a>
</p>
<p align="center">
<a href="#why-remote-ssh-mcp">Why</a> ·
<a href="#features">Features</a> ·
<a href="#how-it-works">How it works</a> ·
<a href="#mcp-tools">Tools</a> ·
<a href="#quick-start">Quick start</a> ·
<a href="#configuration">Config</a> ·
<a href="#security">Security</a> ·
<a href="./README.zh-CN.md">简体中文</a>
</p>
<p align="center">
<a href="https://github.com/the-nine-nation/remote-ssh-mcp/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="MIT License" /></a>
<a href="https://nodejs.org/"><img src="https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg?style=flat-square" alt="Node.js 20+" /></a>
<a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-5.x-3178C6.svg?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" /></a>
<a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-stdio-8B5CF6.svg?style=flat-square" alt="MCP stdio" /></a>
<a href="https://www.openssh.com/"><img src="https://img.shields.io/badge/OpenSSH-native-1ABC9C.svg?style=flat-square" alt="OpenSSH" /></a>
<img src="https://img.shields.io/badge/version-0.2.1-informational.svg?style=flat-square" alt="Version 0.2.1" />
<a href="https://github.com/the-nine-nation/remote-ssh-mcp/releases/tag/v0.2.1"><img src="https://img.shields.io/github/v/release/the-nine-nation/remote-ssh-mcp?style=flat-square&label=release" alt="GitHub release" /></a>
<a href="https://www.npmjs.com/package/@zyluo/remote-ssh-mcp"><img src="https://img.shields.io/npm/v/%40zyluo%2Fremote-ssh-mcp?style=flat-square" alt="npm version" /></a>
<a href="https://github.com/the-nine-nation/remote-ssh-mcp/stargazers"><img src="https://img.shields.io/github/stars/the-nine-nation/remote-ssh-mcp?style=flat-square" alt="GitHub stars" /></a>
</p>
<p align="center">
<img src="docs/assets/banner.jpg" alt="Remote SSH MCP — AI agent terminal connected to remote servers over SSH" width="100%" />
</p>
---
## Why Remote SSH MCP?
Most agents reach remote machines like this:
```text
bash → ssh host "cmd" → disconnect → repeat
```
Every call pays the same tax:
| Pain | What happens |
|------|----------------|
| 🔁 **Token waste** | Banners, MOTD, login noise, and `pwd` / `whoami` probes flood the context |
| 🧊 **Lost state** | `cwd`, `export`, venv activation, and shell side effects vanish |
| 🔌 **Unstable** | Fresh connects hit timeouts, host-key prompts, ProxyJump, and auth jitter |
| 🌀 **Error spiral** | The model compensates with longer probe commands → more tokens |
**Remote SSH MCP** turns a long-lived remote Bash into first-class MCP tools. One session ID keeps working directory, environment variables, and shell side effects. Open a new session when you need a clean environment.
### Why pick this over one-shot `ssh` in bash?
Concrete gains for agent workflows (multi-step remote work: deploy, debug, build, inspect logs):
| Dimension | One-shot `ssh host "…"` | **Remote SSH MCP** |
|-----------|-------------------------|---------------------|
| 💰 **Tokens** | Each step re-pays connect noise + state probes; models often re-`cd` / re-`pwd` | **Pay once** on `ssh_open`; later `ssh_run` returns mostly **command output**. Structured tools + head/tail caps cut tool-result bloat. In multi-step sessions this commonly **cuts remote-tool context by ~50–80%** vs reconnect-every-time (exact savings depend on MOTD size and how chatty the model is). |
| ✅ **Success rate** | *N* steps ≈ *N* handshakes → *N* chances to fail (timeout, jump, agent, host key) | **One** handshake per session; subsequent commands ride a live shell. Long jobs use `running` + `ssh_peek` instead of killing the tool call and restarting. Fewer reconnects → **far fewer false “SSH failed” loops** mid-task. |
| 🧳 **Portability** | Remote needs nothing extra — but **every agent machine** reimplements the same brittle `ssh …` patterns | **Install once** on the machine that runs Claude / Cursor / Grok / etc. **Remote hosts install nothing** (no Node, no MCP daemon, no agent). Only a normal shell account + tools already required for SSH (`bash`, `base64`, `stty`, …). Keys and jump hosts stay in **local** `~/.ssh/config`. |
| 🧠 **Model ergonomics** | Model invents `ssh` strings, escapes, and recovery | Stable tools: `open → run → peek → close`. Session id is the only handle. |
| 🔐 **Trust boundary** | Easy to over-expose keys or prompt for passwords in-band | OpenSSH client only; tools never accept passwords or private-key material |
**Portability in one line:** put the MCP on your **dev box / AI host**; every server already in your SSH config is reachable — **zero package install on the remote fleet**.
```text
┌─────────────────────────┐ SSH (OpenSSH) ┌──────────────────┐
│ Your laptop / CI agent │ ───────────────────────────► │ prod / staging │
│ Claude · Cursor · Grok │ ~/.ssh/config · agent │ no MCP install │
│ + remote-ssh-mcp │ │ plain Bash OK │
└─────────────────────────┘ └──────────────────┘
```
**Token sketch (illustrative multi-step remote debug):**
```text
One-shot path (per step × 8):
ssh wrapper + banner/MOTD + pwd/whoami + re-cd + command output
→ noise dominates; context fills with reconnect junk
Session path:
ssh_open → once (handshake + READY)
ssh_run × 8 → mostly the real stdout/stderr (truncated head+tail)
→ context stays on the work product, not the transport
```
It does **not** reimplement SSH. Your system OpenSSH client stays in charge — so `~/.ssh/config`, known hosts, the SSH agent, ProxyJump routes, and hardware keys keep working exactly as they already do.
```text
ssh_hosts() → discover allowed Host aliases
ssh_open(host) → session id
ssh_run(id, command) → same cwd + env as last time
ssh_peek / ssh_interrupt → observe or recover long / stuck work
ssh_close(id) → release the shell and connection
```
---
## Features
### 🧠 Persistent remote sessions
- One **stable session ID** maps to one long-lived remote Bash
- **`cwd` and environment** survive across `ssh_run` calls
- Open a **fresh session** whenever you need a clean slate
- Multiple sessions can target the same or different hosts (up to `maxSessions`)
### 🔧 Native OpenSSH integration
- Spawns the real **`ssh` binary** — no custom crypto stack
- Honors **`~/.ssh/config`**, `Include`, agent sockets, and **ProxyJump**
- Forces **`BatchMode=yes`** and **`StrictHostKeyChecking=yes`**
- Never accepts passwords, private-key text, or arbitrary SSH option args from the model
### 📡 Long-running command friendly
- `ssh_run` waits up to `wait_sec` (default **10s**), then returns `status: "running"` while the remote command continues
- Poll with **`ssh_peek(wait_sec=...)`** long-poll instead of busy-looping
- Optional hard **`timeout_sec`** sends Ctrl-C; no automatic kill by default
- Ideal for `docker pull`, builds, downloads, and deploys that must not block the tool call forever
### 🛡️ Safety & control plane
- **Exact Host-alias allowlist** from `ssh_config` + optional config / env overrides
- Patterns with `*`, `?`, or `!` are ignored
- **Fail-closed interrupt**: if shell recovery cannot be confirmed after Ctrl-C, the session is closed
- Built-in **denylist** for a few obviously destructive patterns (not a full policy engine)
- **Idle reaping**, session caps, and a **JSONL audit log** (`0600`) with hashed commands
### 📦 Clean tool results for models
- Separate **`stdout` / `stderr`** streams
- Head-and-tail **byte truncation** with valid UTF-8 boundaries
- `ssh_hosts` returns only safe metadata: `alias`, `hostname`, `user`, `port`, `proxy_jump`
- Never leaks `IdentityFile`, certificates, agent sockets, or `ProxyCommand`
### 🔌 MCP-native
- **stdio** transport for Claude Desktop, Cursor, and other MCP hosts
- Compatible with both legacy and current MCP handshakes
- Parent / stdio exit closes every tracked SSH connection
---
## How it works
```mermaid
flowchart LR
A[AI Agent] -->|MCP tools| B[Remote SSH MCP]
B -->|spawn| C[OpenSSH client]
C -->|SSH + PTY| D[Remote Bash]
D --> E[(cwd / env / side effects)]
subgraph Local machine
B
C
F[~/.ssh/config<br/>agent / keys]
C -.-> F
end
subgraph Remote host
D
E
end
```
**Typical agent flow**
```text
1. ssh_hosts() # pick an alias from the allowlist
2. ssh_open(host="prod") # get session id "s_…"
3. ssh_run(id, "cd app && …") # state sticks to this id
4. ssh_run(id, "npm test") # still in app/, env preserved
5. ssh_peek(id, wait_sec=20) # long-poll a slow job
6. ssh_close(id) # clean up when done
```
---
## MCP tools
| Tool | What it does |
|------|----------------|
| 🗂️ **`ssh_hosts`** | List allowed Host aliases (safe metadata only). Pass `reload=true` after editing `~/.ssh/config` |
| 🔓 **`ssh_open`** | Open a clean persistent shell for an allowed Host alias → returns session `id` |
| ▶️ **`ssh_run`** | Run a non-interactive command in an existing session |
| 👀 **`ssh_peek`** | Latest N lines of output + status; optional `wait_sec` long-polls while running |
| ⛔ **`ssh_interrupt`** | Send Ctrl-C and wait for confirmed shell recovery |
| 📋 **`ssh_list`** | List sessions, cwd, state, idle countdown, and capacity |
| 🔒 **`ssh_close`** | Tear down remote temp state and close the connection |
### Tool parameters (essentials)
| Tool | Key params |
|------|------------|
| `ssh_open` | `host` (required Host alias), optional `name` label |
| `ssWhat people ask about remote-ssh-mcp
What is the-nine-nation/remote-ssh-mcp?
+
the-nine-nation/remote-ssh-mcp is mcp servers for the Claude AI ecosystem. Persistent, stateful remote SSH sessions for AI agents via MCP. Keep cwd, env & shell state across commands — powered by your local OpenSSH. Works with Claude, Cursor & any MCP host. It has 1 GitHub stars and its last recorded update is dated 2026-08-06.
How do I install remote-ssh-mcp?
+
You can install remote-ssh-mcp by cloning the repository (https://github.com/the-nine-nation/remote-ssh-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is the-nine-nation/remote-ssh-mcp safe to use?
+
Our security agent has analyzed the-nine-nation/remote-ssh-mcp and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains the-nine-nation/remote-ssh-mcp?
+
the-nine-nation/remote-ssh-mcp is maintained by the-nine-nation. The last recorded GitHub activity is dated 2026-08-06, with 0 open issues.
Are there alternatives to remote-ssh-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy remote-ssh-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/the-nine-nation-remote-ssh-mcp)<a href="https://claudewave.com/repo/the-nine-nation-remote-ssh-mcp"><img src="https://claudewave.com/api/badge/the-nine-nation-remote-ssh-mcp" alt="Featured on ClaudeWave: the-nine-nation/remote-ssh-mcp" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!