Remote MCP Proxy
About
A Docker-based proxy to access local MCP servers through Claude's web UI using the Remote MCP protocol.
Details
- Author
- pezzos
- Categories
- Cloud Service, Infrastructure, Other, Developer Tools
Jump to
Setup
Install Remote MCP Proxy in your MCP client (Claude Desktop, Cursor, Windsurf, and others).
Repository: https://github.com/pezzos/remote-mcp-proxy
Follow the installation instructions in the repository README, then restart your MCP client.
Seamlessly use your favorite MCP servers anywhere. This project packages a small Go proxy that lets you connect local or experimental MCP servers to Claude.ai and the mobile app. Even if a server isn't officially "remote" yet, this proxy exposes it over Claude's new Remote MCP protocol so you can start integrating immediately.
Existing MCP servers often run only on your desktop, making them impossible to use with Claude's web UI or phone app. The Remote MCP protocol solves this, but not every server supports it yet. This proxy fills that gap so you can experiment right away.
- Launches and monitors your local MCP servers automatically
- Converts traffic between HTTP/SSE and standard MCP JSON-RPC
- Hosts several MCP servers at once under different URL paths
- Reuses the familiarclaude_desktop_config.jsonformat
- Shuts down cleanly and cleans up any spawned processes
- Exposes a/healthendpoint so you can check status at a glance
This proxy now featuresautomatic subdomain routing generationfrom yourconfig.jsonfile. Simply define your MCP servers in JSON, and the system automatically creates Traefik routing rules for each server.
# 1. Define servers echo '{"mcpServers":{"memory":{"command":"npx","args":["-y","@modelcontextprotocol/server-memory"]}}}' > config.json # 2. Set domain echo "DOMAIN=yourdomain.com" > .env # 3. Deploy make install-deps && make up # 4. Use in Claude.ai # → https://memory.mcp.yourdomain.com/sse
- ✅Dynamic Subdomain Routing: Each server gets{server}.mcp.{domain}/sse
- ✅Automatic Traefik Integration: Routes generated automatically
- ✅Easy Scaling: Add servers by editing JSON only
- ✅Production Ready: Proper SSL, load balancing, service discovery
Create aconfig.jsonfile describing your MCP servers (same format asclaude_desktop_config.json):
{ "mcpServers": { "notion-mcp": { "command": "npx", "args": ["-y", "@anthropic-ai/mcp-server-notion"], "env": { "NOTION_TOKEN": "your_notion_token_here" } }, "memory-mcp": { "command": "python", "args": ["-m", "memory_mcp"], "env": {} } } }
Option A: Automated Make Workflow (Recommended)
# Install dependencies (first time only) make install-deps # Set your domain echo "DOMAIN=yourdomain.com" > .env # Generate configuration and deploy make up # View logs make logs
# Build the image docker build -t remote-mcp-proxy . # Run the proxy docker run -d \ --name mcp-proxy \ -p 8080:8080 \ -v $(pwd)/config.json:/app/config.json:ro \ remote-mcp-proxy
The compose setup expects/home/pezzos/docker/config/secrets/remote_mcp_proxy.env. The file is symlinked into this directory as.env.
cd /home/pezzos/docker/config cp secrets/remote_mcp_proxy.env secrets/remote_mcp_proxy.env.example # optional backup ${EDITOR:-nano} secrets/remote_mcp_proxy.env
DOMAIN=proxy.example.com LOG_LEVEL_SYSTEM=INFO LOG_LEVEL_MCP=DEBUG LOG_RETENTION_SYSTEM=24h LOG_RETENTION_MCP=12h
This will deploy the service with Traefik reverse proxy integration, making it accessible atmcp.{DOMAIN}with automatic HTTPS.
Configure wildcard DNS for dynamic subdomain routing:
Type: A Name: .mcp Content: YOUR_SERVER_IP Proxy status: Proxied (orange cloud)
For other DNS providers, create an A record:
Open Claude.ai (requires Pro, Max, Teams, or Enterprise plan) and add yourautomatically generatedproxy URLs under Settings > Integrations:
Auto-Generated URLs(based on your config.json):
- https://notion-mcp.mcp.your-domain.com/sse
- https://memory-mcp.mcp.your-domain.com/sse
- https://sequential-thinking.mcp.your-domain.com/sse
✅Claude.ai Integration Status: The Connect button now works reliably! The proxy fully supports Claude.ai Remote MCP integration with proper session management and tool discovery.
{ "mcpServers": { "existing-server": {...}, "new-server": { "command": "python", "args": ["/path/to/server.py"] } } }
- New URL:https://new-server.mcp.your-domain.com/sse
- Automatically configured SSL, routing, load balancing
Debug Endpoints: Use these endpoints to verify your MCP servers are working:
- Check server status:https://mcp.your-domain.com/listmcp
- Verify tools available:https://mcp.your-domain.com/listtools/your-server-name
Auto-Generated Format: Each MCP server is automatically available at:
- https://memory.mcp.your-domain.com/sse
- https://sequential-thinking.mcp.your-domain.com/sse
- https://notion.mcp.your-domain.com/sse
Where{DOMAIN}is set in your.envfile and{server-name}matches the key in yourconfig.jsonfile.
Claude.ai expects Remote MCP endpoints at root level (/sse), not path-based routing. This automated subdomain approach:
- ✅ Matches Remote MCP standard format
- ✅ Auto-scales with config.json changes
- ✅ Provides clean separation between servers
- ✅ Eliminates manual Traefik configuration
- ✅ Enables instant deployment of new servers
The proxy uses the same configuration format as Claude Desktop'sclaude_desktop_config.json:
{ "mcpServers": { "server-name": { "command": "command-to-run", "args": ["arg1", "arg2"], "env": { "ENV_VAR": "value" } } } }
The following environment variables are used by the Docker Compose setup:
- DOMAIN: Your base domain name (e.g.,example.com). MCP servers will be accessible at{server}.mcp.{DOMAIN}
- Set environment variables for your MCP servers in theenvsection ofconfig.json
- Store secrets securely and reference them in your Docker deployment
- The proxy will pass these environment variables to the spawned MCP processes
The service is configured to work with Traefik reverse proxy for automatic HTTPS andwildcard subdomainrouting:
version: '3.8' services: remote-mcp-proxy: build: . container_name: remote-mcp-proxy restart: unless-stopped volumes: - ./config.json:/app/config.json:ro environment: - GO_ENV=production networks: - proxy labels: # Wildcard subdomain routing for dynamic MCP servers - traefik.enable=true - traefik.http.routers.mcp-wildcard.rule=Host(.mcp.${DOMAIN}) - traefik.http.routers.mcp-wildcard.entrypoints=websecure - traefik.http.routers.mcp-wildcard.tls=true - traefik.http.routers.mcp-wildcard.tls.certresolver=letsencrypt - traefik.http.services.mcp-wildcard.loadbalancer.server.port=8080 # Utility endpoints on main domain - traefik.http.routers.mcp-main.rule=Host(mcp.${DOMAIN}) - traefik.http.routers.mcp-main.entrypoints=websecure - traefik.http.routers.mcp-main.tls=true - traefik.http.routers.mcp-main.tls.certresolver=letsencrypt - traefik.http.services.mcp-main.loadbalancer.server.port=8080 networks: proxy: external: true
- Wildcard Rule:Host(\.mcp.${DOMAIN})captures all subdomains likememory.mcp.domain.com
- Dynamic SSL: Traefik automatically generates SSL certificates for new subdomains
- Main Domain:mcp.${DOMAIN}for utility endpoints (/health,/listmcp)
- DNS Requirement: Wildcard DNS record.mcp.domain.commust be configured
- Docker and Docker Compose installed
- Domain name with DNS control
- Traefik reverse proxy running (or willingness to set it up)
# Clone the repository git clone <repository-url> cd remote-mcp-proxy # Create environment configuration echo "DOMAIN=your-domain.com" > .env
Editconfig.jsonwith your desired MCP servers:
{ "mcpServers": { "memory": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-memory"] }, "sequential-thinking": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-sequential-thinking"] }, "notion": { "command": "npx", "args": ["-y", "@anthropic-ai/mcp-server-notion"], "env": { "NOTION_TOKEN": "your_notion_token_here" } } } }
- Go to DNS settings for your domain
- Add new record:
- Type: A
- Name:.mcp
- Content: Your server's IP address
- Proxy status: Proxied (orange cloud)
For other DNS providers:Create a wildcard A record:.mcp.your-domain.com → YOUR_SERVER_IP
4. Set Up Traefik (If Not Already Running)
version: '3.8' services: traefik: image: traefik:v3.0 container_name: traefik restart: unless-stopped ports: - "80:80" - "443:443" networks: - proxy volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik.yml:/traefik.yml:ro - ./acme.json:/acme.json environment: - CF_API_EMAIL=your-email@example.com # If using Cloudflare - CF_API_KEY=your-cloudflare-api-key # If using Cloudflare networks: proxy: external: true
global: checkNewVersion: false entryPoints: web: address: ":80" websecure: address: ":443" providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false certificatesResolvers: letsencrypt: acme: email: your-email@example.com storage: acme.json dnsChallenge: # Recommended for wildcard certificates provider: cloudflare delayBeforeCheck: 0
# Create proxy network (if not exists) docker network create proxy # Start Traefik (if not running) cd traefik && docker-compose up -d && cd .. # Deploy MCP Proxy docker-compose up -d
# Check if services are running docker-compose ps # Test main endpoints curl -s https://mcp.your-domain.com/health curl -s https://mcp.your-domain.com/listmcp # Test individual MCP server subdomains curl -s https://memory.mcp.your-domain.com/health curl -s https://sequential-thinking.mcp.your-domain.com/health
- Open Claude.ai (requires Pro/Team/Enterprise plan)
- Go to Settings → Integrations
- Click "Add More" → "Custom Integration"
- Add your MCP server URLs:
- https://memory.mcp.your-domain.com/sse
- https://sequential-thinking.mcp.your-domain.com/sse
- https://notion.mcp.your-domain.com/sse
# Test DNS resolution nslookup memory.mcp.your-domain.com dig *.mcp.your-domain.com # Should resolve to your server IP
# Check Traefik logs docker logs traefik # Check certificate generation docker exec traefik cat /acme.json
# Check proxy logs docker logs remote-mcp-proxy # Test individual server tools curl -s https://mcp.your-domain.com/listtools/memory
- Verify URL format:https://server.mcp.domain.com/sse
- Check authentication (if required)
- Ensure DNS and SSL are working
- Test with browser first
- DOMAIN: Your base domain (required)
- MCP_DOMAIN: Override domain for MCP routing (optional)
- PORT: HTTP server port (default: 8080)
# View current servers jq '.mcpServers | keys' config.json # Generate and view routing configuration make generate cat docker-compose.yml # View logs for all services make logs # Quick restart after config changes make restart # Add new MCP server workflow: # 1. Edit config.json - add new server # 2. Run: make restart # 3. New URL automatically available: https://newserver.mcp.domain.com/sse # 4. All SSL, routing, service discovery handled automatically # Update to latest version docker-compose pull && make up
config.json → gomplate → docker-compose.yml → Traefik → Claude.ai ↓ ↓ ↓ ↓ ↓ Servers Templates Container Labels SSL Routes Integration
- config.json: Define MCP servers (single source of truth)
- gomplate: Template engine generates docker-compose.yml
- Traefik Labels: Each server gets automatic routing rules
- SSL: Automatic certificate generation for subdomains
- Claude.ai: Ready-to-use URLs with zero manual configuration
remote-mcp-proxy/ ├── config.json # ← MCP server definitions (edit this) ├── .env # ← Domain configuration ├── docker-compose.yml.template # ← Template for generation ├── docker-compose.yml # ← Generated automatically (don't edit) ├── Makefile # ← Build automation └── ...
- Edit:config.json,.env
- Auto-generated:docker-compose.yml
- Use:makecommands for all operations
- Go 1.21 or later
- Docker
- Your MCP servers' dependencies (Node.js, Python, etc.)
# Clone the repository git clone <repository-url> cd remote-mcp-proxy # Install Go dependencies go mod tidy # Build locally go build -o remote-mcp-proxy . # Run locally (requires config.json at /app/config.json) ./remote-mcp-proxy # Or build and run with Docker docker build -t remote-mcp-proxy . docker run -v $(pwd)/config.json:/app/config.json -p 8080:8080 remote-mcp-proxy
- Build:go build -o remote-mcp-proxy .
- Run:./remote-mcp-proxy
- Test:go test ./...
- Lint:go fmt ./...andgo vet ./...
- Dependencies:go mod tidy
The Remote MCP Proxy includes comprehensive tests to ensure reliability and correctness.
# Unit tests only go test -v ./protocol ./mcp ./proxy # Integration tests go test -v . # Tests with coverage go test -cover ./... # Short tests (skip integration) go test -short ./... # Benchmarks go test -bench=. -benchmem ./...
Several test configurations are provided in thetest/directory:
- test/minimal-config.json: Basic echo server for testing
- test/development-config.json: Common MCP servers for development
- test/production-config.json: Production server examples
- test/config.json: Full test suite configuration
# Test with minimal config CONFIG_PATH=./test/minimal-config.json ./remote-mcp-proxy # Test with development servers (requires npm packages) CONFIG_PATH=./test/development-config.json ./remote-mcp-proxy # Test specific functionality curl http://localhost:8080/health curl -X GET http://localhost:8080/simple-echo/sse \ -H "Accept: text/event-stream"
- Protocol Translation: JSON-RPC ↔ Remote MCP message conversion
- Connection Management: Session handling, timeouts, cleanup
- Error Handling: Invalid requests, server failures, network issues
- Concurrency: Multiple simultaneous connections
- Authentication: Token validation and CORS
- Health Checks: Server status monitoring
- Integration: End-to-end workflow testing
For automated testing in CI environments:
# Install dependencies go mod download # Run tests with XML output (for CI) go test -v ./... -coverprofile=coverage.out go tool cover -html=coverage.out -o coverage.html # Static analysis go vet ./... go fmt ./...
- Add the server configuration toconfig.json
- Restart the proxy container
- The new server will be available at/{server-name}/sse
The proxy is built in Go and consists of:
- HTTP Proxy Server: Handles incoming Remote MCP requests using Gorilla Mux router
- MCP Process Manager: Spawns and manages local MCP server processes with health monitoring
- Protocol Translator: Converts between HTTP/SSE and MCP JSON-RPC protocols
- Configuration Loader: Reads and validates MCP server configs (claude_desktop_config.json format)
- SSE Handler: Implements Server-Sent Events for real-time Remote MCP communication
- Go 1.21: Core language for performance and concurrency
- Gorilla Mux: HTTP routing and path-based server selection
- Standard Library: Process management (os/exec), HTTP/SSE, JSON handling
- Alpine Linux: Minimal Docker base image for production deployment
The proxy implements the Remote MCP protocol specification to enable Claude.ai integration:
- OAuth 2.0 Authentication: Claude.ai authenticates using Bearer tokens via OAuth 2.0 Dynamic Client Registration
- Initialize Handshake: Synchronous POST request to/{server}/ssewith initialize message
- Session Management: Sessions are tracked usingMcp-Session-Idheader and marked as initialized immediately after successful handshake
- Tool Discovery: Follow-up requests use the same session to discover and call tools
- SSE Communication: Server-Sent Events for real-time message delivery (future requests)
Synchronous Initialize: Unlike local MCP servers, Claude.ai expects a synchronous JSON response to the initialize POST request, not an asynchronous SSE response.
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.




