Skip to content

fix(mcp): give allow-private-ips OAuth clients a private connection pool#3707

Merged
dgageot merged 1 commit into
docker:mainfrom
dgageot:fix/oauth-allow-private-ips-transport-pool
Jul 17, 2026
Merged

fix(mcp): give allow-private-ips OAuth clients a private connection pool#3707
dgageot merged 1 commit into
docker:mainfrom
dgageot:fix/oauth-allow-private-ips-transport-pool

Conversation

@dgageot

@dgageot dgageot commented Jul 17, 2026

Copy link
Copy Markdown
Member

Follow-up to f7b5c10 (#3704), which fixed a flaky-test root cause — oauthTransport sharing http.DefaultTransport as its base RoundTripper — but left two paths untouched. Both surfaced in CI on #3696 as net/http: HTTP/1.x transport connection broken: http: CloseIdleConnections called in TestUnmanagedOAuthFlow_LegacyMode_NoAuthorizeURLInElicitation. The culprit is httptest.Server.Close, called by every finishing parallel test, which drains the shared http.DefaultTransport idle-connection pool. When another test's OAuth client holds a connection from that same pool — between the server's 401 and the authorized retry — the connection is killed mid-flight.

oauthHTTPClientForAllowPrivateIPs(true) returned a client with a nil Transport, so it fell back to http.DefaultTransport. The fix clones the default transport instead, giving each remote-client its own private pool while preserving the same proxy, HTTP/2, and timeout settings. The clone is constructed once per remote-client, so connection reuse within a single client is still effective. On the test side, newTestTransport similarly clones the default transport rather than returning a bare &http.Transport{}, TestMain reuses the production helper so its swapped-in client is also isolated, and the callback-server test client gets a per-test transport.

No behavior change in production beyond connection-pool isolation; the fix only affects which pool a client draws from.

oauthHTTPClientForAllowPrivateIPs(true) returned a client with a nil
Transport, i.e. http.DefaultTransport. Anything pruning that shared pool
via CloseIdleConnections — notably httptest.Server.Close, run by every
finishing parallel test — could break another client's in-flight request
("transport connection broken: http: CloseIdleConnections called"),
the same flake f7b5c10 fixed for the transports' base RoundTripper.

Clone the default transport instead: same proxy/HTTP2/timeout behavior,
private pool. TestMain's swapped-in client and the remaining nil-Transport
test clients now get private pools too.

Assisted-By: Claude
@dgageot
dgageot requested a review from a team as a code owner July 17, 2026 08:33
@aheritier aheritier added area/mcp MCP protocol, MCP tool servers, integration kind/fix PR fixes a bug (maps to fix:). Use on PRs only. labels Jul 17, 2026

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟢 APPROVE

The fix correctly solves the connection-pool isolation problem. Giving each oauthHTTPClientForAllowPrivateIPs(true) call its own cloned transport prevents httptest.Server.Close (or any third-party CloseIdleConnections) from breaking in-flight requests made by other test clients.

Dismissed security findings (review manually)

  • pkg/tools/mcp/oauth_helpers.go:46 — Unchecked type assertion http.DefaultTransport.(*http.Transport) (verifier mitigation: Go's stdlib always initializes DefaultTransport as *http.Transport; no code in this repo replaces it. The same pattern is used by the co-authored test helper newTestTransport. Risk is purely theoretical.)

@dgageot
dgageot merged commit 2567aef into docker:main Jul 17, 2026
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/mcp MCP protocol, MCP tool servers, integration kind/fix PR fixes a bug (maps to fix:). Use on PRs only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants