- Notifications
You must be signed in to change notification settings - Fork 698
Description
Problem Statement
Currently, I see that it is possible to specify headers when initializing a transport (StreamableHTTP, etc.). However, it doesn’t seem possible to specify different headers once the client has been initialized.
To give a bit of context, I am developing an MCP proxy based on your great library. In my proxy’s case, I open one MCP client per MCP server I need to proxy, injecting headers that allow validating the “authentication” between my gateway and the proxied MCP servers.
From what I can see in your library, it is not possible to specify headers anywhere other than during the transport initialization. This seems unfortunate, as it prevents us from adding more context to the request, and opening a new transport for each call does not seem efficient.
Proposed Solution
Would a contribution allowing the specification of custom headers outside of the initialization (for example, in the sendRequest method) be of interest? If so, I’d be happy to contribute to the project.
Example Usage
// client.go // sendRequest sends a JSON-RPC request to the server and waits for a response. // Returns the raw JSON response message or an error if the request fails. func (c *Client) sendRequest( ctx context.Context, method string, params any, headers http.Header, ) (*json.RawMessage, error) { if !c.initialized && method != "initialize" { return nil, fmt.Errorf("client not initialized") } id := c.requestID.Add(1) request := transport.JSONRPCRequest{ JSONRPC: mcp.JSONRPC_VERSION, ID: mcp.NewRequestId(id), Method: method, Params: params, Header: headers, } response, err := c.transport.SendRequest(ctx, request) if err != nil { return nil, transport.NewError(err) } if response.Error != nil { return nil, errors.New(response.Error.Message) } return &response.Result, nil } ---- // streamable-http.go func (c *StreamableHTTP) sendHTTP( ctx context.Context, method string, body io.Reader, acceptType string, headers http.Header, ) (resp *http.Response, err error) { // Create HTTP request req, err := http.NewRequestWithContext(ctx, method, c.serverURL.String(), body) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } // custom headers req.Header = headers // Set headers req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", acceptType) sessionID := c.sessionID.Load().(string) if sessionID != "" { req.Header.Set(HeaderKeySessionID, sessionID) } // Set protocol version header if negotiated if v := c.protocolVersion.Load(); v != nil { if version, ok := v.(string); ok && version != "" { req.Header.Set(HeaderKeyProtocolVersion, version) } } // default headers for k, v := range c.headers { req.Header.Set(k, v) } ...
Alternatives/Workarounds Considered
Currently, you have to reopen a transport to adjust the headers being sent.