Skip to main content

MCP SSH Multi - Multi-server SSH access through MCP

Project description

mcp-ssh-multi

MCP server for managing multiple SSH servers through AI assistants. Provides 11 tools for remote command execution, file operations, and system monitoring.

Features

  • Multi-server management — Configure and manage multiple SSH servers from a single YAML file
  • Connection pooling — Automatic connection reuse with per-server locks and retry on stale connections
  • 11 MCP tools — Execute commands, transfer files, read/write files, tail logs, list processes
  • Two transports — stdio (for local MCP clients) and streamable-http (for web/remote)
  • Cloudflare Tunnel compatible — Deploy behind a tunnel for remote access
  • MCP tool annotations — Hints for destructive, read-only, idempotent, and open-world operations
  • MCP resourcesssh://servers resource for listing configured servers
  • Pagination — Directory listings support limit/offset for large directories
  • Input validation — Path and filter sanitization to prevent command injection
  • Structured errors — Consistent error responses with codes, messages, and suggestions

Installation

Using uv (recommended)

uv tool install mcp-ssh-multi

Using pip

pip install mcp-ssh-multi

Using uvx (one-shot)

uvx --from mcp-ssh-multi ssh-mcp

From source

git clone https://github.com/gilberth/mcp-ssh-multi.git
cd mcp-ssh-multi
uv sync

Configuration

1. SSH Servers (ssh_servers.yaml)

Create a ssh_servers.yaml file with your server definitions:

servers:
  proxmox:
    host: 192.168.1.100
    port: 22
    username: root
    key_file: ~/.ssh/id_rsa
    description: "Proxmox VE hypervisor"

  truenas:
    host: 192.168.1.101
    port: 22
    username: root
    password: "my-password"  # or use key_file
    description: "TrueNAS storage server"

2. Environment Variables (.env)

Copy .env.example to .env and customize:

cp .env.example .env
Variable Default Description
SSH_SERVERS_FILE ssh_servers.yaml Path to servers config
SSH_TIMEOUT 30 Default command timeout (seconds)
LOG_LEVEL INFO Logging level
MCP_PORT 8086 HTTP server port
MCP_SECRET_PATH /mcp HTTP endpoint path

Usage

stdio mode (local MCP clients)

ssh-mcp

Or with uvx:

uvx --from mcp-ssh-multi ssh-mcp

HTTP mode (web/remote MCP clients)

ssh-mcp-web

The server will listen on http://0.0.0.0:8086/mcp by default.

MCP Client Configuration

Add to your MCP client config (e.g., Claude Desktop):

{
  "mcpServers": {
    "ssh": {
      "command": "uvx",
      "args": ["--from", "mcp-ssh-multi", "ssh-mcp"],
      "env": {
        "SSH_SERVERS_FILE": "/path/to/ssh_servers.yaml"
      }
    }
  }
}

For HTTP mode:

{
  "mcpServers": {
    "ssh": {
      "url": "http://localhost:8086/mcp"
    }
  }
}

Tool Reference

Connection Management

Tool Description
ssh_list_servers List all configured servers with connection status
ssh_disconnect Disconnect from a specific server

Command Execution

Tool Description
ssh_execute Execute a shell command on a remote server

File Operations

Tool Description
ssh_upload Upload a local file to a remote server
ssh_download Download a file from a remote server
ssh_file_exists Check if a file/directory exists on a server
ssh_list_dir List contents of a remote directory (supports pagination with limit/offset)
ssh_read_file Read a text file from a remote server
ssh_write_file Write content to a file on a remote server

System Monitoring

Tool Description
ssh_tail_log Tail a log file on a remote server
ssh_process_list List running processes (optionally filtered)

MCP Resources

The server exposes the following MCP resources:

Resource URI Description
ssh://servers List of all configured SSH servers with connection status

Changelog

v0.2.0

  • Per-server connection locks — Replaced global lock with per-server async locks for better concurrency
  • Connection retry — Automatic single retry on stale/lost SSH connections
  • MCP tool annotations — Added destructiveHint, readOnlyHint, idempotentHint, openWorldHint to all tools
  • MCP resource — Added ssh://servers resource endpoint
  • Directory paginationssh_list_dir now supports limit and offset parameters
  • Input validation — Path sanitization for ssh_tail_log and filter validation for ssh_process_list
  • Structured errors — Consistent error format with ErrorCode enum across all tools
  • Dynamic versioning — Version sourced from importlib.metadata instead of hardcoded strings
  • Test suite — Added tests for pagination, retry logic, input validation, and version consistency

v0.1.1

  • Initial public release with 11 SSH tools, stdio and HTTP transports

Production Deployment (LXC + Cloudflare Tunnel)

