MCP SSH Server

Maxim11111/mcp-ssh
2 starsMITCommunity

Install to Claude Code

This server doesn't publish a one-line install command. Follow the setup in the source repository.

Summary

A centralized MCP server that enables LLM agents to securely execute commands and manage Linux servers via SSH.

README.md

MCP SSH Server

Remote SSH Management Server for LLM Agents

A centralized MCP (Model Context Protocol) server that enables LLM agents (Cursor AI, Claude Desktop, Codex, etc.) to securely execute commands and manage Linux servers via SSH.

![License: MIT](https://opensource.org/licenses/MIT) ![Python 3.10+](https://www.python.org/downloads/)

Features

  • 🔐 Secure SSH Access - Key-based authentication with automatic setup
  • 🌐 Official MCP SDK - Streamable HTTP (modelcontextprotocol/python-sdk)
  • 🔏 MCP OAuth (RFC 9728) - Protected resource metadata + browser login for Claude Code; same API tokens as Bearer
  • 🔄 Real-time Streaming - Live stdout/stderr streaming via SSE
  • 🔑 Token-based Auth - Bearer tokens with granular permissions
  • 🛡️ Security First - Command validation, rate limiting, audit logging
  • 📊 Multi-server Support - Manage hundreds of servers from one endpoint
  • 🚀 Production Ready - Docker support, health checks, graceful shutdown
  • 🛠️ CLI Management - Easy server/token management via CLI tool

Quick Start

Using Docker (Recommended)

# Clone repository
git clone https://github.com/Maxim11111/mcp-ssh.git
cd mcp-ssh

# Copy example configs
cp config/servers.json.example config/servers.json
cp config/tokens.json.example config/tokens.json

# Copy environment configuration
cp env.example .env

# Edit .env file to customize settings (optional)
# nano .env

# Start with Docker Compose
docker-compose up -d

# Quick view servers list
docker exec -it mcp-ssh-server python -m src.cli server list

# Add your first server
docker exec -it mcp-ssh-server python -m src.cli server add

# Check status
docker-compose logs -f mcp-ssh-server

Local Installation

# Install dependencies
pip install -r requirements.txt

# Setup configuration
mkdir -p config keys logs
cp config/servers.json.example config/servers.json
cp config/tokens.json.example config/tokens.json

# Add server
python -m src.cli server add

# Start server (factory loads env each process)
uvicorn src.server_http:create_app --factory --host 0.0.0.0 --port 8000

Architecture

[Cursor / Claude Code / Codex / …]
         ↓
  HTTPS → Streamable HTTP POST /mcp (Bearer or OAuth access token)
         ↓
  [MCP SSH Server] → SSH Keys → [Your Linux Servers]
         ↓
  Audit Logs + Security Validation

Set PUBLIC_BASE_URL in .env to the URL clients use (e.g. https://mcp.example.com behind TLS). The SDK publishes OAuth discovery at /.well-known/oauth-protected-resource/mcp and authorization server metadata at /.well-known/oauth-authorization-server. Browser login for MCP OAuth is at /login (paste the same API token you would put in Authorization: Bearer).

Client configuration (quick reference)

| Client | Config | Notes | |--------|--------|--------| | Cursor | ~/.cursor/mcp.json | url + headers.Authorization: Bearer tok_… | | Claude Code | claude mcp add … or project config | Use HTTP transport URL ending in /mcp; complete Authenticate with token from cli token create, or pre-supply Bearer if the client supports it | | OpenAI Codex | ~/.codex/config.toml or .codex/config.toml | [mcp_servers.name] with url = "https://host/mcp" and bearer_token_env_var = "MCP_SSH_TOKEN" (or http_headers) — see Codex MCP | | Google Gemini CLI | gemini mcp add … | HTTP URL ending in /mcp; -s user = user-level config; Bearer via --header "Authorization: Bearer tok_…" or OAuth with /mcp auth <name> | | Stdio | process env | MCP_TOKEN=tok_… and python -m src.server_stdio |

Usage Examples

With Cursor AI

Add to ~/.cursor/mcp.json:

{
  "mcpServers": {
    "ssh-devops": {
      "url": "http://your-server:8000/mcp",
      "headers": {
        "Authorization": "Bearer tok_your_token_here"
      }
    }
  }
}

Then in Cursor chat:

You: Install nginx on prod-web-01
AI: Executing command on prod-web-01...
✓ nginx installed successfully

With Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "ssh-devops": {
      "url": "http://your-server:8000/mcp",
      "headers": {
        "Authorization": "Bearer tok_your_token_here"
      }
    }
  }
}

With Claude Code (CLI)

After the server is reachable at PUBLIC_BASE_URL (HTTPS in production):

claude mcp add --transport http ssh-devops https://your-server.example.com/mcp

Use Authenticate in /mcp when prompted: open /login, paste the API token from python -m src.cli token create. The issued access token is the same string as your Bearer token.

With Google Gemini CLI

Add a streamable HTTP server (user-wide config under ~/.gemini/):

gemini mcp add devops https://your-server.example.com/mcp --transport http -s user

If you use a Bearer token instead of the browser OAuth flow, pass it when adding the server:

gemini mcp add devops https://your-server.example.com/mcp --transport http -s user \
  --header "Authorization: Bearer tok_your_token_here"

