MCP: SSE timeout or unexpected disconnect
Why long-lived MCP SSE connections drop after a minute or two, when to switch to Streamable HTTP, and the proxy and keep-alive settings that fix it.
The symptom
The MCP server connects fine and answers the first request. After a minute or two of idle, the next request times out or returns a connection error. The client logs SSE connection closed, stream ended, or a generic ECONNRESET.
Fix 1: move to Streamable HTTP
The current MCP spec defines Streamable HTTP as the HTTP-based transport. The older HTTP+SSE transport is kept for backwards compatibility but is marked deprecated. Streamable HTTP opens streams on demand and survives the network layer better. Most servers (including Hjarni) accept it at the same URL.
If your client lets you pick a transport explicitly (VS Code's "type": "http", Goose's type: streamable_http), pick Streamable HTTP. Most timeout problems disappear there.
Fix 2: turn off proxy buffering
Reverse proxies between the client and the MCP server can buffer responses. SSE depends on bytes flowing out as soon as they exist. Any buffering breaks the stream.
nginx:
location /mcp {
proxy_pass http://upstream;
proxy_buffering off;
proxy_set_header X-Accel-Buffering "no";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
Cloudflare:
Cloudflare proxies SSE natively, so the orange cloud is not the problem. The thing that bites is the proxy read timeout (120 seconds by default, configurable on Enterprise). If your stream needs to stay idle longer, raise the timeout, switch to Streamable HTTP, or front the endpoint through a Cloudflare Tunnel.
Fix 3: raise idle timeouts on every hop
Every layer between the client and the server has its own idle timeout. The connection drops at the tightest one.
- AWS ALB: default 60s. Raise via the load balancer attribute
idle_timeout.timeout_seconds. - GCP Load Balancer: default 30s for backend service. Raise
timeoutSec. - Cloudflare: proxy read timeout defaults to 120s and is configurable on Enterprise. Switch transports if long-lived SSE drops are a recurring issue.
- Puma/Unicorn: default 60s worker timeout. Raise
worker_timeoutfor the MCP route.
Fix 4: confirm the client retries
Some MCP clients reconnect transparently on drop. Others give up after one error. In that case, restart the app or remove and re-add the server. Check the client's logs for retry behaviour. If retries are absent, that is your workaround until the server-side timeout is fixed.