Skip to content

OpenAPI tool forwards MCP transport auth headers to downstream APIs #3260

Description

@aaazzam

Summary

When an MCP server is created with FastMCP.from_openapi() and served over Streamable HTTP, the get_http_headers() call in OpenAPITool.run() forwards the incoming MCP transport's Authorization header to the downstream API, overwriting the API key configured on the httpx client.

This means the downstream API receives the MCP client's auth token instead of the intended API key, causing auth failures (503/401/403).

Root cause

In fastmcp/server/providers/openapi/components.py lines 173-175:

mcp_headers = get_http_headers()
if mcp_headers:
    request.headers.update(mcp_headers)

get_http_headers() extracts headers from the current MCP HTTP request context and forwards them. The authorization header is not in the exclude_headers set in dependencies.py, and .update() overwrites any existing headers — including the Authorization header that was already set from the httpx client's configured headers.

Minimal reproduction

# server.py
import json, os, httpx
from fastmcp import FastMCP

# Any OpenAPI spec will do
spec = json.loads(open("openapi.json").read())

backend = FastMCP.from_openapi(
    openapi_spec=spec,
    client=httpx.AsyncClient(
        base_url="https://api.example.com",
        headers={"Authorization": f"Bearer {os.environ['MY_API_KEY']}"},
    ),
    name="My API",
)

backend.run(transport="streamable-http")

When a client connects over Streamable HTTP with its own auth header (e.g. Claude Code, or any MCP client authenticating with the server), that auth header gets forwarded to api.example.com, replacing MY_API_KEY.

This does not happen when:

  • The server runs over stdio (no HTTP request context, get_http_headers() returns {})
  • You call backend.call_tool() directly in-process without an MCP HTTP context

Suggested fix

Add "authorization" to the exclude_headers set in get_http_headers():

exclude_headers = {
    "host",
    "content-length",
    "content-type",
    "connection",
    "transfer-encoding",
    "upgrade",
    "te",
    "keep-alive",
    "expect",
    "accept",
    "authorization",  # <-- add this
    # ...
}

Or alternatively, don't forward MCP transport headers to OpenAPI downstream requests by default.

Environment

  • fastmcp 3.0.0
  • httpx 0.28.1
  • Python 3.13

Metadata

Metadata

Assignees

No one assigned

    Labels

    authRelated to authentication (Bearer, JWT, OAuth, WorkOS) for client or server.bugSomething isn't working. Reports of errors, unexpected behavior, or broken functionality.httpRelated to HTTP transport, networking, or web server functionality.openapiRelated to OpenAPI integration, parsing, or code generation features.potential-duplicateBot-suggested duplicate awaiting human review. Auto-closes after 3 days if unchallenged.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions