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

  1. Re-acquire an access token that includes the missing scopes listed in the error message (printed after 'required:').
  2. Update the token request's scope parameter or the OAuth provider client configuration to grant the required scopes.
  3. If the tool's required scopes are wrong, adjust the tool's auth configuration (e.g. requires_scopes) to match your actual token scopes.
  4. 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

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


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/6c4aeca1ee5bc8a5. Report an issue: GitHub.