Description
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
- Manually patching
fastapi_mcp/server.py
: This is our current workaround but is not sustainable. - Attempting to modify
http_request_info
before it reaches_execute_api_tool
: This is complex and involves internal details of themcp
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.