HTTP transport issues
Diagnose SSE disconnects, missing session IDs, port conflicts, and 404s from the HTTP transport.
Last updated
HTTP transport issues
When the HTTP + SSE transport misbehaves, the cause is usually one of four things.
404 Not Found on every request
The server only responds on /mcp. Any other path returns 404.
- Wrong path. Double-check the URL.
http://host:9090/mcp— not/mcp/tools/call, not/api/mcp, not/. - Wrong host or port.
MCP_HTTP_PORT=9090is the default; confirm withlsof -i :9090orss -lnt.
Port already in use
Error: listen EADDRINUSE: address already in use 0.0.0.0:9090
Another process is bound to :9090. Either stop it or pick a different
port:
MCP_HTTP_PORT=9091 MCP_TRANSPORT=http node apps/mcp/dist/index.js
Session ID is missing or stale
The transport is session-aware. Every request after the first
initialize must include the mcp-session-id header returned on that
initialize. Common failures:
- The header is not echoed. Each subsequent request starts a fresh session, which works but loses tool capability context and forces a re-initialize.
- The session expired. If the transport closed (network blip, TCP
reset, explicit
DELETE /mcp), the server drops the session. A stale ID is ignored; the next request mints a new session. - Header name is wrong. It's
mcp-session-id, lowercase, hyphens. Most HTTP clients normalize header casing, but some (notably Windows PowerShell) don't.
See Transports → Sessions for the full contract.
SSE connection closes immediately
A GET /mcp stream should stay open indefinitely. If it closes in under a
second:
- Proxy buffering. If the server sits behind a reverse proxy, confirm
SSE is passed through without buffering (
proxy_buffering offin nginx,disable_chunked_encoding=truein some CDN configs). - Client timeout. Many HTTP clients default to a short read timeout.
Set a long or unlimited timeout for SSE reads (
curl -N,axios.timeout=0). - The server crashed. The Plainwork MCP server writes fatal errors to
stderr. Run it in the foreground and watch for
[plainwork-mcp] fatal: …lines.
Starting works, requests hang forever
The HTTP transport does not kill partial requests — if your client sends a POST with a never-ending body, the server waits. Symptoms:
- Client issues
POST /mcp, server never responds. Content-Lengthis omitted and the request body stream is not closed.
Always send Content-Length with a complete body, or use Transfer- Encoding: chunked and close the request stream.
Docker-specific
docker runwithout-p 9090:9090— the server is listening inside the container but the port is not published. Add the flag.- Host-network mode on Linux —
--network=hostis an alternative to-p, but means every container using that mode shares the port namespace. Prefer-punless you have a reason not to.