PrefectHQ/fastmcp · error · InsufficientScopeError

Authorization failed for resource '{uri}': insufficient scop

Error message

Authorization failed for resource '{uri}': insufficient scope (required: {', '.join(missing)})

What it means

The resource/template was found but the global auth checks returned unauthorized with a non-empty shortfall of missing scopes. The middleware raises InsufficientScopeError naming the required scopes (post _chain_shortfall) so clients can perform scope-upgrade flows (RFC 6750 insufficient_scope).

Source

Thrown at fastmcp_slim/fastmcp/server/middleware/authorization.py:331

        if component is None:
            component = await fastmcp.fastmcp.get_resource_template(
                str(uri),
                version=version,
            )
        if component is None:
            raise AuthorizationError(
                f"Authorization failed for resource '{uri}': "
                "not found or not authorized"
            )

        # Global auth check
        token = get_access_token()
        ctx = AuthContext(token=token, component=component)
        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 resource '{uri}': "
                        f"insufficient scope (required: {', '.join(missing)})"
                    ),
                )
            raise AuthorizationError(
                f"Authorization failed for resource '{uri}': insufficient permissions"
            )

        return await call_next(context)

    async def on_list_resource_templates(
        self,
        context: MiddlewareContext[mt.ListResourceTemplatesRequest],
        call_next: CallNext[
            mt.ListResourceTemplatesRequest, Sequence[ResourceTemplate]
        ],

View on GitHub (pinned to 1f02114297)

Solutions

  1. Re-obtain a token containing every scope listed after 'required:' in the message.
  2. Adjust the OAuth client's requested scopes or provider config so issued tokens include them.
  3. If the resource's scope requirements are wrong, update its auth configuration (requires_scopes / auth policy) in code.
  4. Validate claim mapping (SCOPE claim, audience) between the identity provider and the FastMCP auth server.

Example fix

# before
token = get_token(scopes=['data:read'])
await client.read_resource('pii://users/1')  # requires pii:read
# after
token = get_token(scopes=['data:read', 'pii:read'])
await client.read_resource('pii://users/1')
Defensive patterns

Strategy: try-catch

Validate before calling

claims = decode_jwt(token)
have = set(claims.get('scope', '').split())
assert {'data:read', 'pii:read'}.issubset(have), 'token missing resource scopes'

Try / catch

from fastmcp.exceptions import InsufficientScopeError
try:
    res = await client.read_resource(uri)
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))
    res = await client.read_resource(uri)

Prevention

When it happens

Trigger: resources/read for a registered resource whose required scopes (resource-level or global policy) are not all present in the access token — e.g. token has 'data:read' but the resource requires 'data:read' plus 'pii:read'.

Common situations: OAuth tokens downscoped or issued before new scopes were added to the resource; scope naming drift after switching auth providers; service accounts missing newly-required scopes; test tokens without production scopes.

Related errors


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