MCP Reverse ProxyΒΆ
The MCP Reverse Proxy enables local MCP servers to be accessible through remote gateways without requiring inbound network access. This is similar to SSH reverse tunneling or ngrok, but specifically designed for the MCP protocol.
OverviewΒΆ
The reverse proxy establishes an outbound connection from a local environment to a remote gateway, then tunnels all MCP protocol messages through this persistent connection. This allows:
- Firewall traversal: Share MCP servers without opening inbound ports
- NAT bypass: Work seamlessly behind corporate or home NATs
- Edge deployments: Connect edge servers to central management
- Development testing: Test local servers with cloud-hosted gateways
ArchitectureΒΆ
βββββββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββ
β Local MCP Server β stdio β Reverse Proxy β WS/SSE β Remote β
β (uvx mcp-server) β <-----> β Client β <-----> β Gateway β
βββββββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββ
β
β
ββββββββ΄βββββββ
β MCP Clients β
βββββββββββββββ
Quick StartΒΆ
1. Basic UsageΒΆ
Connect a local MCP server to a remote gateway:
# Set gateway URL and authentication
export REVERSE_PROXY_GATEWAY=https://gateway.example.com
export REVERSE_PROXY_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token \
--username admin --exp 10080 --secret your-secret-key)
# Run the reverse proxy
python3 -m mcpgateway.reverse_proxy \
--local-stdio "uvx mcp-server-git"
2. Command Line OptionsΒΆ
python3 -m mcpgateway.reverse_proxy \
--local-stdio "uvx mcp-server-filesystem --directory /path/to/files" \
--gateway https://gateway.example.com \
--token your-bearer-token \
--reconnect-delay 2 \
--max-retries 10 \
--keepalive 30 \
--log-level DEBUG
Options: - --local-stdio
: Command to run the local MCP server (required) - --gateway
: Remote gateway URL (or use REVERSE_PROXY_GATEWAY env var) - --token
: Bearer token for authentication (or use REVERSE_PROXY_TOKEN env var) - --reconnect-delay
: Initial reconnection delay in seconds (default: 1) - --max-retries
: Maximum reconnection attempts, 0=infinite (default: 0) - --keepalive
: Heartbeat interval in seconds (default: 30) - --log-level
: Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) - --verbose
: Enable verbose logging (same as βlog-level DEBUG) - --config
: Configuration file (YAML or JSON)
3. Configuration FileΒΆ
Create a reverse-proxy.yaml
:
# reverse-proxy.yaml
local_stdio: "uvx mcp-server-git"
gateway: "https://gateway.example.com"
token: "your-bearer-token"
reconnect_delay: 2
max_retries: 0
keepalive: 30
log_level: "INFO"
Run with configuration:
Environment VariablesΒΆ
REVERSE_PROXY_GATEWAY
: Remote gateway URLREVERSE_PROXY_TOKEN
: Bearer token for authenticationREVERSE_PROXY_RECONNECT_DELAY
: Initial reconnection delay (seconds)REVERSE_PROXY_MAX_RETRIES
: Maximum reconnection attempts (0=infinite)REVERSE_PROXY_LOG_LEVEL
: Python log level
Docker DeploymentΒΆ
Single ContainerΒΆ
FROM python:3.11-slim
# Install MCP gateway and server
RUN pip install mcp-gateway mcp-server-git
# Set environment
ENV REVERSE_PROXY_GATEWAY=https://gateway.example.com
ENV REVERSE_PROXY_TOKEN=your-token
# Run reverse proxy
CMD ["python", "-m", "mcpgateway.reverse_proxy", \
"--local-stdio", "mcp-server-git"]
Docker ComposeΒΆ
version: '3.8'
services:
reverse-proxy-git:
image: mcp-gateway:latest
environment:
REVERSE_PROXY_GATEWAY: https://gateway.example.com
REVERSE_PROXY_TOKEN: ${TOKEN}
command: >
python -m mcpgateway.reverse_proxy
--local-stdio "mcp-server-git"
--keepalive 30
--log-level INFO
restart: unless-stopped
reverse-proxy-filesystem:
image: mcp-gateway:latest
environment:
REVERSE_PROXY_GATEWAY: https://gateway.example.com
REVERSE_PROXY_TOKEN: ${TOKEN}
volumes:
- ./data:/data:ro
command: >
python -m mcpgateway.reverse_proxy
--local-stdio "mcp-server-filesystem --directory /data"
restart: unless-stopped
Kubernetes DeploymentΒΆ
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-reverse-proxy
spec:
replicas: 1
selector:
matchLabels:
app: mcp-reverse-proxy
template:
metadata:
labels:
app: mcp-reverse-proxy
spec:
containers:
- name: reverse-proxy
image: mcp-gateway:latest
env:
- name: REVERSE_PROXY_GATEWAY
value: "https://gateway.example.com"
- name: REVERSE_PROXY_TOKEN
valueFrom:
secretKeyRef:
name: mcp-credentials
key: token
command:
- python
- -m
- mcpgateway.reverse_proxy
args:
- --local-stdio
- "mcp-server-git"
- --keepalive
- "30"
resources:
limits:
memory: "256Mi"
cpu: "100m"
Gateway-Side ConfigurationΒΆ
The remote gateway must have the reverse proxy endpoints enabled:
1. WebSocket EndpointΒΆ
The gateway exposes /reverse-proxy/ws
for WebSocket connections:
2. Session ManagementΒΆ
View active reverse proxy sessions:
# List all sessions
curl -H "Authorization: Bearer $TOKEN" \
https://gateway.example.com/reverse-proxy/sessions
# Disconnect a session
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
https://gateway.example.com/reverse-proxy/sessions/{session_id}
3. Virtual Server RegistrationΒΆ
Reverse-proxied servers automatically appear in the gateway's server catalog and can be accessed like any other MCP server.
Security ConsiderationsΒΆ
AuthenticationΒΆ
- Always use authentication tokens in production
- Tokens should have appropriate expiration times
- Consider using mutual TLS for additional security
Network SecurityΒΆ
- The reverse proxy only requires outbound HTTPS/WSS
- No inbound firewall rules needed
- All traffic is encrypted via TLS
Best PracticesΒΆ
-
Use specific tokens per deployment
-
Monitor connection health
- Check gateway logs for connection events
- Monitor reconnection attempts
-
Set up alerts for persistent failures
-
Resource limits
- Set appropriate memory/CPU limits in containers
- Configure max message sizes
- Implement rate limiting on the gateway
TroubleshootingΒΆ
Connection IssuesΒΆ
-
Check connectivity:
-
Verify authentication:
-
Enable debug logging:
Common ErrorsΒΆ
Error | Cause | Solution |
---|---|---|
Connection refused | Gateway unreachable | Check gateway URL and network |
401 Unauthorized | Invalid token | Regenerate token with correct secret |
WebSocket connection failed | Firewall blocking WSS | Check outbound port 443 |
Subprocess not running | Local server crashed | Check server command and logs |
Max retries exceeded | Persistent network issue | Check network stability |
Performance TuningΒΆ
-
Adjust keepalive interval:
-
Configure reconnection strategy:
Advanced UsageΒΆ
Multiple Local ServersΒΆ
Run multiple reverse proxies for different servers:
# multi-server.yaml
servers:
- name: git-server
command: "uvx mcp-server-git"
gateway: "https://gateway1.example.com"
- name: filesystem-server
command: "uvx mcp-server-filesystem --directory /data"
gateway: "https://gateway2.example.com"
Load BalancingΒΆ
Connect the same server to multiple gateways:
# Primary gateway
python3 -m mcpgateway.reverse_proxy \
--local-stdio "uvx mcp-server-git" \
--gateway https://gateway1.example.com &
# Backup gateway
python3 -m mcpgateway.reverse_proxy \
--local-stdio "uvx mcp-server-git" \
--gateway https://gateway2.example.com &
Monitoring IntegrationΒΆ
Export metrics for monitoring systems:
# Custom monitoring wrapper
import asyncio
from mcpgateway.reverse_proxy import ReverseProxyClient
class MonitoredReverseProxy(ReverseProxyClient):
async def connect(self):
# Export connection metric
prometheus_client.Counter('reverse_proxy_connections_total').inc()
await super().connect()