PrefectHQ/fastmcp · error · AuthorizationError
Authorization failed for tool '{tool_name}': missing context
Error message
Authorization failed for tool '{tool_name}': missing context What it means
AuthMiddleware.on_call_tool fails closed: if `context.fastmcp_context` is None when a tools/call arrives, it cannot run authorization checks, so it denies the request with an AuthorizationError rather than allowing it. This is a defense-in-depth guard — the request reached the middleware without the request-scoped FastMCP Context that normal transports establish.
Source
Thrown at fastmcp_slim/fastmcp/server/middleware/authorization.py:220
) -> ToolResult:
"""Check auth before tool execution."""
# STDIO has no auth concept, skip enforcement
# Late import to avoid circular import with context.py
from fastmcp.server.context import _current_transport
if _current_transport.get() == "stdio":
return await call_next(context)
# Get the tool being called
tool_name = context.message.name
fastmcp = context.fastmcp_context
if fastmcp is None:
# Fail closed: deny access when context is missing
logger.warning(
f"AuthMiddleware: fastmcp_context is None for tool '{tool_name}'. "
"Denying access for security."
)
raise AuthorizationError(
f"Authorization failed for tool '{tool_name}': missing context"
)
# get_tool returns None both when the tool does not exist and when
# component-level auth denied access, so the two cases are
# indistinguishable here. Keep the message ambiguous to avoid
# disclosing existence of tools the caller is not authorized to see.
version = _requested_version(context.message.meta)
tool = await fastmcp.fastmcp.get_tool(tool_name, version=version)
if tool is None:
raise AuthorizationError(
f"Authorization failed for tool '{tool_name}': "
"not found or not authorized"
)
# Global auth check
token = get_access_token()
ctx = AuthContext(token=token, component=tool)View on GitHub (pinned to 1f02114297)
Solutions
- Route the call through the normal server dispatch (client -> server) so FastMCP establishes the request Context, instead of invoking middleware directly.
- In tests, build the context properly: `async with Context(fastmcp=mcp, session=...) as ctx:` and pass `fastmcp_context=ctx` into MiddlewareContext.
- If you have a custom transport, ensure it wraps handler execution in a FastMCP Context as the built-in transports do.
- Confirm the transport is detected correctly — requests with _current_transport unset/not stdio still require auth context.
Example fix
# before (test)
ctx = MiddlewareContext(message=params, fastmcp_context=None)
await mw.on_call_tool(ctx, call_next) # AuthorizationError: missing context
# after
async with Context(fastmcp=mcp, session=session) as fctx:
ctx = MiddlewareContext(message=params, fastmcp_context=fctx)
await mw.on_call_tool(ctx, call_next) Defensive patterns
Strategy: try-catch
Validate before calling
from fastmcp.server.context import Context
async with Context(fastmcp=mcp, session=session) as fctx:
assert fctx is not None, 'middleware requires a FastMCP context' Try / catch
from fastmcp.exceptions import AuthorizationError
try:
result = await client.call_tool('my_tool', {'arg': 1})
except AuthorizationError as e:
if 'missing context' in str(e):
logger.error('Request bypassed context establishment; fix transport/test harness')
else:
raise Prevention
- Always dispatch requests through the client/server transport stack, never straight into middleware.
- In tests, use Context(fastmcp=..., session=...) when building MiddlewareContext.
- Keep custom transports in sync with FastMCP's context-establishment pattern after upgrades.
- Treat 'missing context' warnings in logs as harness bugs, not auth policy issues.
When it happens
Trigger: Calling a tool over a non-stdio transport while the middleware pipeline runs without a populated fastmcp_context — requests injected directly into the middleware stack in tests, custom transports/handlers that bypass `Context` setup, or middleware wrapping that loses the request context. STDIO is exempted earlier, so this only happens on HTTP/SSE-style transports.
Common situations: Integration tests that invoke `middleware.on_call_tool` with a hand-built MiddlewareContext lacking fastmcp_context; embedding the low-level server in a custom ASGI app that doesn't establish FastMCP's request context; upgrading FastMCP so custom transport glue no longer populates the context.
Related errors
- Authorization failed for resource '{uri}': missing context
- Authorization failed for prompt '{prompt_name}': missing con
- Authorization failed for tool '{tool_name}': not found or no
- Authorization failed for tool '{tool_name}': insufficient pe
- Authorization failed for resource '{uri}': not found or not
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/320b3b67b5fe5ecd.
Report an issue: GitHub.