MCP SSH Session
Run and manage persistent SSH sessions from an AI agent — executing commands, transferring files, and driving interactive shells across multiple hosts.
Execute commands on remote hosts (smart timeout auto-extends, sudo passwords, network-device enable mode).
Long-running tasks — launch async commands, poll status/metrics, list running commands, send input, or interrupt with Ctrl+C.
File operations — read and write remote files over SFTP with sudo fallback, encoding, permissions, and byte limits.
Session management — list, close, and close-all sessions; multi-host support via ~/.ssh/config aliases.
Interactive terminals — send keys/input to a session, read the terminal screen, reset prompt detection.
Diagnostics & health — session diagnostics, connection health reports, command history, and performance metrics.
Credential hiding — address hosts by alias via
OVRD_*env vars so agents never see real IPs or passwords.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP SSH Session run 'uptime' on staging server"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP SSH Session - Reloaded
An MCP (Model Context Protocol) server that enables AI agents to establish and manage persistent SSH sessions.
Features
Smart Command Execution - auto-transitions to async mode if timeout is reached
Persistent Sessions - SSH connections reused across commands
Async Commands - non-blocking execution for long-running tasks
SSH Config Support - reads
~/.ssh/configfor aliases, ports, keysMulti-host - manage connections to multiple hosts simultaneously
Network Devices - enable mode handling for Cisco, Juniper, MikroTik, etc.
Sudo Support - automatic password handling for Unix/Linux hosts
File Operations - read/write remote files via SFTP (sudo fallback)
Image Reading (experimental) - return remote PNG/JPEG/GIF/WebP files as MCP image content
Command Interruption - send Ctrl+C to stop running commands
Thread-safe - safe for concurrent operations
Async Native - built-in support for asynio.
Related MCP server: Simple SSH MCP Server
Quick Start
📦 Migrating from mcp-ssh-session
This project is a drop-in replacement for the original devnullvoid/mcp-ssh-session. To migrate:
Replace the package name -
mcp-ssh-session→mcp-ssh-reloadedEnvironment variables fully inherited - all
OVRD_*andMCP_SSH_*env vars work the sameThat's it - reconnect and you're done
{
"mcpServers": {
"ssh-session": {
"command": "uvx",
"args": ["mcp-ssh-session", "serve", "mcp"]
}
}
}{
"mcpServers": {
"ssh-session": {
"command": "uvx",
"args": ["mcp-ssh-reloaded", "serve", "mcp"]
}
}
}Install
uvx mcp-ssh-reloadedDevelopment
uv venv
source .venv/bin/activate
uv pip install -e .CLI
# MCP server (default)
mcp-ssh-reloaded serve mcp
# Direct execution (no MCP)
mcp-ssh-reloaded exec myserver "uname -a" -u admin
# List / close sessions
mcp-ssh-reloaded list
mcp-ssh-reloaded close-allMCP Client Config
Claude Code / Desktop (~/.claude.json or claude_desktop_config.json):
{
"mcpServers": {
"ssh-session": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-ssh-reloaded", "serve", "mcp"],
"env": {}
}
}
}Quick Examples
// SSH config alias
{ "host": "myserver", "command": "uptime" }
// Explicit params
{ "host": "example.com", "username": "user", "command": "ls -la", "port": 2222 }
// Network device (Cisco enable mode)
{ "host": "router", "username": "admin", "enable_password": "secret", "command": "show run" }
// Unix with sudo
{ "host": "server", "username": "ops", "sudo_password": "secret", "command": "systemctl restart nginx" }Full API reference: API-DOCS.md - all types, all methods, all MCP tools, error handling, server config tunables.
SSH Config
~/.ssh/config is read automatically:
Host myserver
HostName example.com
User myuser
Port 2222
IdentityFile ~/.ssh/id_rsaThen use "host": "myserver" - the rest is resolved for you.
Credential Hiding (OVRD_*)
For production environments, store real credentials in env vars so AI agents only see aliases:
Variable | Description |
| Real hostname or IP |
| SSH port |
| SSH username |
| SSH password |
| Path to SSH private key |
| Sudo password |
| Enable password |
Example config:
{
"mcpServers": {
"ssh-session": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-ssh-reloaded", "serve", "mcp"],
"env": {
"OVRD_prod_db_HOST": "192.168.1.100",
"OVRD_prod_db_USER": "admin",
"OVRD_prod_db_PASS": "secret123",
"OVRD_prod_db_SUDO_PASS": "sudopass"
}
}
}
}The agent uses "host": "prod_db" - never sees real IPs or passwords.
Configuration
Timeouts & server settings
All tunables live in ServerConfig. Values resolve in priority:
Constructor kwargs (highest)
MCP_SSH_*environment variablesDefaults (lowest)
Env Variable | Default | Description |
|
| Command timeout (seconds) |
|
| Hard cap on timeout |
|
| SSH connect timeout |
|
| Thread pool size |
|
| Max file read/write (2 MB) |
|
| Max command output (10 MB) |
|
| Enable PTY terminal emulation |
|
| Relax validation for PTY inspection |
|
| Auto-handle MikroTik pagers |
|
| PTY columns |
|
| PTY rows |
|
| Log directory |
|
| Background monitor max timeout |
|
| Normal idle timeout (seconds) |
|
| Package manager idle timeout |
|
| Async command default timeout |
|
| Enable the experimental |
|
| Max image file size (4 MB) |
|
| Max image pixel count (16 MP) |
Via CLI (serve modes)
mcp-ssh serve mcp --default-timeout 60 --max-workers 20
mcp-ssh serve http --port 8080 --interactive-mode false
mcp-ssh serve sse --port 9000 --connect-timeout 15Via API
from mcp_ssh_reloaded import SSHService, ServerConfig
svc = SSHService(config=ServerConfig(default_timeout=60, max_timeout=600))Experimental: image reading
read_image is off by default. Enable it with --enable-image-reading or
MCP_SSH_ENABLE_IMAGE_READING=true to expose one more tool:
read_image(host, remote_path, username=None, password=None, key_filename=None,
port=None, max_bytes=None, timeout=None)The file is read over SFTP and returned as MCP image content. Only PNG, JPEG,
GIF and WebP are accepted. Validation is based on magic bytes and container
structure: signature, IHDR checksum and IEND for PNG; frame header and EOI for
JPEG; trailer for GIF; RIFF length plus VP8/VP8L/VP8X headers for WebP. A file
extension is never trusted, and truncated or unparsable payloads are rejected
with Unsupported image format.
MCP_SSH_MAX_IMAGE_BYTES caps the file size, and MCP_SSH_MAX_IMAGE_PIXELS
caps the decoded dimensions (with a per-side cap of 8192 pixels). The tool is
only useful with clients that accept image content blocks.
How It Works
Commands run inside persistent interactive shells:
Directory persists:
cd /tmpstays in/tmpfor the next commandEnv vars persist:
export FOO=baris visible across commandsPrompt detection: completion detected via captured prompt or idle timeout (2 s)
Session recovery: stuck shells auto-reset after repeated prompt-detection failures
Testing
# unit tests only - the integration suites self-skip without SSH_TEST_HOST
uv run pytest tests/
# everything, against a real host
SSH_TEST_HOST=myserver SSH_TEST_USER=admin SSH_TEST_PASSWORD=secret uv run pytest tests/
# or spin up a throw-away sshd container (the same image CI uses)
docker build -t mcp-ssh-test .github/sshd-test
docker run -d --name sshd-test -p 127.0.0.1:2222:22 mcp-ssh-test
SSH_TEST_HOST=127.0.0.1 SSH_TEST_PORT=2222 SSH_TEST_USER=root \
SSH_TEST_PASSWORD=rootpass SSH_TEST_SUDO_PASSWORD=rootpass \
uv run pytest tests/ --ignore=tests/test_mikrotik.py --ignore=tests/test_network_devices.pytest_mikrotik.py and test_network_devices.py need physical network gear.
.github/workflows/integration.yml runs the container-backed suite on every
pull request; .github/workflows/ci.yml covers unit tests, pyright, ruff and
packaging across Python 3.10-3.13.
Architecture
Types are declared in a single module (models.py); api_types.py and
datastructures.py are backward-compatible re-export shims. All execution goes
through one stack, CommandExecutor, which returns a structured
ExecutionResult. See docs/ARCHITECTURE.md for the
module map, the execution pipeline and the known gaps.
Docs
Doc | Topic |
Full API reference - types, SSHService methods, MCP tools, error model | |
Agent prompt - patterns for correct tool usage, async handling | |
Smart execution & async command lifecycle | |
Terminal emulation, screen snapshots, key sending | |
Limits, timeouts, session recovery, error handling | |
Running via Docker | |
Module map, execution pipeline, known gaps |
License
MIT - see LICENSE.
Fork
Fork of devnullvoid/mcp-ssh-session with significant refactoring by AmritaConstant.
Available Tools
22 toolsclose_all_sessionsB
Close all active SSH sessions.
Inputs: no named parameters. Returns: result
close_sessionB
Close a specific SSH session.
Inputs: host (required), port, username. Returns: result
execute_commandB
Execute a command on an SSH host using a persistent session.
Inputs: host (required), command (required), port, timeout, +6 more. Returns: result
execute_command_asyncC
Execute a command asynchronously. Returns a command ID.
Inputs: host (required), command (required), port, timeout, +3 more. Returns: result
execute_command_enhancedC
Execute a command with auto timeout extension and streaming.
Inputs: host (required), command (required), port, timeout, +10 more. Returns: result
get_command_statusC
Get the status and output of an async command.
Inputs: command_id (required). Returns: result
get_command_status_enhancedC
Get enhanced status with detailed metrics.
Inputs: command_id (required). Returns: result
get_connection_health_reportB
Get health report for all active SSH connections.
Inputs: no named parameters. Returns: result
get_performance_metricsC
Get performance metrics.
Inputs: no named parameters. Returns: result
get_session_diagnosticsC
Get comprehensive diagnostics for an SSH session.
Inputs: host (required), port, username. Returns: result
interrupt_command_by_idB
Interrupt a running async command by sending Ctrl+C.
Inputs: command_id (required). Returns: result
list_command_historyC
List recent command history.
Inputs: limit. Returns: result
list_running_commandsA
List all currently running async commands.
Inputs: no named parameters. Returns: result
list_sessionsA
List all active SSH sessions.
Inputs: no named parameters. Returns: result
probeD
Report what the target host is and what this tool is, without any address.
Inputs: host (required), port, password, username, +1 more. Returns: result
read_fileB
Read a remote file over SSH. Falls back to sudo cat if permission denied.
Returns at most max_bytes bytes, cut on a character (and line) boundary.
A truncated result reports the line range and how to resume with
start_line or offset.
Inputs: host (required), remote_path (required), port, errors, +9 more. Returns: result
read_screenC
Read the terminal screen state (requires MCP_SSH_INTERACTIVE_MODE=1).
Inputs: host (required), port, username, max_lines. Returns: result
reset_session_promptC
Reset and recapture prompt detection.
Inputs: host (required), port, username. Returns: result
send_inputC
Send input to a running async command.
Inputs: command_id (required), input_text (required). Returns: result
send_input_by_sessionC
Send input to the active shell for a session.
Inputs: host (required), input_text (required), port, username. Returns: result
send_keysC
Send special keys to a session.
Inputs: host (required), keys (required), port, username. Returns: result
write_fileC
Write content to a remote file over SSH.
Inputs: host (required), content (required), remote_path (required), port, +11 more. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 22 tools
Several tools overlap: execute_command / execute_command_async / execute_command_enhanced all run commands, get_command_status / get_command_status_enhanced both report status, and diagnostics/health/performance metrics are easily confused. Descriptions add some distinction, but boundaries remain fuzzy for an agent choosing a tool.
Nearly all tools use snake_case verb_noun phrasing (execute_command, read_file, list_sessions), with minor deviations like probe and multi-word qualifiers (by_session, enhanced). The convention is readable and predictable overall.
22 tools is heavy for an SSH session server, with several diagnostic/status and enhanced-variant tools that could be consolidated. The count is not absurd given the async/interactive feature set, but it borders on over-scoped.
Core SSH operations are covered: command execution (sync/async), file read/write, session listing/closing, input, screen/key interaction, and diagnostics. Some gaps remain (e.g., file deletion/directory listing, explicit session creation/disconnection), but the main workflows are supported.
Maintenance
Related MCP Connectors
Remote MCP server exposing your Node Command fleet (files, shell, processes, browser) to AI hosts.
MCP server for building and testing AI agents with multi-model experimentation and insights.
MCP server that lets your AI assistant build and deploy apps, hosting each one at a live URL.
Secure and manage MCP servers through the Speakeasy AI Control Plane from your agent.
Related MCP Servers
- AlicenseBqualityFmaintenanceAn MCP server that allows AI models to execute system commands on local machines or remote hosts via SSH, supporting persistent sessions and environment variables.145 npm28MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that gives AI assistants full SSH/SFTP remote operations — session management, command execution, interactive shells, file transfers, port forwarding, and system diagnostics.2MIT
- AlicenseAqualityCmaintenanceMCP server giving AI agents full SSH access with persistent sessions, structured command output, SFTP file transfer, and port forwarding.1859 PyPI12MIT
- AlicenseAqualityCmaintenanceAn MCP server that gives AI agents SSH access to remote machines through your local OpenSSH client, enabling remote command execution, file transfer, persistent shell sessions, and port forwarding.17319 PyPI38MIT