Documentation Index Fetch the complete documentation index at: https://mintlify.com/punkpeye/fastmcp/llms.txt
Use this file to discover all available pages before exploring further.
FastMCP provides flexible authentication options to secure your MCP server, from simple API keys to full OAuth 2.1 flows with pre-configured providers.
The simplest way to add OAuth is using the auth option with a pre-configured provider:
import { FastMCP , getAuthSession , GoogleProvider , requireAuth } from "fastmcp" ;
const server = new FastMCP ({
auth: new GoogleProvider ({
baseUrl: "https://your-server.com" ,
clientId: process . env . GOOGLE_CLIENT_ID ! ,
clientSecret: process . env . GOOGLE_CLIENT_SECRET ! ,
}),
name: "My Server" ,
version: "1.0.0" ,
});
server . addTool ({
canAccess: requireAuth ,
description: "Get user profile" ,
execute : async ( _args , { session }) => {
const { accessToken } = getAuthSession ( session );
const response = await fetch (
"https://www.googleapis.com/oauth2/v2/userinfo" ,
{
headers: { Authorization: `Bearer ${ accessToken } ` },
},
);
return JSON . stringify ( await response . json ());
},
name: "get-profile" ,
});
Available Providers
Google
GitHub
Azure
Custom Provider
import { GoogleProvider } from "fastmcp" ;
const server = new FastMCP ({
auth: new GoogleProvider ({
baseUrl: "https://your-server.com" ,
clientId: process . env . GOOGLE_CLIENT_ID ! ,
clientSecret: process . env . GOOGLE_CLIENT_SECRET ! ,
scopes: [ "openid" , "profile" , "email" ],
}),
name: "My Server" ,
version: "1.0.0" ,
});
Control which tools are available to authenticated users using the canAccess property with built-in helper functions:
Require Authentication
import { requireAuth } from "fastmcp" ;
server . addTool ({
canAccess: requireAuth , // Only authenticated users
name: "user-tool" ,
execute : async () => "Authenticated!" ,
});
Require Specific Scopes
import { requireScopes } from "fastmcp" ;
server . addTool ({
canAccess: requireScopes ( "read:user" , "write:data" ),
name: "scoped-tool" ,
execute : async () => "Access granted!" ,
});
Require Specific Role
import { requireRole } from "fastmcp" ;
server . addTool ({
canAccess: requireRole ( "admin" ),
name: "admin-tool" ,
execute : async () => "Welcome, admin!" ,
});
Combine Requirements
AND Logic
OR Logic
Custom Logic
import { requireAll , requireAuth , requireRole } from "fastmcp" ;
server . addTool ({
canAccess: requireAll ( requireAuth , requireRole ( "admin" )),
name: "admin-only" ,
execute : async () => "Full access!" ,
});
Access Session Data
Use getAuthSession for type-safe access to the OAuth session in your tool execute functions:
import { getAuthSession , GoogleSession } from "fastmcp" ;
server . addTool ({
canAccess: requireAuth ,
name: "get-profile" ,
execute : async ( _args , { session }) => {
// Type-safe destructuring (throws if not authenticated)
const { accessToken } = getAuthSession ( session );
// Or with provider-specific typing:
// const { accessToken } = getAuthSession<GoogleSession>(session);
const response = await fetch ( "https://api.example.com/user" , {
headers: { Authorization: `Bearer ${ accessToken } ` },
});
return JSON . stringify ( await response . json ());
},
});
You can also access session.accessToken directly, but you must handle the case where session is undefined. The getAuthSession helper throws a clear error if the session is not authenticated, making it safer when used with canAccess: requireAuth.
Custom Authentication
For non-OAuth scenarios like API keys or custom tokens, use the authenticate option:
const server = new FastMCP ({
name: "My Server" ,
version: "1.0.0" ,
authenticate : ( request ) => {
const apiKey = request . headers [ "x-api-key" ];
if ( apiKey !== "123" ) {
throw new Response ( null , {
status: 401 ,
statusText: "Unauthorized" ,
});
}
return { id: 1 , role: "user" };
},
});
server . addTool ({
name: "sayHello" ,
execute : async ( args , { session }) => {
return `Hello, ${ session . id } !` ;
},
});
OAuth Discovery Endpoints
FastMCP supports OAuth discovery endpoints for direct integration with OAuth providers, supporting both MCP Specification 2025-03-26 and MCP Specification 2025-06-18 :
import { FastMCP , DiscoveryDocumentCache } from "fastmcp" ;
import { buildGetJwks } from "get-jwks" ;
import fastJwt from "fast-jwt" ;
const discoveryCache = new DiscoveryDocumentCache ({
ttl: 3600000 , // Cache for 1 hour
});
const server = new FastMCP ({
name: "My Server" ,
version: "1.0.0" ,
oauth: {
enabled: true ,
authorizationServer: {
issuer: "https://auth.example.com" ,
authorizationEndpoint: "https://auth.example.com/oauth/authorize" ,
tokenEndpoint: "https://auth.example.com/oauth/token" ,
jwksUri: "https://auth.example.com/.well-known/jwks.json" ,
responseTypesSupported: [ "code" ],
},
protectedResource: {
resource: "mcp://my-server" ,
authorizationServers: [ "https://auth.example.com" ],
},
},
authenticate : async ( request ) => {
const authHeader = request . headers . authorization ;
if ( ! authHeader ?. startsWith ( "Bearer " )) {
throw new Response ( null , {
status: 401 ,
statusText: "Missing or invalid authorization header" ,
});
}
const token = authHeader . slice ( 7 );
try {
const config = ( await discoveryCache . get (
"https://auth.example.com/.well-known/openid-configuration"
)) as {
jwks_uri : string ;
issuer : string ;
};
const getJwks = buildGetJwks ({
jwksUrl: config . jwks_uri ,
cache: true ,
rateLimit: true ,
});
const verify = fastJwt . createVerifier ({
key : async ( token ) => {
const { header } = fastJwt . decode ( token , { complete: true });
const jwk = await getJwks . getJwk ({
kid: header . kid ,
alg: header . alg ,
});
return jwk ;
},
algorithms: [ "RS256" , "ES256" ],
issuer: config . issuer ,
audience: "mcp://my-server" ,
});
const payload = await verify ( token );
return {
userId: payload . sub ,
scope: payload . scope ,
email: payload . email ,
};
} catch ( error ) {
throw new Response ( null , {
status: 401 ,
statusText: "Invalid OAuth token" ,
});
}
},
});
This configuration automatically exposes OAuth discovery endpoints:
/.well-known/oauth-authorization-server - Authorization server metadata (RFC 8414)
/.well-known/oauth-protected-resource - Protected resource metadata (RFC 9728)
/.well-known/oauth-protected-resource<endpoint> - Protected resource metadata at sub-path
Helper Functions Reference
Function Description Example requireAuthRequires any authenticated user canAccess: requireAuthrequireScopes(...scopes)Requires specific OAuth scopes canAccess: requireScopes("read:user")requireRole(...roles)Requires specific role canAccess: requireRole("admin")requireAll(...checks)Combines checks with AND logic canAccess: requireAll(requireAuth, requireRole("admin"))requireAny(...checks)Combines checks with OR logic canAccess: requireAny(requireRole("admin"), requireRole("moderator"))getAuthSession(session)Type-safe session extraction const { accessToken } = getAuthSession(session)
Next Steps
OAuth Proxy Learn about the built-in OAuth Proxy with DCR, PKCE, and token swap
Custom Routes Add authenticated custom HTTP routes to your server