Skip to main content
Glama
AmritaBot

MCP SSH Session

by AmritaBot
README.md
# 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`](https://github.com/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

<table>
<tr><th>Before (old)</th><th>After (new)</th></tr>
<tr><td>

```json
{
  "mcpServers": {
    "ssh-session": {
      "command": "uvx",
      "args": ["mcp-ssh-session", "serve", "mcp"]
    }
  }
}
```

</td><td>

```json
{
  "mcpServers": {
    "ssh-session": {
      "command": "uvx",
      "args": ["mcp-ssh-reloaded", "serve", "mcp"]
    }
  }
}
```

</td></tr>
</table>

### Install

```bash
uvx mcp-ssh-reloaded
```

### Development

```bash
uv venv
source .venv/bin/activate
uv pip install -e .
```

### CLI

```bash
# 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`):

```json
{
  "mcpServers": {
    "ssh-session": {
      "type": "stdio",
      "command": "uvx",
      "args": ["mcp-ssh-reloaded", "serve", "mcp"],
      "env": {}
    }
  }
}
```

### Quick Examples

```json
// 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](./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:**

```json
{
  "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)

```bash
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

```python
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

## Docs

| Doc                                                        | Topic                                                                  |
| ---------------------------------------------------------- | ---------------------------------------------------------------------- |
| [API-DOCS.md](./API-DOCS.md)                               | Full API reference - types, SSHService methods, MCP tools, error model |
| [docs/AGENT_GUIDE.md](./docs/AGENT_GUIDE.md)               | **Agent prompt** - patterns for correct tool usage, async handling     |
| [docs/ASYNC_COMMANDS.md](./docs/ASYNC_COMMANDS.md)         | Smart execution & async command lifecycle                              |
| [docs/INTERACTIVE_MODE.md](./docs/INTERACTIVE_MODE.md)     | Terminal emulation, screen snapshots, key sending                      |
| [docs/SAFETY_PROTECTIONS.md](./docs/SAFETY_PROTECTIONS.md) | Limits, timeouts, session recovery, error handling                     |
| [docs/DOCKER.md](./docs/DOCKER.md)                         | Running via Docker                                                     |

## License

MIT - see [LICENSE](./LICENSE).

## Fork

Fork of [devnullvoid/mcp-ssh-session](https://github.com/devnullvoid/mcp-ssh-session) with significant refactoring by [AmritaConstant](https://github.com/AmritaBot).

TDQS

C2.9/5.0

Scored across 20 tools

Disambiguation4/5

Most tools have distinct purposes, but there is some overlap between execute_command_async and execute_command_enhanced, and between send_input, send_input_by_session, and send_keys. The descriptions help differentiate them.

Naming Consistency4/5

The naming follows a consistent verb_noun pattern in snake_case (e.g., close_session, execute_command_async), but minor inconsistencies exist like 'close_all_sessions' vs 'close_session' and 'send_keys' breaking the verb_noun pattern.

Tool Count4/5

20 tools is on the higher side but appropriate for the server's scope, covering session management, command execution, file operations, and diagnostics. Each tool serves a clear purpose.

Completeness3/5

The tool set covers core SSH session management and file read/write, but lacks file deletion, directory listing, and an explicit session creation tool (sessions may be implicit). The command execution variants are redundant, leaving minor gaps.

Maintenance

ActivityNo data
ResponsivenessNo issues