Control access to components using callable-based authorization checks that filter visibility and enforce permissions.
New in version 3.0.0Authorization controls what authenticated users can do with your FastMCP server. While authentication verifies identity (who you are), authorization determines access (what you can do). FastMCP provides a callable-based authorization system that works at both the component level and globally via middleware.The authorization model centers on a simple concept: callable functions that receive context about the current request and return True to allow access or False to deny it. Multiple checks combine with AND logic, meaning all checks must pass for access to be granted.
Authorization relies on OAuth tokens which are only available with HTTP transports (SSE, Streamable HTTP). In STDIO mode, there’s no OAuth mechanism, so get_access_token() returns None and all auth checks are skipped.
An auth check is any callable that accepts an AuthContext and returns a boolean. The AuthContext provides access to the current token (if any) and the component being accessed.
Copy
from fastmcp.server.auth import AuthContextdef my_custom_check(ctx: AuthContext) -> bool: # ctx.token is AccessToken | None # ctx.component is the Tool, Resource, or Prompt being accessed return ctx.token is not None and "special" in ctx.token.scopes
FastMCP provides three built-in auth checks that cover common authorization patterns.
For scope-based authorization, require_scopes checks that the token contains all specified OAuth scopes. When multiple scopes are provided, all must be present (AND logic).
Copy
from fastmcp import FastMCPfrom fastmcp.server.auth import require_scopesmcp = FastMCP("Scoped Server")@mcp.tool(auth=require_scopes("admin"))def admin_operation() -> str: """Requires the 'admin' scope.""" return "Admin action completed"@mcp.tool(auth=require_scopes("read", "write"))def read_write_operation() -> str: """Requires both 'read' AND 'write' scopes.""" return "Read/write action completed"
Tag-based restrictions apply scope requirements conditionally. If a component has the specified tag, the token must have the required scopes. Components without the tag are unaffected.
Copy
from fastmcp import FastMCPfrom fastmcp.server.auth import restrict_tagfrom fastmcp.server.middleware import AuthMiddlewaremcp = FastMCP( "Tagged Server", middleware=[ AuthMiddleware(auth=restrict_tag("admin", scopes=["admin"])) ])@mcp.tool(tags={"admin"})def admin_tool() -> str: """Tagged 'admin', so requires 'admin' scope.""" return "Admin only"@mcp.tool(tags={"public"})def public_tool() -> str: """Not tagged 'admin', so no scope required by the restriction.""" return "Anyone can access"
Any callable that accepts AuthContext and returns bool can serve as an auth check. This enables authorization logic based on token claims, component metadata, or external systems.
Copy
from fastmcp import FastMCPfrom fastmcp.server.auth import AuthContextmcp = FastMCP("Custom Auth Server")def require_premium_user(ctx: AuthContext) -> bool: """Check for premium user status in token claims.""" if ctx.token is None: return False return ctx.token.claims.get("premium", False) is Truedef require_access_level(minimum_level: int): """Factory function for level-based authorization.""" def check(ctx: AuthContext) -> bool: if ctx.token is None: return False user_level = ctx.token.claims.get("level", 0) return user_level >= minimum_level return check@mcp.tool(auth=require_premium_user)def premium_feature() -> str: """Only for premium users.""" return "Premium content"@mcp.tool(auth=require_access_level(5))def advanced_feature() -> str: """Requires access level 5 or higher.""" return "Advanced feature"
Auth checks can raise exceptions for explicit denial with custom messages:
AuthorizationError: Propagates with its custom message, useful for explaining why access was denied
Other exceptions: Masked for security (logged internally, treated as denial)
Copy
from fastmcp.server.auth import AuthContextfrom fastmcp.exceptions import AuthorizationErrordef require_verified_email(ctx: AuthContext) -> bool: """Require verified email with explicit denial message.""" if ctx.token is None: raise AuthorizationError("Authentication required") if not ctx.token.claims.get("email_verified"): raise AuthorizationError("Email verification required") return True
The auth parameter on decorators controls visibility of individual components. When auth checks fail for the current request, the component is hidden from list responses—it simply doesn’t appear.
Copy
from fastmcp import FastMCPfrom fastmcp.server.auth import require_auth, require_scopesmcp = FastMCP("Component Auth Server")@mcp.tool(auth=require_auth)def authenticated_tool() -> str: """Only visible to authenticated users.""" return "Authenticated"@mcp.resource("secret://data", auth=require_scopes("read"))def secret_resource() -> str: """Only visible to users with 'read' scope.""" return "Secret data"@mcp.prompt(auth=require_scopes("admin"))def admin_prompt() -> str: """Only visible to users with 'admin' scope.""" return "Admin prompt content"
Component-level auth only controls visibility in list operations. It does not block direct access. Use AuthMiddleware to enforce authorization on execution.
For server-wide authorization enforcement, use AuthMiddleware. This middleware applies auth checks globally to all components—filtering list responses and blocking unauthorized execution.
Copy
from fastmcp import FastMCPfrom fastmcp.server.auth import require_authfrom fastmcp.server.middleware import AuthMiddlewaremcp = FastMCP( "Enforced Auth Server", middleware=[AuthMiddleware(auth=require_auth)])@mcp.tooldef any_tool() -> str: """Requires authentication to see AND call.""" return "Protected"
Component-level auth is useful for hiding components from unauthorized users while still allowing advanced clients to access them directly. AuthMiddleware provides complete enforcement by raising AuthorizationError when unauthorized requests attempt execution.
Tools can access the current authentication token using get_access_token() from fastmcp.server.dependencies. This enables tools to make decisions based on user identity or permissions beyond simple authorization checks.
Copy
from fastmcp import FastMCPfrom fastmcp.server.dependencies import get_access_tokenmcp = FastMCP("Token Access Server")@mcp.tooldef personalized_greeting() -> str: """Greet the user based on their token claims.""" token = get_access_token() if token is None: return "Hello, guest!" name = token.claims.get("name", "user") return f"Hello, {name}!"@mcp.tooldef user_dashboard() -> dict: """Return user-specific data based on token.""" token = get_access_token() if token is None: return {"error": "Not authenticated"} return { "client_id": token.client_id, "scopes": token.scopes, "claims": token.claims, }
The AuthContext dataclass is passed to all auth check functions.
Property
Type
Description
token
AccessToken | None
Current access token, or None if unauthenticated
component
Tool | Resource | Prompt
The component being accessed
Access to the component object enables authorization decisions based on metadata like tags, name, or custom properties.
Copy
from fastmcp.server.auth import AuthContextdef require_matching_tag(ctx: AuthContext) -> bool: """Require a scope matching each of the component's tags.""" if ctx.token is None: return False user_scopes = set(ctx.token.scopes) return ctx.component.tags.issubset(user_scopes)