MCP server for remote SSH operations -- persistent sessions, structured command execution, SFTP file transfer, and port forwarding for AI agents.
Project description
mcp-remote-ssh
MCP server for remote SSH operations. Gives AI agents persistent SSH sessions, structured command output, SFTP file transfer, and SSH port forwarding -- with native password and key-based authentication.
Why this exists
Existing SSH MCP servers each solve part of the problem but none combine all of:
- Password + key auth -- connect to any host, whether it uses passwords, SSH keys, or an agent
- Dual execution model -- one-shot
exec_command()with real exit codes and persistent interactive shells for long-running workflows - SFTP -- read, write, upload, download files properly instead of piping through a PTY
- Port forwarding -- SSH tunnels for accessing remote services (databases, web UIs, VNC, etc.)
- Structured output --
stdout,stderr, andexit_codeas separate fields, not screen scrapes
Installation
# Via uv (recommended)
uv tool install mcp-remote-ssh
# Via pip
pip install mcp-remote-ssh
# From source
git clone https://github.com/faizbawa/mcp-remote-ssh.git
cd mcp-remote-ssh
uv sync
Configuration
Cursor / Claude Desktop
Add to your MCP client configuration:
{
"mcpServers": {
"remote-ssh": {
"command": "uvx",
"args": ["mcp-remote-ssh"]
}
}
}
Or if running from source:
{
"mcpServers": {
"remote-ssh": {
"command": "uv",
"args": ["run", "--directory", "/path/to/mcp-remote-ssh", "mcp-remote-ssh"]
}
}
}
Tools (18 total)
Connection management
| Tool | Description |
|---|---|
ssh_connect |
Connect to a host (password, key, or agent auth). Returns session_id. |
ssh_list_sessions |
List all active sessions with status |
ssh_close_session |
Close a session and release all resources |
Structured execution (one-shot, clean output)
| Tool | Description |
|---|---|
ssh_execute |
Run a command, returns {stdout, stderr, exit_code} |
ssh_sudo_execute |
Run a command with sudo elevation |
Interactive shell (persistent state)
| Tool | Description |
|---|---|
ssh_shell_open |
Open a persistent interactive shell (invoke_shell) |
ssh_shell_send |
Send text to the shell (with optional Enter) |
ssh_shell_read |
Read current shell buffer (poll for output) |
ssh_shell_send_control |
Send Ctrl+C, Ctrl+D, etc. |
ssh_shell_wait |
Wait for a pattern or output to stabilize |
File transfer (SFTP)
| Tool | Description |
|---|---|
ssh_upload_file |
Upload a local file to the remote host |
ssh_download_file |
Download a remote file to local machine |
ssh_read_remote_file |
Read a text file on the remote host |
ssh_write_remote_file |
Write text to a remote file (create or append) |
ssh_list_remote_dir |
List directory contents with metadata |
Port forwarding
| Tool | Description |
|---|---|
ssh_forward_port |
Create an SSH tunnel (local port -> remote port) |
ssh_list_forwards |
List active port forwards for a session |
ssh_close_forward |
Close a specific port forward |
Quick start
# Connect with password
ssh_connect(host="myserver.example.com", username="admin", password="secret")
→ {"session_id": "a1b2c3d4", "connected": true, ...}
# Run a structured command
ssh_execute(session_id="a1b2c3d4", command="df -h /")
→ {"stdout": "Filesystem Size Used ...", "stderr": "", "exit_code": 0}
# Open a persistent shell for interactive work
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)
# Transfer files via SFTP
ssh_upload_file(session_id="a1b2c3d4", local_path="config.yaml", remote_path="/etc/app/config.yaml")
ssh_read_remote_file(session_id="a1b2c3d4", remote_path="/var/log/app.log")
# Set up an SSH tunnel
ssh_forward_port(session_id="a1b2c3d4", remote_port=5432, local_port=15432)
# Now connect to localhost:15432 to reach the remote PostgreSQL
Architecture
src/mcp_remote_ssh/
├── __init__.py # CLI entry point (click)
├── lifespan.py # FastMCP lifespan (session cleanup)
├── session.py # SSHSession, SessionStore, PortForward
└── server/
├── __init__.py # FastMCP app + tool registration
├── helpers.py # get_session, require_connected, require_shell
├── connection.py # ssh_connect, ssh_list_sessions, ssh_close_session
├── execute.py # ssh_execute, ssh_sudo_execute
├── shell.py # ssh_shell_open/send/read/control/wait
├── sftp.py # upload, download, read, write, list_dir
└── forward.py # forward_port, list_forwards, close_forward
Key design decisions
- Paramiko for SSH -- mature, pure-Python, supports password auth, SFTP, channels, and port forwarding natively
- FastMCP for MCP protocol
- Dual execution model --
exec_command()for structured one-shot commands (returns exit codes),invoke_shell()for persistent interactive sessions - Async wrappers -- all blocking Paramiko calls run in
run_in_executorto avoid blocking the event loop - Shell buffer management -- interactive shell keeps a 500KB rolling buffer for
shell_readpolling
Transport options
# stdio (default, for Cursor/Claude Desktop)
mcp-remote-ssh
# SSE
mcp-remote-ssh --transport sse --host 0.0.0.0 --port 9810
# Streamable HTTP
mcp-remote-ssh --transport streamable-http --host 0.0.0.0 --port 9810
Dependencies
| Package | Purpose |
|---|---|
| FastMCP | MCP protocol handling |
| Paramiko | SSH2 protocol (connections, channels, SFTP) |
| Click | CLI interface |
| Loguru | Logging |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_remote_ssh-0.1.0.tar.gz.
File metadata
- Download URL: mcp_remote_ssh-0.1.0.tar.gz
- Upload date:
- Size: 15.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
006758892100cb61680804c24752b51cd55ca12a271e17c03c7781a8cd23950e
|
|
| MD5 |
1afa21577687c3744dd433d29992d856
|
|
| BLAKE2b-256 |
821f7cdc1ba79efc1abfe7d1eac362b3fcc7f62d8d175b8b0ab0ecbe1b3f89e9
|
File details
Details for the file mcp_remote_ssh-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mcp_remote_ssh-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90c235c611125cac0c390756efa8134fee79f4122c2499a96b0396b8d8346479
|
|
| MD5 |
78713ba50235504e99a6abfaa9b5cdbe
|
|
| BLAKE2b-256 |
c9bcb4432a1da05b384097bd8b2ec9f60a984774dad986ace30b11e38aecf103
|