MCP SSH Server

MCP SSH Server

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

Category
Visit Server

README

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 Python 3.10+

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

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured