A modular Docker container for hosting multiple MCP (Model Context Protocol) servers with remote SSH access support. Perfect for running MCP servers on any Docker-compatible system.
- Multi-Language Support: Go, Rust, Node.js, Python (with virtual environments)
- Modular Architecture: Easy to add/remove servers via JSON configuration
- Process Management: Supervisor handles all MCP servers automatically
- Remote Access: SSH + docker exec integration for Claude Desktop
- Health Monitoring: Built-in health checks and logging
- Virtual Environment Support: Python servers run in isolated environments
# Build and start the container make build make start # Check status make status # View logs make logsmcp-server-host/ ├── Dockerfile # Ubuntu 25.04 with multi-language support ├── docker-compose.yml # Container orchestration ├── Makefile # Management commands ├── entrypoint.sh # Container startup script ├── supervisord.conf # Process management configuration ├── config/ │ └── servers.json # MCP server configuration ├── scripts/ │ ├── install-servers.sh # Automated server installation │ ├── start-servers.sh # Dynamic supervisor config generation │ └── health-check.sh # Health monitoring └── README.md # This file | Server | Status | Type | Description |
|---|---|---|---|
| mcp-language-server | DISABLED | Go | LSP integration with rust-analyzer support |
| mcp-nixos | ENABLED | Python | NixOS package search and configuration |
| tailwind-svelte-assistant | ENABLED | Node.js | Tailwind CSS and SvelteKit documentation |
| context7 | ENABLED | Node.js | Up-to-date code documentation for LLMs |
- Type: Python-based NixOS package search
- Capabilities: NixOS package search, configuration assistance
- Repository: utensils/mcp-nixos
- Virtual Environment:
/app/servers/mcp-nixos/venv/ - Runtime: Python 3.13 with isolated dependencies
- Type: Node.js MCP server
- Capabilities: Tailwind CSS classes, SvelteKit documentation, component snippets
- Repository: CaullenOmdahl/Tailwind-Svelte-Assistant
- Runtime: Node.js 20 with TypeScript
- Type: Node.js MCP server via npx
- Capabilities: Real-time library documentation, code examples
- Repository: upstash/context7
- Runtime: Executed via
npx @upstash/context7-mcp - Note: For Claude Desktop/Cursor users, add a rule to auto-invoke Context7:
[[calls]] match = "when the user requests code examples, setup or configuration steps, or library/API documentation" tool = "context7"
- Type: Go-based LSP integration
- Capabilities: Rust, Go, Python, TypeScript language support via rust-analyzer
- Repository: isaacphi/mcp-language-server
- To Enable: Set
"enabled": trueinconfig/servers.json
This Docker setup is specifically designed for running MCP servers on a remote VPS and connecting to them via SSH. Unlike typical local MCP integrations, this approach:
- Centralizes all MCP servers on a single remote host
- Uses SSH + docker exec to bridge MCP communication
- Works with Claude Code, Claude Desktop, Cursor, and other MCP clients
- No local installation of individual MCP servers required
The pattern for remote MCP server access:
[Claude Code] → SSH → [VPS] → docker exec → [MCP Server in Container] Add this to your Claude Code settings to use MCP servers running on your remote VPS:
{ "mcpServers": { "nixos-search": { "command": "ssh", "args": [ "user@your-vps-ip", "docker", "exec", "mcp-server-host", "/app/servers/mcp-nixos/venv/bin/python3", "-m", "mcp_nixos.server" ] }, "tailwind-svelte": { "command": "ssh", "args": [ "user@your-vps-ip", "docker", "exec", "mcp-server-host", "node", "/app/servers/tailwind-svelte-assistant/dist/index.js" ] }, "context7": { "command": "ssh", "args": [ "user@your-vps-ip", "docker", "exec", "mcp-server-host", "npx", "-y", "@upstash/context7-mcp" ] } } }Important: Replace user@your-vps-ip with your actual VPS SSH credentials.
- SSH key authentication configured between your local machine and VPS
- Docker installed on the VPS
- User has docker permissions (user in docker group or sudo access)
- Container running via
make starton the VPS
The config/servers.json file controls which servers are active. Set "enabled" to true or false to control each server:
{ "servers": { "mcp-language-server": { "enabled": false, // Currently DISABLED "type": "go", "description": "MCP Language Server with Rust support via rust-analyzer" }, "mcp-nixos": { "enabled": true, // Currently ENABLED "type": "python", "description": "NixOS package and configuration search MCP server" }, "tailwind-svelte-assistant": { "enabled": true, // Currently ENABLED "type": "node", "description": "Tailwind CSS and SvelteKit documentation MCP server" }, "context7": { "enabled": true, // Currently ENABLED "type": "node", "description": "Up-to-date code documentation for LLMs" } } }- Edit
config/servers.json- Set"enabled"totrueorfalse - Run
make update-config- Apply changes without rebuilding - Check status - Run
make statusto verify
- Edit
config/servers.json- Add your server configuration with"enabled": true - Run
make rebuild- Rebuild container with new server - Update Claude Code config - Add SSH command for new server
- go: Go-based servers (uses
go installorgo build) - rust: Rust-based servers (uses
cargo build --release) - node: Node.js servers (uses
npm installand optionalnpm run build) - python: Python servers (creates virtual environment and uses
pip install)
- Ubuntu 25.04 with Python 3.13 support
- Multi-language toolchain: Go 1.24+, Rust (latest), Node.js 20, Python 3.13
- rust-analyzer pre-installed for Rust language support
volumes: - ./workspace:/workspace:rw # Shared workspace - ./data:/app/data:rw # Persistent data - ./logs:/var/log:rw # Log files - ./config:/app/config:ro # Configuration (read-only)# Container Operations make build # Build Docker image make start # Start container make stop # Stop container make restart # Restart container make rebuild # Clean rebuild (recommended after config changes) # Monitoring make logs # View container logs make health # Run health check make status # Show MCP server status make supervisor-logs # View supervisor logs make server-logs # View specific server logs (prompts for server name) # Development make shell # Open container shell make ssh-test # Test SSH connectivity make update-config # Update configuration without rebuild make info # Show container informationPython servers automatically get isolated virtual environments:
- Created at
/app/servers/{server-name}/venv/ - Dependencies installed via pip in the virtual environment
- Supervisor uses the venv Python binary:
/app/servers/{server-name}/venv/bin/python3
- Supervisor manages all MCP servers as background processes
- Automatic restart on failure
- Structured logging to
/var/log/mcp/ - Health monitoring and status reporting
- Container runs without special network requirements
- Accessible via
docker execcommands over SSH - No exposed ports needed for MCP communication
# View all servers make status # Check specific server logs docker exec mcp-server-host tail -n 50 /var/log/mcp/mcp-language-server.err.log docker exec mcp-server-host tail -n 50 /var/log/mcp/mcp-nixos.err.log# Test language server docker exec mcp-server-host /root/go/bin/mcp-language-server --help # Test NixOS server docker exec mcp-server-host /app/servers/mcp-nixos/venv/bin/python3 -m mcp_nixos.server --help# Restart specific server docker exec mcp-server-host supervisorctl restart mcp-mcp-nixos docker exec mcp-server-host supervisorctl restart mcp-mcp-language-server # Restart all servers docker exec mcp-server-host supervisorctl restart all# Test SSH connection ssh tim@tim-server "docker exec mcp-server-host echo 'SSH works'" # Test specific MCP server via SSH ssh tim@tim-server "docker exec mcp-server-host /root/go/bin/mcp-language-server --help"| Variable | Default | Description |
|---|---|---|
LOG_LEVEL | info | Logging level for MCP servers |
WORKSPACE_PATH | /workspace | Working directory for projects |
MCP_SERVERS_CONFIG | /app/config/servers.json | Server configuration file |
The container runs without network dependencies:
version: '3.8' services: mcp-server-host: build: . image: mcp-server-host:latest container_name: mcp-server-host restart: unless-stopped volumes: - ./workspace:/workspace:rw - ./data:/app/data:rw - ./logs:/var/log:rw - ./config:/app/config:ro environment: - LOG_LEVEL=${LOG_LEVEL:-info} - WORKSPACE_PATH=/workspace ports: - "8080:8080" # Optional: for web-based servers