With MCP OAuth, add the server first, then in the interactive CLI run /mcp auth devops (browser redirect to http://localhost:7777/oauth/callback).

With OpenAI Codex (config.toml)

[mcp_servers.ssh_devops]
url = "https://your-server.example.com/mcp"
bearer_token_env_var = "MCP_SSH_TOKEN"

Then export MCP_SSH_TOKEN=tok_... before running Codex.

Stdio (local)

export MCP_TOKEN=tok_your_token_here
export CONFIG_DIR=./config
python -m src.server_stdio

Available Tools

MCP SSH Server provides these tools to agents:

  • execute_command - Execute shell command on a server
  • execute_on_multiple - Execute command on multiple servers in parallel
  • read_file - Read file contents
  • write_file - Write/update files
  • list_directory - List directory contents
  • check_service_status - Check systemd service status
  • install_package - Install packages (apt/yum/dnf)
  • list_servers - Get available servers
  • get_system_info - Get system information

CLI Management

Server Management

# Add server with automatic SSH key setup
python -m src.cli server add

# List all servers
python -m src.cli server list

# Test connection
python -m src.cli server test prod-web-01

# Remove server
python -m src.cli server remove prod-web-01

Token Management

# Create new API token
python -m src.cli token create

# List tokens
python -m src.cli token list

# Revoke token
python -m src.cli token revoke tok_abc123

Configuration

Environment Variables (.env)

The server can be configured using environment variables. Copy env.example to .env and customize:

# Copy example configuration
cp env.example .env

# Edit configuration
nano .env

Key configuration options:

# Server Configuration
HOST=0.0.0.0                    # Server bind address
PORT=8000                       # Internal container port
EXTERNAL_PORT=8000              # External Docker host port

# Security
TOKEN_EXPIRY_HOURS=8760        # Token validity period

# Rate Limiting
RATE_LIMIT_PER_MINUTE=60       # Requests per minute
RATE_LIMIT_PER_HOUR=500        # Commands per hour

# SSH Settings
SSH_CONNECTION_TIMEOUT=30       # SSH connection timeout
SSH_COMMAND_TIMEOUT=300        # Command execution timeout

Reverse Proxy Setup

For production deployments with reverse proxy (nginx-proxy-manager, traefik, etc.):

# Use proxy compose file (recommended)
docker-compose -f docker-compose.yml -f docker-compose.proxy.yml up -d

servers.json

{
  "servers": {
    "prod-web-01": {
      "host": "192.168.1.10",
      "port": 22,
      "user": "deploy",
      "ssh_key_path": "/app/keys/prod_web_ed25519",
      "tags": ["production", "web"],
      "enabled": true,
      "description": "Production web server"
    }
  },
  "security": {
    "allowed_commands_patterns": ["^apt ", "^systemctl ", "^docker "],
    "forbidden_commands": ["rm -rf /", "mkfs"],
    "rate_limit": {
      "requests_per_minute": 60,
      "commands_per_hour": 500
    }
  }
}

tokens.json

{
  "tokens": {
    "tok_abc123...": {
      "name": "cursor-admin",
      "permissions": ["execute", "read", "write", "install"],
      "allowed_servers": ["*"],
      "rate_limit_multiplier": 1.0,
      "enabled": true
    }
  }
}

Security

Multi-layer Security

  1. Bearer Tokens - API access control
  2. SSH Keys - Server authentication (keys never leave server)
  3. Command Validation - Whitelist/blacklist patterns
  4. Rate Limiting - Per-token request limits
  5. Audit Logging - All operations logged
  6. Permission System - Granular access control

Best Practices

  • Use ED25519 SSH keys
  • Rotate tokens regularly
  • Configure allowed command patterns
  • Monitor audit logs
  • Use HTTPS in production (via nginx-proxy-manager)
  • Limit token permissions to minimum required

Testing

# Install dev dependencies
pip install -r requirements-dev.txt

# Run tests
pytest

# Run with coverage
pytest --cov=src --cov-report=html

# View coverage report
open htmlcov/index.html

See TESTING.md for detailed testing instructions.

Deployment

See DEPLOYMENT.md for production deployment guide.

Documentation

API Endpoints

The server runs HTTP JSON-RPC on a single endpoint (see MCP_PROTOCOL.md):

MCP Protocol

  • GET /mcp - Server info and available transports
  • POST /mcp - JSON-RPC (methods: initialize, tools/list, tools/call)
  • GET /sse - SSE transport (legacy)

Utility

  • GET /health - Health check

Environment Variables

All configuration can be managed via .env file. See env.example for all available options:

# Server Configuration
HOST=0.0.0.0              # Listen host
PORT=8000                 # Internal container port
EXTERNAL_PORT=8000        # External Docker host port
LOG_LEVEL=INFO            # Logging level

# Directory Configuration
CONFIG_DIR=/app/config    # Configuration directory
KEYS_DIR=/app/keys        # SSH keys directory
LOGS_DIR=/app/logs        # Logs directory

# Security Settings
TOKEN_EXPIRY_HOURS=8760   # Token validity period

# Rate Limiting
RATE_LIMIT_ENABLED=true   # Enable rate limiting
RATE_LIMIT_PER_MINUTE=60  # Requests per minute
RATE_LIMIT_PER_HOUR=500   # Commands per hour

# SSH Settings
SSH_CONNECTION_TIMEOUT=30  # SSH connection timeout
SSH_COMMAND_TIMEOUT=300   # Command execution timeout

# Development Settings
DEBUG=false               # Debug mode
RELOAD=false              # Auto-reload on changes

Requirements

  • Python 3.10+
  • Docker & Docker Compose (for containerized deployment)
  • SSH access to target servers
  • OpenSSH client

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new features
  4. Ensure all tests pass
  5. Submit a pull request

License

MIT License - see LICENSE file for details.

Support

  • GitHub Issues: Report bugs
  • Documentation: See *.md files in the repository root
  • Email: your.email@example.com

Acknowledgments

---

Made with ❤️ for the LLM DevOps community

Related MCP servers

Browse all →