From 99f27da0883a42f604ad87e24debb536249e0817 Mon Sep 17 00:00:00 2001 From: itaru2622 <70509350+itaru2622@users.noreply.github.com> Date: Sat, 26 Jul 2025 00:04:41 +0900 Subject: [PATCH] fix: experimental FastMCPOpenAPI server lost headers in request when __init__(client with headers) (#1254) --- .../experimental/server/openapi/components.py | 26 +++++++++++++++++++ .../server/openapi/test_comprehensive.py | 4 +++ 2 files changed, 30 insertions(+) diff --git a/src/fastmcp/experimental/server/openapi/components.py b/src/fastmcp/experimental/server/openapi/components.py index f8a241330..f7720746b 100644 --- a/src/fastmcp/experimental/server/openapi/components.py +++ b/src/fastmcp/experimental/server/openapi/components.py @@ -68,6 +68,13 @@ class OpenAPITool(Tool): else "http://localhost" ) + # Get Headers from client + cli_headers = ( + self._client.headers + if hasattr(self._client, "headers") and self._client.headers + else {} + ) + # Build the request using RequestDirector request = self._director.build(self._route, arguments, base_url) @@ -82,6 +89,17 @@ class OpenAPITool(Tool): for key, value in mcp_headers.items(): request.headers[key] = value + if cli_headers: + # Merge with existing headers, _client headers take precedence + if request.headers: + request.headers.update(cli_headers) + else: + # Create new headers from cli_headers + for key, value in cli_headers.items(): + request.headers[key] = value + # print logger + logger.debug(f"run - sending request; headers: {request.headers}") + # Execute the request # Note: httpx.AsyncClient.send() doesn't accept timeout parameter # The timeout should be configured on the client itself @@ -210,6 +228,14 @@ class OpenAPIResource(Resource): headers = {} mcp_headers = get_http_headers() headers.update(mcp_headers) + # Get Headers from client + cli_headers = ( + self._client.headers + if hasattr(self._client, "headers") and self._client.headers + else {} + ) + # Merge with existing headers, _client headers take precedence + headers.update(cli_headers) response = await self._client.request( method=self._route.method, diff --git a/tests/experimental/server/openapi/test_comprehensive.py b/tests/experimental/server/openapi/test_comprehensive.py index 187180252..c613cd0a0 100644 --- a/tests/experimental/server/openapi/test_comprehensive.py +++ b/tests/experimental/server/openapi/test_comprehensive.py @@ -468,6 +468,7 @@ class TestOpenAPIComprehensive: # Create a mock client that tracks requests mock_client = Mock(spec=httpx.AsyncClient) mock_client.base_url = "https://api.example.com" + mock_client.headers = None # Mock successful response mock_response = Mock(spec=Response) @@ -509,6 +510,7 @@ class TestOpenAPIComprehensive: """Test complex request with both parameters and body.""" mock_client = Mock(spec=httpx.AsyncClient) mock_client.base_url = "https://api.example.com" + mock_client.headers = None mock_response = Mock(spec=Response) mock_response.status_code = 201 @@ -557,6 +559,7 @@ class TestOpenAPIComprehensive: """Test query parameter handling.""" mock_client = Mock(spec=httpx.AsyncClient) mock_client.base_url = "https://api.example.com" + mock_client.headers = None mock_response = Mock(spec=Response) mock_response.status_code = 200 @@ -595,6 +598,7 @@ class TestOpenAPIComprehensive: """Test error handling for HTTP errors.""" mock_client = Mock(spec=httpx.AsyncClient) mock_client.base_url = "https://api.example.com" + mock_client.headers = None # Mock HTTP error response mock_response = Mock(spec=Response)