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