PrefectHQ/fastmcp · error · InsufficientScopeError
Authorization failed for tool '{tool_name}': insufficient sc
Error message
Authorization failed for tool '{tool_name}': insufficient scope (required: {', '.join(missing)}) What it means
The caller's token passed all existence checks but the auth provider's checks returned unauthorized with a non-empty shortfall of missing scopes. AuthMiddleware converts that into InsufficientScopeError listing the required scopes (after chaining shortfalls via _chain_shortfall), following RFC 6750 insufficient_scope semantics.
Source
Thrown at fastmcp_slim/fastmcp/server/middleware/authorization.py:243
# 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)
authorized, missing = await run_auth_checks_with_shortfall(self.auth, ctx)
if not authorized:
if missing:
missing = self._chain_shortfall(missing, ctx, fastmcp.fastmcp)
raise InsufficientScopeError(
missing,
message=(
f"Authorization failed for tool '{tool_name}': "
f"insufficient scope (required: {', '.join(missing)})"
),
)
raise AuthorizationError(
f"Authorization failed for tool '{tool_name}': insufficient permissions"
)
return await call_next(context)
async def on_list_resources(
self,
context: MiddlewareContext[mt.ListResourcesRequest],
call_next: CallNext[mt.ListResourcesRequest, Sequence[Resource]],
) -> Sequence[Resource]:
"""Filter resources/list response based on auth checks."""View on GitHub (pinned to 1f02114297)
Solutions
- Re-acquire an access token that includes the missing scopes listed in the error message (printed after 'required:').
- Update the token request's scope parameter or the OAuth provider client configuration to grant the required scopes.
- If the tool's required scopes are wrong, adjust the tool's auth configuration (e.g. requires_scopes) to match your actual token scopes.
- Verify scope naming/claims mapping (SCOPE claim, audience) between your identity provider and the FastMCP auth server configuration.
Example fix
# before
token = get_token(client_id, scopes=['read'])
result = await client.call_tool('deploy', {...}) # requires 'deploy:write'
# after
token = get_token(client_id, scopes=['read', 'deploy:write'])
result = await client.call_tool('deploy', {...}) Defensive patterns
Strategy: try-catch
Validate before calling
# client-side: ensure requested scopes are granted before calling
claims = decode_jwt(token) # provider-specific
required = {'deploy:write'}
assert required.issubset(set(claims.get('scope', '').split())), 'token missing scopes' Try / catch
from fastmcp.exceptions import InsufficientScopeError
try:
result = await client.call_tool('deploy', args)
except InsufficientScopeError as e:
missing = getattr(e, 'missing_scopes', None) or parse_scopes(str(e))
token = await auth_provider.refresh_with_scopes(missing)
client.set_auth(BearerAuth(token))
result = await client.call_tool('deploy', args) Prevention
- Request all scopes the protected components require when obtaining tokens.
- Handle insufficient_scope responses with a scope-upgrade (re-auth) flow instead of retrying blindly.
- Keep scope names consistent between the auth provider and tool/resource auth config.
- Decode and inspect tokens in staging before deploying scope changes.
When it happens
Trigger: tools/call for a tool whose configured required scopes (tool-level or global auth policy) are not fully satisfied by the access token — e.g. token has 'read' but the tool requires 'read' and 'write'.
Common situations: Downscoped or expired OAuth tokens; JWT issued by a provider without the scope attached to the tool's auth config; switching auth providers so scope names changed (e.g. 'admin' vs 'tools:admin'); test-client tokens missing production scopes.
Related errors
- Authorization failed for resource '{uri}': insufficient scop
- Assertion must include exp claim
- Assertion must include sub claim
- Assertion missing required scopes: {sorted(missing)}
- Assertion must include a string jti claim
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/6c4aeca1ee5bc8a5.
Report an issue: GitHub.