Skip to content

Conversation

@jeanlaurent
Copy link
Member

Fix: Apply custom HTTP headers to remote MCP server requests

Problem: Custom HTTP headers configured for remote MCP servers were stored but never applied to HTTP requests, preventing authentication to servers that require API keys, bearer tokens, or other header-based auth.

Root cause: In commit 814d46a ("MCP Oauth rework"), when migrating from mark3labs/mcp-go to the official MCP SDK, header support was accidentally dropped. The createHTTPClient() method only wrapped requests with OAuth support, ignoring the stored headers.

Summary

  • Context: The remoteMCPClient in pkg/tools/mcp/remote.go handles connections to remote MCP servers over HTTP (SSE and Streamable transports) and accepts custom HTTP headers for authentication or other purposes.
  • Bug: Custom HTTP headers passed to newRemoteClient are stored in the struct but never applied to HTTP requests sent to the remote MCP server.
  • Actual vs. expected: Headers are accepted as a parameter and stored in the remoteMCPClient.headers field, but the createHTTPClient method creates an HTTP client that ignores these headers. Expected behavior is that all HTTP requests to the MCP server should include these custom headers.
  • Impact: Users cannot authenticate to remote MCP servers that require custom headers (like API keys, authorization tokens, or other authentication mechanisms), making those servers effectively inaccessible.

Code with bug

In pkg/tools/mcp/remote.go:

type remoteMCPClient struct {
	session             *mcp.ClientSession
	url                 string
	transportType       string
	headers             map[string]string  // <-- BUG 🔴 Stored but never used
	tokenStore          OAuthTokenStore
	elicitationHandler  tools.ElicitationHandler
	oauthSuccessHandler func()
	managed             bool
	mu                  sync.RWMutex
}

func newRemoteClient(url, transportType string, headers map[string]string, tokenStore OAuthTokenStore, managed bool) *remoteMCPClient {
	slog.Debug("Creating remote MCP client", "url", url, "transport", transportType, "headers", headers, "managed", managed)

	if tokenStore == nil {
		tokenStore = NewInMemoryTokenStore()
	}

	return &remoteMCPClient{
		url:           url,
		transportType: transportType,
		headers:       headers,  // <-- BUG 🔴 Headers are stored here but never used
		tokenStore:    tokenStore,
		managed:       managed,
	}
}

// createHTTPClient creates an HTTP client with OAuth support
func (c *remoteMCPClient) createHTTPClient() *http.Client {
	return &http.Client{
		Transport: &oauthTransport{  // <-- BUG 🔴 Only wraps with OAuth, doesn't add custom headers
			base:       http.DefaultTransport,
			client:     c,
			tokenStore: c.tokenStore,
			baseURL:    c.url,
			managed:    c.managed,
		},
	}
}

@jeanlaurent jeanlaurent requested a review from a team as a code owner December 13, 2025 10:25
@dgageot dgageot merged commit 22f8914 into docker:main Dec 13, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants