multi-ssh-mcp

vignitin/multi-ssh-mcp

3.3

If you are the rightful owner of multi-ssh-mcp and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.

A Python-based Model Context Protocol (MCP) server for managing multiple SSH servers through a unified interface.

Tools
6
Resources
0
Prompts
0

Multi-Server SSH MCP Server

Python 3.10+ License: MIT

A Python-based Model Context Protocol (MCP) server that enables Claude to connect to and manage multiple SSH servers through a unified interface. Built with FastMCP, it provides secure, on-demand connections with comprehensive server management capabilities.

Table of Contents

Features

  • Multiple Server Support: Define unlimited SSH servers in JSON configuration
  • On-Demand Connections: Connects only when needed, one server at a time
  • Flexible Authentication: Supports both password and SSH key authentication
  • Environment Variables: Secure credential storage using environment variables
  • File Transfer: Upload and download files via SFTP
  • Command Execution: Execute commands on any configured server
  • Structured Output Parsing: Automatic JSON parsing of command outputs using JC library
  • Connection Management: Easy connect/disconnect with status tracking
  • Security First: Credentials never stored in configuration files
  • Multiple Transports: Supports both stdio (Claude Desktop) and SSE/HTTP modes
  • Docker Ready: Full containerization with Docker and Docker Compose support

Quick Start

1. Clone and Install

git clone <repository-url>
cd multi-ssh-mcp

Install dependencies (see Installation section for more options):

pip install -r requirements.txt
# or using UV (recommended)
uv sync

2. Create Configuration

Copy the example configuration and customize for your servers:

cp ssh_config_example.json servers.json
# Edit servers.json with your server details

3. Run the MCP Server

# Using default config (servers.json)
python3 multi_ssh_mcp.py

# Using UV
uv run multi_ssh_mcp.py

# With custom config
python3 multi_ssh_mcp.py --config my_servers.json

Installation

System Requirements

  • Python 3.10 or higher (or Docker)
  • SSH access to target servers
  • SSH keys or passwords for authentication

Docker Installation (Recommended)

Using Docker simplifies deployment and ensures consistent environments:

# Clone the repository
git clone <repository-url>
cd multi-ssh-mcp

# Build the Docker image
./scripts/build.sh

# Copy and configure your servers
cp ssh_config_example.json config/servers.json
# Edit config/servers.json with your server details

Local Installation

Install from requirements.txt:

pip install -r requirements.txt

Or install manually:

pip install fastmcp>=2.0.0 paramiko>=3.0.0 jc>=1.25.0

Development Dependencies

For development and testing:

pip install -e .[dev]

Usage

Command Line Options

# Use default config file (servers.json in current directory)
python3 multi_ssh_mcp.py

# Specify config file path as positional argument
python3 multi_ssh_mcp.py /path/to/my_servers.json

# Use --config flag
python3 multi_ssh_mcp.py --config /path/to/my_servers.json
python3 multi_ssh_mcp.py -c servers.json

Help

python3 multi_ssh_mcp.py --help

Configuration

1. Create Configuration File

Create your SSH servers configuration file (e.g., my_servers.json) with your server definitions. See the example configuration for the structure.

2. Authentication Methods

Password Authentication:

{
  "host": "example.com",
  "username": "user",
  "auth_method": "password",
  "password": "${ENV:SERVER_PASSWORD}"
}

SSH Key Authentication:

{
  "host": "example.com", 
  "username": "user",
  "auth_method": "key",
  "private_key_path": "~/.ssh/id_rsa",
  "key_passphrase": "${ENV:KEY_PASSPHRASE}"
}

3. Environment Variables

Set environment variables for secure credential storage (when using ${ENV:VAR_NAME} in config):

export STAGING_PASSWORD="your_staging_password"
export PROD_KEY_PASSPHRASE="your_key_passphrase"
export BACKUP_PASSWORD="your_backup_password"

Claude Desktop Integration

Configuration

Add this to your claude_desktop_config.json:

{
  "mcpServers": {
    "Multi-SSH MCP Server": {
      "command": "uv",
      "args": [
        "run",
        "--with",
        "fastmcp,paramiko",
        "python3",
        "/path/to/multi-ssh-mcp/multi_ssh_mcp.py",
        "/path/to/multi-ssh-mcp/servers.json"
      ]
    }
  }
}

Alternative Configurations

Using Python directly (if dependencies are already installed):

{
  "mcpServers": {
    "Multi-SSH MCP Server": {
      "command": "python3",
      "args": [
        "/path/to/multi-ssh-mcp/multi_ssh_mcp.py",
        "/path/to/multi-ssh-mcp/servers.json"
      ]
    }
  }
}

Using --config flag:

{
  "mcpServers": {
    "Multi-SSH MCP Server": {
      "command": "uv",
      "args": [
        "run",
        "--with",
        "fastmcp,paramiko",
        "python3",
        "/path/to/multi-ssh-mcp/multi_ssh_mcp.py",
        "--config",
        "/path/to/multi-ssh-mcp/servers.json"
      ]
    }
  }
}

Using default config location (servers.json in script directory):

{
  "mcpServers": {
    "Multi-SSH MCP Server": {
      "command": "uv",
      "args": [
        "run",
        "--with",
        "fastmcp,paramiko",
        "python3",
        "/path/to/multi-ssh-mcp/multi_ssh_mcp.py"
      ]
    }
  }
}

Note: Replace /path/to/multi-ssh-mcp/ with the actual absolute path to your cloned repository.

Docker Setup

The Multi-SSH MCP server can be run in Docker containers with support for both stdio (for Claude Desktop) and SSE/HTTP modes.

Quick Start with Docker
  1. Build the Docker image:

    ./scripts/build.sh
    
  2. Run in stdio mode (for Claude Desktop):

    ./scripts/run-docker.sh stdio
    
  3. Run in SSE/HTTP mode:

    ./scripts/run-docker.sh sse
    # Server will be available at http://localhost:8080
    
Docker Compose Options
# Run in stdio mode
docker-compose --profile stdio run --rm mcp-ssh-stdio

# Run in SSE/HTTP mode
docker-compose --profile sse up -d

# Run in development mode with hot reload
docker-compose --profile dev up
Claude Desktop Configuration for Docker

Add this to your claude_desktop_config.json:

{
  "mcpServers": {
    "Multi-SSH MCP (Docker)": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-v", "/path/to/config:/config:ro",
        "-v", "${HOME}/.ssh:/home/mcp/.ssh:ro",
        "-e", "SSH_PASSWORD_PROD",
        "-e", "SSH_PASSWORD_STAGING",
        "multi-ssh-mcp:latest"
      ]
    }
  }
}

Available Tools

ToolDescription
list_serversLists all configured SSH servers with their details
connect_serverConnects to a specific SSH server
disconnect_serverDisconnects from the current SSH server
execute_commandExecutes commands with automatic output parsing (JC library)
upload_fileUploads files via SFTP with path validation
download_fileDownloads files via SFTP with path validation
get_current_connectionShows current SSH connection status
pingSecure ping with count limits and source interface support
tracerouteTraceroute with hop control and automatic parsing
network_diagnosticsRun safe network commands (dig, nslookup, netstat, ss, ip)

Core SSH Tools

  • list_servers(): Show all configured servers
  • connect_server(server_name): Connect to a specific server
  • disconnect_server(): Close current connection
  • get_current_connection(): Check connection status

Command Execution

  • execute_command(command, server_name=None, parse_output=None): Run commands with JC parsing
    • Auto-parses common commands (ls, ps, df, netstat, etc.)
    • Optional parse_output: None (auto), True (force), False (disable)

File Transfer

  • upload_file(local_path, remote_path, server_name=None): SFTP upload
  • download_file(remote_path, local_path, server_name=None): SFTP download

Network Diagnostics

  • ping(destination, server_name=None, count=5, source_interface=None): Test connectivity
  • traceroute(destination, server_name=None, max_hops=30, source_interface=None): Trace network path
  • network_diagnostics(command_type, destination, server_name=None): Run network tools
    • Supported commands: nslookup, dig, netstat, ss, ip

Output Parsing with JC

The MCP server automatically parses command outputs into structured JSON format using the JC library. This makes it easier to analyze and process command results.

Automatic Parsing

Common commands like ls, ps, df, netstat, ifconfig, and many others are automatically parsed when executed.

Parsing Control

Use the parse_output parameter in execute_command:

  • None (default): Auto-parse supported commands
  • True: Force parsing attempt
  • False: Disable parsing, return raw output only

Example

When running df -h, instead of raw text output, you'll receive structured JSON data with fields like filesystem, size, used, available, use_percent, and mount_point.

Usage Examples

  1. List available servers:

    "Show me all configured SSH servers"
    
  2. Connect and run commands:

    "Connect to the production server and check disk usage"
    "Run 'ps aux | grep nginx' on web-server-1"
    
  3. File operations:

    "Upload my local script.sh to /tmp/ on the staging server"
    "Download the nginx config from production server"
    
  4. Multi-server workflows:

    "Check the system load on all web servers"
    "Deploy the config file to both staging and production"
    

