How to Deploy MetaMCP Behind Nginx: Ensuring SSE Compatibility
Configure Nginx with keepalive_timeout 300, disable buffering via X-Accel-Buffering 'no', and clear the Connection header to stream MetaMCP's Server-Sent Events without interruption.
MetaMCP relies on Server-Sent Events (SSE) to stream real-time data through long-lived HTTP connections, which requires specific reverse-proxy tuning to avoid premature connection drops. When deploying the metatool-ai/metamcp repository behind Nginx, default buffering settings will block or delay the event stream, breaking the real-time experience for downstream clients. This guide provides the exact configuration directives and source file references needed to deploy MetaMCP behind Nginx while maintaining full SSE compatibility.
Why SSE Requires Special Nginx Configuration
MetaMCP uses SSE to maintain persistent connections between the backend and clients such as Open WebUI or Claude Desktop. In apps/backend/src/routers/public-metamcp/sse.ts, the application handles the /metamcp/:endpoint_name/sse route by streaming EventSource data over a single HTTP connection that can remain open for minutes or hours. Nginx's default behavior—buffering responses and closing idle connections after 75 seconds—directly conflicts with this architecture.
To support SSE properly, you must:
- Extend connection timeouts to prevent Nginx from closing idle streams
- Disable response buffering to ensure immediate delivery of each
data:line - Preserve original request headers so MetaMCP can correctly build URLs and perform authentication
Critical Nginx Directives for MetaMCP SSE
The repository provides a working reference in nginx.conf.example. The following directives are essential for SSE compatibility:
| Directive | Purpose | Source Location |
|---|---|---|
keepalive_timeout 300; |
Extends idle timeout from the default 75s to 5 minutes (or longer) to support long-lived streams | nginx.conf.example, line 31 |
proxy_set_header Connection ''; |
Removes the Connection: close header that would otherwise terminate the stream immediately |
nginx.conf.example, line 134 |
proxy_set_header Cache-Control 'no-cache'; |
Prevents intermediate caches from buffering the event stream | nginx.conf.example, line 138 |
proxy_set_header X-Accel-Buffering 'no'; |
Disables Nginx's internal response buffering, ensuring real-time delivery | nginx.conf.example, line 139 |
proxy_set_header Host $host; |
Preserves the original Host header for correct URL generation | nginx.conf.example, lines 122-125 |
Complete Nginx Configuration for MetaMCP
Copy the following location block into your nginx.conf, adjusting the proxy_pass URL to match your MetaMCP backend address (default port 12008):
http {
# Critical for long-lived SSE connections
keepalive_timeout 300;
server {
listen 8080;
server_name localhost;
# Static frontend assets
location / {
root html;
index index.html index.htm;
}
# MetaMCP SSE and API proxy
location /metamcp/ {
proxy_pass http://localhost:12008;
proxy_http_version 1.1;
# Preserve client information
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# SSE-specific headers (disable buffering)
proxy_set_header Connection '';
proxy_set_header Cache-Control 'no-cache';
proxy_set_header X-Accel-Buffering 'no';
}
}
}
Key configuration details:
proxy_http_version 1.1– Required for keepalive connections to the backendproxy_pass http://localhost:12008– Points to the MetaMCP backend container or process- Location path
/metamcp/– Matches the route defined inapps/backend/src/routers/public-metamcp/sse.ts
Docker Compose Integration
If running MetaMCP with Docker Compose, expose the backend port and mount your custom Nginx configuration:
services:
metamcp-backend:
build: .
container_name: metamcp-backend
expose:
- "12008"
environment:
- NODE_ENV=production
nginx:
image: nginx:stable-alpine
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "8080:8080"
depends_on:
- metamcp-backend
Verifying SSE Compatibility Through Nginx
Test that Nginx correctly proxies the SSE stream without buffering by connecting directly to the /metamcp/:endpoint_name/sse endpoint:
curl -N -H "Accept: text/event-stream" http://localhost:8080/metamcp/my-endpoint/sse
The -N flag disables curl's buffering, allowing you to observe each data: line as the server emits it. If the configuration is correct, you will see a continuous stream of events; if buffering is misconfigured, the connection will hang or timeout without displaying data.
This verification confirms that the directives from nginx.conf.example are functioning correctly and that your MetaMCP instance can stream events reliably through the reverse proxy.
Summary
- Extend timeouts: Set
keepalive_timeout 300(or higher) in thehttpblock to prevent Nginx from closing idle SSE connections - Disable buffering: Use
proxy_set_header X-Accel-Buffering 'no'andproxy_set_header Connection ''to ensure real-time event delivery - Preserve headers: Pass
Host,X-Real-IP, and forwarding headers so MetaMCP can authenticate requests and generate correct URLs - Reference implementation: Consult
apps/backend/src/routers/public-metamcp/sse.tsfor the SSE endpoint logic andnginx.conf.examplefor the complete working configuration - Test with curl: Use
curl -Nto verify unbuffered streaming through your Nginx proxy before deploying to production
Frequently Asked Questions
What port does the MetaMCP backend run on by default?
The MetaMCP backend listens on port 12008 by default, as reflected in the proxy_pass directive within nginx.conf.example. When deploying with Docker, expose this port internally and map Nginx to communicate with http://metamcp-backend:12008 (or localhost:12008 for single-host deployments).
Why does SSE stop working when I add Nginx?
Nginx buffers responses by default to optimize throughput, which breaks SSE's real-time nature. Additionally, Nginx closes idle connections after 75 seconds by default. To fix this, you must disable buffering with X-Accel-Buffering 'no', clear the Connection header, and increase keepalive_timeout as shown in the configuration above.
Can I use this same configuration for the internal MCP proxy routes?
Yes. The SSE transport is also used for internal proxy routes implemented in apps/backend/src/routers/mcp-proxy/server.ts. The same Nginx location block and buffering directives apply to any MetaMCP endpoint that utilizes Server-Sent Events, ensuring consistent behavior across public and internal APIs.
How do I handle authentication headers when proxying through Nginx?
Pass the original Host header and client IP information using proxy_set_header Host $host, X-Real-IP $remote_addr, and X-Forwarded-For $proxy_add_x_forwarded_for. MetaMCP inspects these headers to validate requests and build absolute URLs, so preserving them is essential for correct authentication and routing behavior.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →