Skip to content

Feature Request: Allow _execute_api_tool to source Authorization header from tool arguments for internal clients #143

Open
@stepolan

Description

@stepolan

Is your feature request related to a problem? Please describe.
Currently, when fastapi-mcp's _execute_api_tool method in server.py makes an internal HTTP request to execute a FastAPI tool endpoint, it primarily looks for an Authorization header within the http_request_info.headers that it receives. This works well for external MCP clients that pass the Authorization header directly.

However, in scenarios involving internal MCP clients (e.g., a backend service within the same application making a tool call via an MCPClientSession), the original end-user's authentication token might be more conveniently passed through the arguments of the call_tool request, rather than re-constructing HTTP headers for the internal call.

In our application, a service acts as an internal MCP client. It extracts the Bearer token from the initial HTTP request's Authorization header and includes it in the arguments dictionary (e.g., as user_access_token) when calling MCPClientSession.call_tool(). The current fastapi-mcp (version 0.3.3) does not automatically pick up this token from the arguments to authenticate the subsequent internal request to the tool's actual FastAPI endpoint, leading to authentication failures for the tool if it's protected.

Describe the solution you'd like
Enhance the _execute_api_tool method in fastapi_mcp/server.py to check the arguments dictionary for a specific token key (e.g., user_access_token) if an Authorization header is not already present in http_request_info.headers. If found, this token would be used to construct a Bearer token and set the Authorization header for the httpx.AsyncClient request made to the tool's endpoint.

Describe alternatives you've considered

  1. Manually patching fastapi_mcp/server.py: This is our current workaround but is not sustainable.
  2. Attempting to modify http_request_info before it reaches _execute_api_tool: This is complex and involves internal details of the mcp library.

Proposed Code Change (Illustrative):
This is the patch I have successfully used locally. It's added within the _execute_api_tool method in fastapi_mcp/server.py, just before the httpx.AsyncClient is used:

# ... existing code in _execute_api_tool ...

        if http_request_info and http_request_info.headers:
            if "Authorization" in http_request_info.headers:
                headers["Authorization"] = http_request_info.headers["Authorization"]
            elif "authorization" in http_request_info.headers:
                headers["Authorization"] = http_request_info.headers["authorization"]

        # NEW: Check arguments for a user_access_token if Authorization header is still missing
        if "Authorization" not in headers and arguments and "user_access_token" in arguments:
            token = arguments.pop("user_access_token", None) # Remove it from arguments so it doesn't become body
            if token:
                headers["Authorization"] = f"Bearer {token}"
                logger.debug("Set Authorization header from 'user_access_token' in tool arguments.")

# Existing code...

        body = arguments if arguments else None

        try:
            logger.debug(f"Making {method.upper()} request to {path}")
            response = await self._request(client, method, path, query, headers, body)

(Self-correction during drafting: Used .get() for safer dictionary access and added a type check for the token. Also considered whether to pop the token from arguments, deciding it's often better not to unless a name collision is likely.)

Additional context
This change would make fastapi-mcp more flexible for internal tool usage patterns where direct header manipulation by the immediate internal client is less convenient than passing auth details via arguments. It also maintains the priority of an explicitly passed Authorization header if present.

Thank you for considering this feature.

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