When running supergateway in stateless streamableHttp mode, child processes spawned for each request are never cleaned up because transport.onclose is never called. This causes unbounded memory growth until the container is OOM-killed.
Environment
supergateway version: 3.4.3
Runtime: Bun 1.x (also reproducible with Node.js)
Mode: --outputTransport streamableHttp (stateless, no --stateful flag)
Container: Docker with 4GB memory limit
Reproduction
Run supergateway wrapping any MCP server in stateless streamableHttp mode:
supergateway --stdio "bun my-mcp-server.js" --port 8080 --outputTransport streamableHttp
Send multiple HTTP requests to the server:
for i in {1..100}; do
curl -X POST http://localhost:8080/mcp
-H "Content-Type: application/json"
-d '{"jsonrpc":"2.0","id":"'$i'","method":"tools/list","params":{}}'
done
docker stats my-container
- Memory grows continuously with each request
Expected Behavior
In stateless mode, each request should:
Spawn a child process
Handle the request
Clean up the child process when the HTTP response completes
Actual Behavior
Each request spawns a child process, but:
transport.onclose is never called for stateless HTTP requests
Child processes remain alive indefinitely
Memory grows linearly with each request
Eventually causes OOM and container restart
When running supergateway in stateless streamableHttp mode, child processes spawned for each request are never cleaned up because transport.onclose is never called. This causes unbounded memory growth until the container is OOM-killed.
Environment
supergateway version: 3.4.3
Runtime: Bun 1.x (also reproducible with Node.js)
Mode: --outputTransport streamableHttp (stateless, no --stateful flag)
Container: Docker with 4GB memory limit
Reproduction
Run supergateway wrapping any MCP server in stateless streamableHttp mode:
supergateway --stdio "bun my-mcp-server.js" --port 8080 --outputTransport streamableHttp
Send multiple HTTP requests to the server:
for i in {1..100}; do
curl -X POST http://localhost:8080/mcp
-H "Content-Type: application/json"
-d '{"jsonrpc":"2.0","id":"'$i'","method":"tools/list","params":{}}'
done
docker stats my-container
Expected Behavior
In stateless mode, each request should:
Spawn a child process
Handle the request
Clean up the child process when the HTTP response completes
Actual Behavior
Each request spawns a child process, but:
transport.onclose is never called for stateless HTTP requests
Child processes remain alive indefinitely
Memory grows linearly with each request
Eventually causes OOM and container restart