Skip to content

Commit 4516fc0

Browse files
authored
749 reverse proxy (#750)
* Fix download Signed-off-by: Mihai Criveti <[email protected]> * Reverse proxy Signed-off-by: Mihai Criveti <[email protected]> * Reverse proxy Signed-off-by: Mihai Criveti <[email protected]> * Reverse proxy Signed-off-by: Mihai Criveti <[email protected]> * doctest improvements Signed-off-by: Mihai Criveti <[email protected]> --------- Signed-off-by: Mihai Criveti <[email protected]>
1 parent 3a3a889 commit 4516fc0

File tree

11 files changed

+1957
-0
lines changed

11 files changed

+1957
-0
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ include *.sh
2929
include *.txt
3030
recursive-include async_testing *.py
3131
recursive-include async_testing *.yaml
32+
recursive-include examples *.yaml
3233

3334
# 3️⃣ Tooling/lint configuration dot-files (explicit so they're not lost)
3435
include .env.make

docs/docs/using/.pages

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ nav:
22
- index.md
33
- mcpgateway-wrapper.md
44
- mcpgateway-translate.md
5+
- reverse-proxy.md
56
- Clients: clients
67
- Agents: agents
78
- Servers: servers

docs/docs/using/reverse-proxy.md

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
# MCP Reverse Proxy
2+
3+
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.
4+
5+
## Overview
6+
7+
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:
8+
9+
- **Firewall traversal**: Share MCP servers without opening inbound ports
10+
- **NAT bypass**: Work seamlessly behind corporate or home NATs
11+
- **Edge deployments**: Connect edge servers to central management
12+
- **Development testing**: Test local servers with cloud-hosted gateways
13+
14+
## Architecture
15+
16+
```
17+
┌─────────────────────┐ ┌──────────────────┐ ┌─────────────┐
18+
│ Local MCP Server │ stdio │ Reverse Proxy │ WS/SSE │ Remote │
19+
│ (uvx mcp-server) │ <-----> │ Client │ <-----> │ Gateway │
20+
└─────────────────────┘ └──────────────────┘ └─────────────┘
21+
22+
23+
┌──────┴──────┐
24+
│ MCP Clients │
25+
└─────────────┘
26+
```
27+
28+
## Quick Start
29+
30+
### 1. Basic Usage
31+
32+
Connect a local MCP server to a remote gateway:
33+
34+
```bash
35+
# Set gateway URL and authentication
36+
export REVERSE_PROXY_GATEWAY=https://gateway.example.com
37+
export REVERSE_PROXY_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token \
38+
--username admin --exp 10080 --secret your-secret-key)
39+
40+
# Run the reverse proxy
41+
python3 -m mcpgateway.reverse_proxy \
42+
--local-stdio "uvx mcp-server-git"
43+
```
44+
45+
### 2. Command Line Options
46+
47+
```bash
48+
python3 -m mcpgateway.reverse_proxy \
49+
--local-stdio "uvx mcp-server-filesystem --directory /path/to/files" \
50+
--gateway https://gateway.example.com \
51+
--token your-bearer-token \
52+
--reconnect-delay 2 \
53+
--max-retries 10 \
54+
--keepalive 30 \
55+
--log-level DEBUG
56+
```
57+
58+
Options:
59+
- `--local-stdio`: Command to run the local MCP server (required)
60+
- `--gateway`: Remote gateway URL (or use REVERSE_PROXY_GATEWAY env var)
61+
- `--token`: Bearer token for authentication (or use REVERSE_PROXY_TOKEN env var)
62+
- `--reconnect-delay`: Initial reconnection delay in seconds (default: 1)
63+
- `--max-retries`: Maximum reconnection attempts, 0=infinite (default: 0)
64+
- `--keepalive`: Heartbeat interval in seconds (default: 30)
65+
- `--log-level`: Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
66+
- `--verbose`: Enable verbose logging (same as --log-level DEBUG)
67+
- `--config`: Configuration file (YAML or JSON)
68+
69+
### 3. Configuration File
70+
71+
Create a `reverse-proxy.yaml`:
72+
73+
```yaml
74+
# reverse-proxy.yaml
75+
local_stdio: "uvx mcp-server-git"
76+
gateway: "https://gateway.example.com"
77+
token: "your-bearer-token"
78+
reconnect_delay: 2
79+
max_retries: 0
80+
keepalive: 30
81+
log_level: "INFO"
82+
```
83+
84+
Run with configuration:
85+
86+
```bash
87+
python3 -m mcpgateway.reverse_proxy --config reverse-proxy.yaml
88+
```
89+
90+
## Environment Variables
91+
92+
- `REVERSE_PROXY_GATEWAY`: Remote gateway URL
93+
- `REVERSE_PROXY_TOKEN`: Bearer token for authentication
94+
- `REVERSE_PROXY_RECONNECT_DELAY`: Initial reconnection delay (seconds)
95+
- `REVERSE_PROXY_MAX_RETRIES`: Maximum reconnection attempts (0=infinite)
96+
- `REVERSE_PROXY_LOG_LEVEL`: Python log level
97+
98+
## Docker Deployment
99+
100+
### Single Container
101+
102+
```dockerfile
103+
FROM python:3.11-slim
104+
105+
# Install MCP gateway and server
106+
RUN pip install mcp-gateway mcp-server-git
107+
108+
# Set environment
109+
ENV REVERSE_PROXY_GATEWAY=https://gateway.example.com
110+
ENV REVERSE_PROXY_TOKEN=your-token
111+
112+
# Run reverse proxy
113+
CMD ["python", "-m", "mcpgateway.reverse_proxy", \
114+
"--local-stdio", "mcp-server-git"]
115+
```
116+
117+
### Docker Compose
118+
119+
```yaml
120+
version: '3.8'
121+
122+
services:
123+
reverse-proxy-git:
124+
image: mcp-gateway:latest
125+
environment:
126+
REVERSE_PROXY_GATEWAY: https://gateway.example.com
127+
REVERSE_PROXY_TOKEN: ${TOKEN}
128+
command: >
129+
python -m mcpgateway.reverse_proxy
130+
--local-stdio "mcp-server-git"
131+
--keepalive 30
132+
--log-level INFO
133+
restart: unless-stopped
134+
135+
reverse-proxy-filesystem:
136+
image: mcp-gateway:latest
137+
environment:
138+
REVERSE_PROXY_GATEWAY: https://gateway.example.com
139+
REVERSE_PROXY_TOKEN: ${TOKEN}
140+
volumes:
141+
- ./data:/data:ro
142+
command: >
143+
python -m mcpgateway.reverse_proxy
144+
--local-stdio "mcp-server-filesystem --directory /data"
145+
restart: unless-stopped
146+
```
147+
148+
## Kubernetes Deployment
149+
150+
```yaml
151+
apiVersion: apps/v1
152+
kind: Deployment
153+
metadata:
154+
name: mcp-reverse-proxy
155+
spec:
156+
replicas: 1
157+
selector:
158+
matchLabels:
159+
app: mcp-reverse-proxy
160+
template:
161+
metadata:
162+
labels:
163+
app: mcp-reverse-proxy
164+
spec:
165+
containers:
166+
- name: reverse-proxy
167+
image: mcp-gateway:latest
168+
env:
169+
- name: REVERSE_PROXY_GATEWAY
170+
value: "https://gateway.example.com"
171+
- name: REVERSE_PROXY_TOKEN
172+
valueFrom:
173+
secretKeyRef:
174+
name: mcp-credentials
175+
key: token
176+
command:
177+
- python
178+
- -m
179+
- mcpgateway.reverse_proxy
180+
args:
181+
- --local-stdio
182+
- "mcp-server-git"
183+
- --keepalive
184+
- "30"
185+
resources:
186+
limits:
187+
memory: "256Mi"
188+
cpu: "100m"
189+
```
190+
191+
## Gateway-Side Configuration
192+
193+
The remote gateway must have the reverse proxy endpoints enabled:
194+
195+
### 1. WebSocket Endpoint
196+
197+
The gateway exposes `/reverse-proxy/ws` for WebSocket connections:
198+
199+
```python
200+
# Gateway receives connections at:
201+
wss://gateway.example.com/reverse-proxy/ws
202+
```
203+
204+
### 2. Session Management
205+
206+
View active reverse proxy sessions:
207+
208+
```bash
209+
# List all sessions
210+
curl -H "Authorization: Bearer $TOKEN" \
211+
https://gateway.example.com/reverse-proxy/sessions
212+
213+
# Disconnect a session
214+
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
215+
https://gateway.example.com/reverse-proxy/sessions/{session_id}
216+
```
217+
218+
### 3. Virtual Server Registration
219+
220+
Reverse-proxied servers automatically appear in the gateway's server catalog and can be accessed like any other MCP server.
221+
222+
## Security Considerations
223+
224+
### Authentication
225+
226+
- Always use authentication tokens in production
227+
- Tokens should have appropriate expiration times
228+
- Consider using mutual TLS for additional security
229+
230+
### Network Security
231+
232+
- The reverse proxy only requires outbound HTTPS/WSS
233+
- No inbound firewall rules needed
234+
- All traffic is encrypted via TLS
235+
236+
### Best Practices
237+
238+
1. **Use specific tokens per deployment**
239+
```bash
240+
# Generate deployment-specific token
241+
python3 -m mcpgateway.utils.create_jwt_token \
242+
--username edge-server-01 \
243+
--exp 10080 \
244+
--secret $JWT_SECRET
245+
```
246+
247+
2. **Monitor connection health**
248+
- Check gateway logs for connection events
249+
- Monitor reconnection attempts
250+
- Set up alerts for persistent failures
251+
252+
3. **Resource limits**
253+
- Set appropriate memory/CPU limits in containers
254+
- Configure max message sizes
255+
- Implement rate limiting on the gateway
256+
257+
## Troubleshooting
258+
259+
### Connection Issues
260+
261+
1. **Check connectivity**:
262+
```bash
263+
# Test gateway reachability
264+
curl -I https://gateway.example.com/healthz
265+
```
266+
267+
2. **Verify authentication**:
268+
```bash
269+
# Test token validity
270+
curl -H "Authorization: Bearer $TOKEN" \
271+
https://gateway.example.com/reverse-proxy/sessions
272+
```
273+
274+
3. **Enable debug logging**:
275+
```bash
276+
python3 -m mcpgateway.reverse_proxy \
277+
--local-stdio "uvx mcp-server-git" \
278+
--log-level DEBUG
279+
```
280+
281+
### Common Errors
282+
283+
| Error | Cause | Solution |
284+
|-------|-------|----------|
285+
| `Connection refused` | Gateway unreachable | Check gateway URL and network |
286+
| `401 Unauthorized` | Invalid token | Regenerate token with correct secret |
287+
| `WebSocket connection failed` | Firewall blocking WSS | Check outbound port 443 |
288+
| `Subprocess not running` | Local server crashed | Check server command and logs |
289+
| `Max retries exceeded` | Persistent network issue | Check network stability |
290+
291+
### Performance Tuning
292+
293+
1. **Adjust keepalive interval**:
294+
```bash
295+
# Shorter interval for unstable networks
296+
--keepalive 15
297+
298+
# Longer interval for stable networks
299+
--keepalive 60
300+
```
301+
302+
2. **Configure reconnection strategy**:
303+
```bash
304+
# Quick reconnect with limited retries
305+
--reconnect-delay 0.5 --max-retries 20
306+
307+
# Slow reconnect with infinite retries
308+
--reconnect-delay 5 --max-retries 0
309+
```
310+
311+
## Advanced Usage
312+
313+
### Multiple Local Servers
314+
315+
Run multiple reverse proxies for different servers:
316+
317+
```yaml
318+
# multi-server.yaml
319+
servers:
320+
- name: git-server
321+
command: "uvx mcp-server-git"
322+
gateway: "https://gateway1.example.com"
323+
324+
- name: filesystem-server
325+
command: "uvx mcp-server-filesystem --directory /data"
326+
gateway: "https://gateway2.example.com"
327+
```
328+
329+
### Load Balancing
330+
331+
Connect the same server to multiple gateways:
332+
333+
```bash
334+
# Primary gateway
335+
python3 -m mcpgateway.reverse_proxy \
336+
--local-stdio "uvx mcp-server-git" \
337+
--gateway https://gateway1.example.com &
338+
339+
# Backup gateway
340+
python3 -m mcpgateway.reverse_proxy \
341+
--local-stdio "uvx mcp-server-git" \
342+
--gateway https://gateway2.example.com &
343+
```
344+
345+
### Monitoring Integration
346+
347+
Export metrics for monitoring systems:
348+
349+
```python
350+
# Custom monitoring wrapper
351+
import asyncio
352+
from mcpgateway.reverse_proxy import ReverseProxyClient
353+
354+
class MonitoredReverseProxy(ReverseProxyClient):
355+
async def connect(self):
356+
# Export connection metric
357+
prometheus_client.Counter('reverse_proxy_connections_total').inc()
358+
await super().connect()
359+
```
360+
361+
## Related Documentation
362+
363+
- [MCP Gateway Documentation](./README.md)
364+
- [MCP Protocol Specification](https://modelcontextprotocol.io)
365+
- [Transport Protocols](./transports.md)
366+
- [Authentication Guide](./auth.md)

0 commit comments

Comments
 (0)