Full deployment guide for running mcp-ssh-multi as a systemd service behind a Cloudflare Tunnel on a Proxmox LXC container.

Prerequisites

  • A Proxmox LXC container (Debian 12/13)
  • A Cloudflare account with a domain
  • uv and cloudflared installed on the LXC

1. Install dependencies

# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install cloudflared
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb \
  -o cloudflared.deb && dpkg -i cloudflared.deb

2. Create SSH servers config

mkdir -p /ssh-mcp
cat > /ssh-mcp/ssh_servers.yaml << 'EOF'
servers:
  my-server:
    host: 192.168.1.100
    port: 22
    username: root
    password: "my-password"  # or use key_file
    description: "My server"
EOF

3. Create the Cloudflare Tunnel

# Login to Cloudflare (opens browser)
cloudflared tunnel login

# Create the named tunnel
cloudflared tunnel create ssh-mcp

# Route DNS to your domain
cloudflared tunnel route dns ssh-mcp ssh-mcp.yourdomain.com

4. Configure the tunnel

The tunnel create command outputs the tunnel UUID (e.g. 2687c640-38df-40f9-...) and creates a credentials file at /root/.cloudflared/<TUNNEL-ID>.json. If you need to find it later, run cloudflared tunnel list.

# Replace <TUNNEL-ID> with the UUID from "cloudflared tunnel create" output
cat > /root/.cloudflared/config.yml << 'EOF'
tunnel: <TUNNEL-ID>
credentials-file: /root/.cloudflared/<TUNNEL-ID>.json

ingress:
  - hostname: ssh-mcp.yourdomain.com
    service: http://localhost:8086
  - service: http_status:404
EOF

5. Create systemd services

mcp-ssh-multi service:

cat > /etc/systemd/system/mcp-ssh-multi.service << 'EOF'
[Unit]
Description=MCP SSH Multi Server
After=network.target

[Service]
Type=simple
Environment=SSH_SERVERS_FILE=/ssh-mcp/ssh_servers.yaml
Environment=MCP_SECRET_PATH=/your-secret-path
ExecStart=/root/.local/bin/uvx --from mcp-ssh-multi@latest ssh-mcp-web
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

cloudflared service:

cloudflared service install

Enable and start both:

systemctl daemon-reload
systemctl enable --now mcp-ssh-multi
systemctl enable --now cloudflared

6. Verify

# Check services
systemctl status mcp-ssh-multi
systemctl status cloudflared

# Test the endpoint
curl -s -X POST "https://ssh-mcp.yourdomain.com/your-secret-path" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'

7. Configure your MCP client

{
  "mcpServers": {
    "ssh": {
      "type": "remote",
      "url": "https://ssh-mcp.yourdomain.com/your-secret-path"
    }
  }
}

Service management

# View logs
journalctl -u mcp-ssh-multi -f
journalctl -u cloudflared -f

# Restart services
systemctl restart mcp-ssh-multi
systemctl restart cloudflared

Environment Variables

Variable Default Description
SSH_SERVERS_FILE ssh_servers.yaml Path to servers config
SSH_TIMEOUT 30 Default command timeout (seconds)
LOG_LEVEL INFO Logging level
MCP_PORT 8086 HTTP server port
MCP_SECRET_PATH /mcp HTTP endpoint path (use a secret value)

Development

# Install with dev dependencies
uv sync --group dev

# Run linting
uv run ruff check src/ tests/ --fix
uv run ruff format src/ tests/

# Run type checking
uv run mypy src/

# Run tests
uv run pytest tests/ -v

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_ssh_multi-0.2.1.tar.gz (40.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_ssh_multi-0.2.1-py3-none-any.whl (43.8 kB view details)

Uploaded Python 3

File details

Details for the file mcp_ssh_multi-0.2.1.tar.gz.

File metadata

  • Download URL: mcp_ssh_multi-0.2.1.tar.gz
  • Upload date:
  • Size: 40.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.4

File hashes

Hashes for mcp_ssh_multi-0.2.1.tar.gz
Algorithm Hash digest
SHA256 a5b76f715c6b1307dd9e782ff8312a94071df738b56e0c977e81bafce5206242
MD5 b2716a28634a01a06c191bc4a2af3c81
BLAKE2b-256 df070f7dd0fb0786f0414bc563cfc51b3d696427ac8c3633ef076c1881a0e388

See more details on using hashes here.

File details

Details for the file mcp_ssh_multi-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for mcp_ssh_multi-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 220994d99990cb8256f1b2153835da86f8da171a11526307dc91cf1a2815fa26
MD5 8dea042cc4ef2af391ccfd45b61ab3f9
BLAKE2b-256 9046378c483241138a11d72e87a61023490c469f9f0cc97f8bb24bc34ffc3f2c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page