settings — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited settings (Hook) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
# 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# 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[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 ValidationSet `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 | 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 |
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 successfullyAdd 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"
}
}
}
}After the server is reachable at PUBLIC_BASE_URL (HTTPS in production):
claude mcp add --transport http ssh-devops https://your-server.example.com/mcpUse 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.
Add a streamable HTTP server (user-wide config under ~/.gemini/):
gemini mcp add devops https://your-server.example.com/mcp --transport http -s userIf 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).
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.
export MCP_TOKEN=tok_your_token_here
export CONFIG_DIR=./config
python -m src.server_stdioMCP SSH Server provides these tools to agents:
# 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# 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_abc123The server can be configured using environment variables. Copy env.example to .env and customize:
# Copy example configuration
cp env.example .env
# Edit configuration
nano .envKey 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 timeoutFor 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": {
"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": {
"tok_abc123...": {
"name": "cursor-admin",
"permissions": ["execute", "read", "write", "install"],
"allowed_servers": ["*"],
"rate_limit_multiplier": 1.0,
"enabled": true
}
}
}# 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.htmlSee TESTING.md for detailed testing instructions.
See DEPLOYMENT.md for production deployment guide.
The server runs HTTP JSON-RPC on a single endpoint (see MCP_PROTOCOL.md):
GET /mcp - Server info and available transportsPOST /mcp - JSON-RPC (methods: initialize, tools/list, tools/call)GET /sse - SSE transport (legacy)GET /health - Health checkAll 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 changesContributions welcome! Please:
MIT License - see LICENSE file for details.
Made with ❤️ for the LLM DevOps community
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.