From 37e9875cbe0479311ee5a8431a24962535cc5abf Mon Sep 17 00:00:00 2001 From: Marvin Context Protocol <41898282+Marvin Context Protocol@users.noreply.github.com> Date: Sat, 21 Feb 2026 02:51:30 +0000 Subject: [PATCH 1/2] Exclude authorization header from get_http_headers() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #3260 Co-authored-by: Jeremiah Lowin 🤖 Generated with Claude Code --- src/fastmcp/server/dependencies.py | 4 +++ tests/server/http/test_http_dependencies.py | 36 +++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/fastmcp/server/dependencies.py b/src/fastmcp/server/dependencies.py index 15c8c3124..2770cc867 100644 --- a/src/fastmcp/server/dependencies.py +++ b/src/fastmcp/server/dependencies.py @@ -457,6 +457,10 @@ def get_http_headers(include_all: bool = False) -> dict[str, str]: "keep-alive", "expect", "accept", + # Auth headers — the MCP transport's credentials must not leak + # to downstream APIs (e.g. OpenAPI backends) which have their + # own authentication configured on the httpx client. + "authorization", # Proxy-related headers "proxy-authenticate", "proxy-authorization", diff --git a/tests/server/http/test_http_dependencies.py b/tests/server/http/test_http_dependencies.py index e637af269..de6c2d25c 100644 --- a/tests/server/http/test_http_dependencies.py +++ b/tests/server/http/test_http_dependencies.py @@ -166,3 +166,39 @@ async def test_get_http_headers_excludes_content_type(sse_server: str): # Custom headers should be included assert "x-custom-header" in headers assert headers["x-custom-header"] == "should-be-included" + + +async def test_get_http_headers_excludes_authorization(): + """Test that get_http_headers() excludes the authorization header (#3260). + + The MCP transport's auth credentials must not be forwarded to downstream + APIs (e.g. OpenAPI backends) which use their own authentication. + """ + from fastmcp.server.dependencies import get_http_headers + + server = FastMCP() + + @server.tool + def check_auth_header() -> dict[str, str]: + """Return filtered headers to verify authorization is excluded.""" + return get_http_headers() + + async with run_server_async(server, transport="sse") as url: + async with Client( + transport=SSETransport( + url, + headers={ + "Authorization": "Bearer mcp-client-token", + "X-Custom-Header": "should-be-included", + }, + ) + ) as client: + result = await client.call_tool("check_auth_header") + headers = result.data + + # Authorization header must be excluded + assert "authorization" not in headers + + # Custom headers should still be included + assert "x-custom-header" in headers + assert headers["x-custom-header"] == "should-be-included" From a99abe020fcd198781a72e58ca8f4f2c6d591f02 Mon Sep 17 00:00:00 2001 From: "marvin-context-protocol[bot]" <225465937+marvin-context-protocol[bot]@users.noreply.github.com> Date: Sat, 21 Feb 2026 02:53:08 +0000 Subject: [PATCH 2/2] chore: Update SDK documentation --- .../fastmcp-server-dependencies.mdx | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/python-sdk/fastmcp-server-dependencies.mdx b/docs/python-sdk/fastmcp-server-dependencies.mdx index 88a756ebc..55ab7ca19 100644 --- a/docs/python-sdk/fastmcp-server-dependencies.mdx +++ b/docs/python-sdk/fastmcp-server-dependencies.mdx @@ -169,7 +169,7 @@ By default, strips problematic headers like `content-length` that cause issues if forwarded to downstream clients. If `include_all` is True, all headers are returned. -### `get_access_token` +### `get_access_token` ```python get_access_token() -> AccessToken | None @@ -188,7 +188,7 @@ token snapshot stored in Redis at task submission time. - The access token if an authenticated user is available, None otherwise. -### `without_injected_parameters` +### `without_injected_parameters` ```python without_injected_parameters(fn: Callable[..., Any]) -> Callable[..., Any] @@ -213,7 +213,7 @@ Handles: - Async wrapper function without injected parameters -### `resolve_dependencies` +### `resolve_dependencies` ```python resolve_dependencies(fn: Callable[..., Any], arguments: dict[str, Any]) -> AsyncGenerator[dict[str, Any], None] @@ -239,7 +239,7 @@ time, so all injection goes through the unified DI system. which will be filtered out) -### `CurrentContext` +### `CurrentContext` ```python CurrentContext() -> Context @@ -258,7 +258,7 @@ current MCP operation (tool/resource/prompt call). - `RuntimeError`: If no active context found (during resolution) -### `CurrentDocket` +### `CurrentDocket` ```python CurrentDocket() -> Docket @@ -278,7 +278,7 @@ automatically creates for background task scheduling. - `ImportError`: If fastmcp[tasks] not installed -### `CurrentWorker` +### `CurrentWorker` ```python CurrentWorker() -> Worker @@ -298,7 +298,7 @@ automatically creates for background task processing. - `ImportError`: If fastmcp[tasks] not installed -### `CurrentFastMCP` +### `CurrentFastMCP` ```python CurrentFastMCP() -> FastMCP @@ -316,7 +316,7 @@ This dependency provides access to the active FastMCP server. - `RuntimeError`: If no server in context (during resolution) -### `CurrentRequest` +### `CurrentRequest` ```python CurrentRequest() -> Request @@ -336,7 +336,7 @@ current HTTP request. Only available when running over HTTP transports - `RuntimeError`: If no HTTP request in context (e.g., STDIO transport) -### `CurrentHeaders` +### `CurrentHeaders` ```python CurrentHeaders() -> dict[str, str] @@ -353,7 +353,7 @@ safe to use in code that might run over any transport. - A dependency that resolves to a dictionary of header name -> value -### `CurrentAccessToken` +### `CurrentAccessToken` ```python CurrentAccessToken() -> AccessToken @@ -372,7 +372,7 @@ authenticated request. Raises an error if no authentication is present. - `RuntimeError`: If no authenticated user (use get_access_token() for optional) -### `TokenClaim` +### `TokenClaim` ```python TokenClaim(name: str) -> str @@ -406,7 +406,7 @@ Returned by ``get_task_context()`` when running inside a Docket worker. Contains identifiers needed to communicate with the MCP session. -### `ProgressLike` +### `ProgressLike` Protocol for progress tracking interface. @@ -417,7 +417,7 @@ and Docket's Progress (worker context). **Methods:** -#### `current` +#### `current` ```python current(self) -> int | None @@ -426,7 +426,7 @@ current(self) -> int | None Current progress value. -#### `total` +#### `total` ```python total(self) -> int @@ -435,7 +435,7 @@ total(self) -> int Total/target progress value. -#### `message` +#### `message` ```python message(self) -> str | None @@ -444,7 +444,7 @@ message(self) -> str | None Current progress message. -#### `set_total` +#### `set_total` ```python set_total(self, total: int) -> None @@ -453,7 +453,7 @@ set_total(self, total: int) -> None Set the total/target value for progress tracking. -#### `increment` +#### `increment` ```python increment(self, amount: int = 1) -> None @@ -462,7 +462,7 @@ increment(self, amount: int = 1) -> None Atomically increment the current progress value. -#### `set_message` +#### `set_message` ```python set_message(self, message: str | None) -> None @@ -471,7 +471,7 @@ set_message(self, message: str | None) -> None Update the progress status message. -### `InMemoryProgress` +### `InMemoryProgress` In-memory progress tracker for immediate tool execution. @@ -483,25 +483,25 @@ progress doesn't need to be observable across processes. **Methods:** -#### `current` +#### `current` ```python current(self) -> int | None ``` -#### `total` +#### `total` ```python total(self) -> int ``` -#### `message` +#### `message` ```python message(self) -> str | None ``` -#### `set_total` +#### `set_total` ```python set_total(self, total: int) -> None @@ -510,7 +510,7 @@ set_total(self, total: int) -> None Set the total/target value for progress tracking. -#### `increment` +#### `increment` ```python increment(self, amount: int = 1) -> None @@ -519,7 +519,7 @@ increment(self, amount: int = 1) -> None Atomically increment the current progress value. -#### `set_message` +#### `set_message` ```python set_message(self, message: str | None) -> None @@ -528,7 +528,7 @@ set_message(self, message: str | None) -> None Update the progress status message. -### `Progress` +### `Progress` FastMCP Progress dependency that works in both server and worker contexts.