From 9731b3e30f194b3789409fdf28cb55387b924ced Mon Sep 17 00:00:00 2001 From: Manuel Ibar Date: Wed, 24 Sep 2025 13:55:20 -0300 Subject: [PATCH] mcp: decouple HTTPClient concrete implementation from client transports fixes #513 --- mcp/shared.go | 8 ++++++++ mcp/sse.go | 12 ++++++------ mcp/streamable.go | 8 +++++--- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/mcp/shared.go b/mcp/shared.go index 69b8836a..06515dce 100644 --- a/mcp/shared.go +++ b/mcp/shared.go @@ -541,3 +541,11 @@ func startKeepalive(session keepaliveSession, interval time.Duration, cancelPtr } }() } + +// HTTPClient is the minimal interface required by client transports for issuing HTTP requests. +// +// It matches the method set of (*http.Client).Do, allowing callers to provide custom HTTP clients +// that incorporate middleware (auth, tracing, retries), or test doubles. +type HTTPClient interface { + Do(*http.Request) (*http.Response, error) +} diff --git a/mcp/sse.go b/mcp/sse.go index 7f644918..ed9a2ae6 100644 --- a/mcp/sse.go +++ b/mcp/sse.go @@ -326,9 +326,9 @@ type SSEClientTransport struct { // Endpoint is the SSE endpoint to connect to. Endpoint string - // HTTPClient is the client to use for making HTTP requests. If nil, - // http.DefaultClient is used. - HTTPClient *http.Client + // HTTPClient performs HTTP requests. If nil, http.DefaultClient is used. + // Any type implementing a Do(*http.Request) (*http.Response, error) method is supported. + HTTPClient HTTPClient } // Connect connects through the client endpoint. @@ -403,9 +403,9 @@ func (c *SSEClientTransport) Connect(ctx context.Context) (Connection, error) { // - Reads are SSE 'message' events, and pushes them onto a buffered channel. // - Close terminates the GET request. type sseClientConn struct { - client *http.Client // HTTP client to use for requests - msgEndpoint *url.URL // session endpoint for POSTs - incoming chan []byte // queue of incoming messages + client HTTPClient // HTTP client to use for requests + msgEndpoint *url.URL // session endpoint for POSTs + incoming chan []byte // queue of incoming messages mu sync.Mutex body io.ReadCloser // body of the hanging GET diff --git a/mcp/streamable.go b/mcp/streamable.go index 8072a637..ff629584 100644 --- a/mcp/streamable.go +++ b/mcp/streamable.go @@ -976,8 +976,10 @@ func (c *streamableServerConn) Close() error { // endpoint serving the streamable HTTP transport defined by the 2025-03-26 // version of the spec. type StreamableClientTransport struct { - Endpoint string - HTTPClient *http.Client + Endpoint string + // HTTPClient performs HTTP requests. If nil, http.DefaultClient is used. + // Any type implementing a Do(*http.Request) (*http.Response, error) method is supported. + HTTPClient HTTPClient // MaxRetries is the maximum number of times to attempt a reconnect before giving up. // It defaults to 5. To disable retries, use a negative number. MaxRetries int @@ -1034,7 +1036,7 @@ func (t *StreamableClientTransport) Connect(ctx context.Context) (Connection, er type streamableClientConn struct { url string - client *http.Client + client HTTPClient ctx context.Context cancel context.CancelFunc incoming chan jsonrpc.Message