Security Considerations

Built-in Security Features

  • Command Injection Prevention: All user inputs are sanitized and validated
  • Path Validation: File paths are checked for directory traversal attempts
  • Command Whitelisting: Only safe commands are allowed in execute_command
  • Argument Sanitization: Special characters and shell metacharacters are filtered
  • Network Input Validation: IP addresses and hostnames are validated

Best Practices

  • Store sensitive credentials in environment variables, not in the JSON config
  • Use SSH keys instead of passwords when possible
  • Limit SSH key permissions and use dedicated keys for automation
  • Keep your configuration file secure (proper file permissions)
  • Consider using SSH agent for key management

Security Restrictions

The following are blocked for security:

  • Command chaining (&&, ||, ;)
  • Shell redirections (>, <, |)
  • Command substitution ($(), ``)
  • Environment variable expansion (except for echo $VAR)
  • Directory traversal in file paths (..)

Troubleshooting

Connection Issues

  • Verify server hostnames and ports are correct
  • Check that SSH keys exist and have proper permissions (chmod 600)
  • Ensure environment variables are set correctly
  • Test SSH connections manually first: ssh user@host

Authentication Failures

  • For key auth: verify the key path and passphrase
  • For password auth: check the password in environment variables
  • Ensure the SSH server accepts the authentication method

Configuration Problems

  • Validate JSON syntax in your config file
  • Check file permissions on config and key files
  • Verify the config file path is correct

Logging

The server logs connection attempts and errors. To see detailed logs, run with:

python3 multi_ssh_mcp.py 2>&1 | tee ssh_mcp.log

Environment Variables

The MCP server supports the following environment variables:

Transport Configuration

  • MCP_TRANSPORT: Transport mode (stdio or sse, default: stdio)
  • MCP_HOST: Host for SSE mode (default: 0.0.0.0)
  • MCP_PORT: Port for SSE mode (default: 8080)
  • MCP_CONFIG_PATH: Path to servers.json file (default: servers.json)

SSH Credentials

  • SSH_PASSWORD_<SERVER_NAME>: Password for specific server
  • SSH_KEY_PASSPHRASE: Passphrase for SSH keys
  • Any custom variables referenced in your servers.json

Docker-specific

  • PYTHONUNBUFFERED: Set to 1 for immediate log output

SSE/HTTP Mode

The Multi-SSH MCP server supports Server-Sent Events (SSE) for HTTP-based communication, making it accessible from web applications and HTTP clients.

Running in SSE Mode

  1. Using Docker:

    ./scripts/run-docker.sh sse
    # or
    docker-compose --profile sse up -d
    
  2. Local Python:

    MCP_TRANSPORT=sse MCP_PORT=8080 python multi_ssh_mcp.py
    

HTTP Endpoints

When running with MCP_TRANSPORT=sse, the server provides:

  • GET /sse - Server-Sent Events stream for real-time MCP messages
  • POST /messages - Send commands to the MCP server
  • GET /health - Health check endpoint for monitoring

Client Integration

JavaScript/TypeScript Example:
// Connect to SSE endpoint
const eventSource = new EventSource('http://localhost:8080/sse');

// Handle incoming messages
eventSource.onmessage = (event) => {
    const message = JSON.parse(event.data);
    console.log('MCP Response:', message);
};

// Send MCP commands
async function sendCommand(method, params) {
    const response = await fetch('http://localhost:8080/messages', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            jsonrpc: '2.0',
            method: method,
            params: params,
            id: Date.now()
        })
    });
    return response.json();
}

// Example: List servers
sendCommand('list_servers', {});
Python Client Example:
import requests
import sseclient

# Connect to SSE stream
response = requests.get('http://localhost:8080/sse', stream=True)
client = sseclient.SSEClient(response)

# Send command
def send_command(method, params=None):
    return requests.post('http://localhost:8080/messages', json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params or {},
        'id': 1
    }).json()

# Example usage
servers = send_command('list_servers')
print(servers)

Use Cases for SSE Mode

  • Web Applications: Build web UIs for SSH management
  • Microservices: Integrate SSH operations into HTTP-based architectures
  • Monitoring Systems: Stream real-time command outputs
  • API Gateways: Expose SSH functionality through REST APIs

License

MIT License - feel free to modify and use as needed.