In streamableClientConn.Close(), the DELETE request that terminates the session discards the HTTP response without closing its body:
// mcp/streamable.go:2239
} else if _, err := c.client.Do(req); err != nil {
c.closeErr = err
}
When client.Do succeeds (err == nil), the *http.Response is silently discarded. Per the net/http documentation: "It is the caller's responsibility to close Body. The default HTTP client's Transport may not reuse HTTP/1.x keep-alive TCP connections if the Body is not read to completion and closed."
This leaks the underlying TCP connection on every normal session close. The default client is http.DefaultClient (line 1571), which uses a transport with keep-alives enabled.
The rest of the file consistently closes response bodies (10 other call sites all call resp.Body.Close()). This one was missed.
Fix:
} else if resp, err := c.client.Do(req); err != nil {
c.closeErr = err
} else {
resp.Body.Close()
}
In
streamableClientConn.Close(), the DELETE request that terminates the session discards the HTTP response without closing its body:When
client.Dosucceeds (err == nil), the*http.Responseis silently discarded. Per thenet/httpdocumentation: "It is the caller's responsibility to close Body. The default HTTP client's Transport may not reuse HTTP/1.x keep-alive TCP connections if the Body is not read to completion and closed."This leaks the underlying TCP connection on every normal session close. The default client is
http.DefaultClient(line 1571), which uses a transport with keep-alives enabled.The rest of the file consistently closes response bodies (10 other call sites all call
resp.Body.Close()). This one was missed.Fix: