Skip to content

feat: add support for custom HTTP headers in StreamableHttpClient#655

Merged
alexhancock merged 2 commits intomodelcontextprotocol:mainfrom
Arichy:feat/reqwest-support-custom-headers
Feb 13, 2026
Merged

feat: add support for custom HTTP headers in StreamableHttpClient#655
alexhancock merged 2 commits intomodelcontextprotocol:mainfrom
Arichy:feat/reqwest-support-custom-headers

Conversation

@Arichy
Copy link
Contributor

@Arichy Arichy commented Feb 13, 2026

This PR adds support for custom HTTP headers in the StreamableHttpClient transport, allowing users to pass additional headers when connecting to remote MCP servers.

Motivation and Context

When connecting to the GitHub MCP server remotely, custom headers are required to filter and control server behavior. Specifically, the GitHub MCP server uses the X-MCP-Toolsets header to allow clients to specify which toolsets to load (e.g., X-MCP-Toolsets: issues to only load issue-related tools).

Reference: https://github.com/github/github-mcp-server/blob/main/docs/remote-server.md

The Rust SDK did not previously support custom headers, making it impossible to use these filtering capabilities. This PR addresses that limitation by adding custom header support to the StreamableHttpClient transport configuration.

How Has This Been Tested?

  • Unit tests: Added tests for configuration API, including default behavior, single/multiple headers, and interaction with existing auth_header
  • Integration test: Added end-to-end test that spins up a test HTTP server and verifies custom headers are correctly sent in MCP protocol requests
  • Test scenarios:
    • Default empty headers (backward compatibility)
    • Single custom header
    • Multiple custom headers
    • Custom headers combined with auth_header
    • Headers sent during initialize, initialized notification, and regular requests

All tests pass locally with just test.

Breaking Changes

None. This is a fully backward-compatible addition. Existing code continues to work without modification, as custom headers default to an empty HashMap.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Implementation details:

  • Added custom_headers: HashMap<HeaderName, HeaderValue> field to StreamableHttpClientTransportConfig
  • Added custom_headers() builder method for fluent API configuration
  • Updated StreamableHttpClient trait's post_message method signature to accept custom headers
  • Modified reqwest implementation to apply custom headers to all HTTP requests
  • Updated auth client wrapper to forward custom headers

Example usage:

use std::collections::HashMap;
use http::{HeaderName, HeaderValue};
use rmcp::transport::streamable_http_client::StreamableHttpClientTransportConfig;

// Configure custom headers for GitHub MCP server
let mut headers = HashMap::new();
headers.insert(
    HeaderName::from_static("x-mcp-toolsets"),
    HeaderValue::from_static("issues")
);

let config = StreamableHttpClientTransportConfig::with_uri("https://mcp.github.com")
    .custom_headers(headers);

@github-actions github-actions bot added T-dependencies Dependencies related changes T-test Testing related changes T-config Configuration file changes T-core Core library changes T-transport Transport layer changes labels Feb 13, 2026
@alexhancock alexhancock self-requested a review February 13, 2026 15:28
Copy link
Contributor

@alexhancock alexhancock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea - thanks for the contribution. I left one recommendation in the code.

request = request.bearer_auth(auth_header);
}
// Apply custom headers
for (name, value) in custom_headers {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps disallow any of the headers that are controlled by the default client logic?

ACCEPT HEADER_SESSION_ID etc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would check https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#streamable-http for a full list

MCP-Protocol-Version is another one that comes to mind

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I've updated the PR to add the check.

@alexhancock alexhancock merged commit 016b7d3 into modelcontextprotocol:main Feb 13, 2026
11 checks passed
@alexhancock
Copy link
Contributor

Nice one @Arichy - thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-config Configuration file changes T-core Core library changes T-dependencies Dependencies related changes T-test Testing related changes T-transport Transport layer changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants