Skip to content

feature: Possibility to specify headers when calling a CallTool #544

@matthisholleville

Description

@matthisholleville

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions