Skip to main content

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/config for aliases, ports, keys
  • Multi-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)
  • Command Interruption - send Ctrl+C to stop running commands
  • Thread-safe - safe for concurrent operations
  • Async Native - built-in support for asynio.

Quick Start

📦 Migrating from mcp-ssh-session

This project is a drop-in replacement for the original devnullvoid/mcp-ssh-session. To migrate:

  1. Replace the package name - mcp-ssh-session → mcp-ssh-reloaded
  2. Environment variables fully inherited - all OVRD_* and MCP_SSH_* env vars work the same
  3. That's it - reconnect and you're done
Before (old)After (new)
{
  "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-reloaded

Development

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-all

MCP 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_rsa

Then 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
OVRD_{alias}_HOST Real hostname or IP
OVRD_{alias}_PORT SSH port
OVRD_{alias}_USER SSH username
OVRD_{alias}_PASS SSH password
OVRD_{alias}_KEY Path to SSH private key
OVRD_{alias}_SUDO_PASS Sudo password
OVRD_{alias}_ENABLE_PASS 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:

  1. Constructor kwargs (highest)
  2. MCP_SSH_* environment variables
  3. Defaults (lowest)
Env Variable Default Description
MCP_SSH_DEFAULT_TIMEOUT 30 Command timeout (seconds)
MCP_SSH_MAX_TIMEOUT 300 Hard cap on timeout
MCP_SSH_CONNECT_TIMEOUT 30 SSH connect timeout
MCP_SSH_MAX_WORKERS 10 Thread pool size
MCP_SSH_MAX_FILE_BYTES 2097152 Max file read/write (2 MB)
MCP_SSH_MAX_OUTPUT_BYTES 10485760 Max command output (10 MB)
MCP_SSH_INTERACTIVE_MODE true Enable PTY terminal emulation
MCP_SSH_PTY_AWARE_VALIDATION false Relax validation for PTY inspection
MCP_SSH_MIKROTIK_AUTO_PAGING true Auto-handle MikroTik pagers
MCP_SSH_TERMINAL_WIDTH 100 PTY columns
MCP_SSH_TERMINAL_HEIGHT 24 PTY rows
MCP_SSH_LOG_DIR /tmp/mcp_ssh_session_logs Log directory
MCP_SSH_BACKGROUND_MONITOR_MAX_TIMEOUT 300 Background monitor max timeout
MCP_SSH_NORMAL_IDLE_TIMEOUT 2 Normal idle timeout (seconds)
MCP_SSH_PACKAGE_MANAGER_IDLE_TIMEOUT 10 Package manager idle timeout
MCP_SSH_ASYNC_DEFAULT_TIMEOUT 30 Async command default timeout

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 15

Via API

from mcp_ssh_reloaded import SSHService, ServerConfig

svc = SSHService(config=ServerConfig(default_timeout=60, max_timeout=600))

How It Works

Commands run inside persistent interactive shells:

  • Directory persists: cd /tmp stays in /tmp for the next command
  • Env vars persist: export FOO=bar is visible across commands
  • Prompt 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.py

test_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
API-DOCS.md Full API reference - types, SSHService methods, MCP tools, error model
docs/AGENT_GUIDE.md Agent prompt - patterns for correct tool usage, async handling
docs/ASYNC_COMMANDS.md Smart execution & async command lifecycle
docs/INTERACTIVE_MODE.md Terminal emulation, screen snapshots, key sending
docs/SAFETY_PROTECTIONS.md Limits, timeouts, session recovery, error handling
docs/DOCKER.md Running via Docker
docs/ARCHITECTURE.md Module map, execution pipeline, known gaps

License

MIT - see LICENSE.

Fork

Fork of devnullvoid/mcp-ssh-session with significant refactoring by AmritaConstant.

Metadata

Release files for mcp-ssh-reloaded 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-ssh-reloaded 0.6.0
File Size Uploaded
mcp_ssh_reloaded-0.6.0.tar.gz 108.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mcp-ssh-reloaded 0.6.0
File Interpreter ABI Platform
mcp_ssh_reloaded-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 196.3 kB

Release files / mcp_ssh_reloaded-0.6.0.tar.gz

Download URL mcp_ssh_reloaded-0.6.0.tar.gz
Size 108.7 kB
Tags Source
SHA-256 checksum
How to use checksums
7dbed9aa8aa41388c4297d362528b825cec336059f56a11cbbbaefc2698a1a72
BLAKE2b-256 checksum
How to use checksums
948f5cadf8eb2757f6c97e9998b75abcf9275d83613dac50c124c1c1c6be9050
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / mcp_ssh_reloaded-0.6.0-py3-none-any.whl

Download URL mcp_ssh_reloaded-0.6.0-py3-none-any.whl
Size 87.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d94862aec65410c6d3bba2053c475a68e05e098ef256be36e2a8f282173014a2
BLAKE2b-256 checksum
How to use checksums
9caae26f57ebb4bb87e09d02e80fb0597b57cf324be18930b57de5fbfd0f122c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page