mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: isolate MCP HTTP transports from DefaultTransport in tests (#25821)
Use testing.Testing() inside createTransport to automatically clone http.DefaultTransport when running in tests. In production, DefaultTransport is used as-is (efficient connection pooling). This fixes the CloseIdleConnections flake class: httptest.Server.Close() calls http.DefaultTransport.CloseIdleConnections(), which disrupts any MCP client sharing that transport. The testing.Testing() check means every MCP transport created during tests gets isolation automatically, with no caller changes needed. Closes coder/internal#1016 Closes PLAT-291
This commit is contained in:
@@ -975,15 +975,19 @@ func (m *Manager) createTransport(ctx context.Context, cfg ServerConfig) (transp
|
||||
}),
|
||||
), nil
|
||||
case "http", "":
|
||||
return transport.NewStreamableHTTP(
|
||||
cfg.URL,
|
||||
transport.WithHTTPHeaders(cfg.Headers),
|
||||
)
|
||||
var opts []transport.StreamableHTTPCOption
|
||||
opts = append(opts, transport.WithHTTPHeaders(cfg.Headers))
|
||||
if c := mcpHTTPClient(); c != nil {
|
||||
opts = append(opts, transport.WithHTTPBasicClient(c))
|
||||
}
|
||||
return transport.NewStreamableHTTP(cfg.URL, opts...)
|
||||
case "sse":
|
||||
return transport.NewSSE(
|
||||
cfg.URL,
|
||||
transport.WithHeaders(cfg.Headers),
|
||||
)
|
||||
var sseOpts []transport.ClientOption
|
||||
sseOpts = append(sseOpts, transport.WithHeaders(cfg.Headers))
|
||||
if c := mcpHTTPClient(); c != nil {
|
||||
sseOpts = append(sseOpts, transport.WithHTTPClient(c))
|
||||
}
|
||||
return transport.NewSSE(cfg.URL, sseOpts...)
|
||||
default:
|
||||
return nil, xerrors.Errorf("unsupported transport %q", cfg.Transport)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package agentmcp
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// mcpHTTPClient returns an isolated *http.Client when running
|
||||
// inside tests, or nil for production. During tests,
|
||||
// httptest.Server.Close() calls
|
||||
// http.DefaultTransport.CloseIdleConnections(), which disrupts
|
||||
// any MCP client sharing that transport. When DefaultTransport
|
||||
// is a *http.Transport it is cloned; otherwise a minimal
|
||||
// transport with ProxyFromEnvironment is created as a fallback.
|
||||
func mcpHTTPClient() *http.Client {
|
||||
if !testing.Testing() {
|
||||
return nil
|
||||
}
|
||||
if dt, ok := http.DefaultTransport.(*http.Transport); ok {
|
||||
return &http.Client{Transport: dt.Clone()}
|
||||
}
|
||||
return &http.Client{Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
}}
|
||||
}
|
||||
Reference in New Issue
Block a user