Class: MCPAuth
The main class of the mcp-auth library, providing the two inputs the MCP TypeScript SDK asks you to bring when protecting an MCP server — one method each:
- A token verifier — the instance itself implements the SDK's
OAuthTokenVerifierinterface, and getBearerAuthOptions bundles it with the resource metadata URL into the SDK'sBearerAuthOptions, ready to feed torequireBearerAuth(fetch-native or any of its framework adapters). - Your auth metadata — getAuthMetadataOptions returns the SDK's
AuthMetadataOptions, ready to feed tooauthMetadataResponse(fetch-native) ormcpAuthMetadataRouter(from@modelcontextprotocol/express).
One instance represents one protected resource trusting one authorization server. Create multiple instances if your deployment serves multiple resources.
Example
Fetch-native runtimes (Cloudflare Workers, Deno, Bun, Node.js)
import { createMcpHandler, McpServer, oauthMetadataResponse, requireBearerAuth } from '@modelcontextprotocol/server';
import { getAuthInfo, MCPAuth } from 'mcp-auth';
const mcpAuth = new MCPAuth({
protectedResourceMetadata: {
resource: 'https://api.example.com/mcp',
authorizationServer: { issuer: 'https://auth.example.com/oidc', type: 'oidc' },
scopesSupported: ['read:notes'],
},
});
const createServer = () => {
const server = new McpServer({ name: 'Notes', version: '1.0.0' });
server.registerTool('whoami', { description: 'Get the current user' }, (ctx) => {
const { subject, claims } = getAuthInfo(ctx);
return { content: [{ type: 'text', text: JSON.stringify({ subject, claims }) }] };
});
return server;
};
const handler = createMcpHandler(createServer);
const gate = requireBearerAuth(mcpAuth.getBearerAuthOptions({ requiredScopes: ['read:notes'] }));
export default {
async fetch(request: Request): Promise<Response> {
// Serve the OAuth discovery documents; the path guard keeps the (lazily fetched)
// metadata resolution off the request path of regular MCP traffic
if (new URL(request.url).pathname.startsWith('/.well-known/')) {
const metadataResponse = oauthMetadataResponse(request, await mcpAuth.getAuthMetadataOptions());
if (metadataResponse) {
return metadataResponse;
}
}
// Require a valid Bearer token for everything else
const auth = await gate(request);
if (auth instanceof Response) {
return auth;
}
return handler.fetch(request, { authInfo: auth });
},
};
Express (via @modelcontextprotocol/express)
import { createMcpExpressApp, mcpAuthMetadataRouter, requireBearerAuth } from '@modelcontextprotocol/express';
import { toNodeHandler } from '@modelcontextprotocol/node';
import { createMcpHandler } from '@modelcontextprotocol/server';
import { MCPAuth } from 'mcp-auth';
const mcpAuth = new MCPAuth({
protectedResourceMetadata: {
resource: 'https://api.example.com/mcp',
authorizationServer: { issuer: 'https://auth.example.com/oidc', type: 'oidc' },
scopesSupported: ['read:notes'],
},
});
// Reuses `createServer` from the fetch-native example above
const mcpNodeHandler = toNodeHandler(createMcpHandler(createServer));
const app = createMcpExpressApp();
app.use(mcpAuthMetadataRouter(await mcpAuth.getAuthMetadataOptions()));
app.all(
'/mcp',
requireBearerAuth(mcpAuth.getBearerAuthOptions({ requiredScopes: ['read:notes'] })),
// `createMcpExpressApp` applies `express.json()`, which drains the request stream, so the
// parsed body is passed along explicitly
async (request, response) => mcpNodeHandler(request, response, request.body)
);
app.listen(3000);
Implements
OAuthTokenVerifier
Constructors
Constructor
new MCPAuth(config: MCPAuthConfig): MCPAuth;
Creates an instance of MCPAuth and validates the configuration, so misconfigurations fail fast at startup. For a resolved authorization server config, the metadata is validated immediately; for a discovery config, the metadata is validated when it is first fetched.
Parameters
config
The authentication configuration.
Returns
MCPAuth
Throws
if the configuration is malformed.
Throws
if the provided authorization server metadata is invalid or does not satisfy the MCP authorization specification.
Properties
config
readonly config: MCPAuthConfig;
The authentication configuration.
Accessors
resourceMetadataUrl
Get Signature
get resourceMetadataUrl(): string;
The RFC 9728 Protected Resource Metadata URL for the configured
ProtectedResourceMetadataConfig.resource, built with the MCP SDK's
getOAuthProtectedResourceMetadataUrl.
Pass it as the resourceMetadataUrl option of the SDK's requireBearerAuth so the
WWW-Authenticate challenge on 401 responses points clients at the metadata document.
Example
const mcpAuth = new MCPAuth({
protectedResourceMetadata: { resource: 'https://api.example.com/mcp', ... },
});
mcpAuth.resourceMetadataUrl
// → 'https://api.example.com/.well-known/oauth-protected-resource/mcp'
Returns
string
Methods
getAuthMetadataOptions()
getAuthMetadataOptions(): Promise<AuthMetadataOptions>;
Builds the MCP SDK's AuthMetadataOptions from this instance's configuration and the
(possibly lazily fetched) authorization server metadata.
Feed the result to the SDK's oauthMetadataResponse (fetch-native) or to
mcpAuthMetadataRouter from @modelcontextprotocol/express to serve the OAuth discovery
documents (RFC 9728 Protected Resource Metadata and RFC 8414 Authorization Server Metadata).
Returns
Promise<AuthMetadataOptions>
A promise that resolves to the SDK's AuthMetadataOptions.
Throws
if fetching the authorization server metadata fails.
Throws
if the fetched metadata is invalid or does not satisfy the MCP authorization specification.
getBearerAuthOptions()
getBearerAuthOptions(options?: Pick<BearerAuthOptions, "requiredScopes">): BearerAuthOptions;
Builds the MCP SDK's BearerAuthOptions from this instance: the instance itself as the
verifier and resourceMetadataUrl for the WWW-Authenticate challenge, plus the
per-endpoint requiredScopes you pass in.
Feed the result to requireBearerAuth — the fetch-native one from
@modelcontextprotocol/server and the Express middleware from
@modelcontextprotocol/express accept the same options type. Endpoints with different
scope requirements call this method once each.
Parameters
options?
Pick<BearerAuthOptions, "requiredScopes">
Per-endpoint bearer-auth requirements.
Returns
BearerAuthOptions
The SDK's BearerAuthOptions, ready to pass to requireBearerAuth.
Example
// Fetch-native (Cloudflare Workers, Deno, Bun, Node.js)
const gate = requireBearerAuth(mcpAuth.getBearerAuthOptions({ requiredScopes: ['read:notes'] }));
// Express
app.post('/mcp', requireBearerAuth(mcpAuth.getBearerAuthOptions({ requiredScopes: ['read:notes'] })), ...);
verifyAccessToken()
verifyAccessToken(token: string): Promise<McpAuthInfo>;
Verifies a JWT access token issued by the trusted authorization server and returns the extended auth info (McpAuthInfo).
This method implements the MCP SDK's OAuthTokenVerifier interface, so the instance can be
passed directly as the verifier to the SDK's requireBearerAuth / verifyBearerToken
(or their framework adapters).
The verification flow:
- Decodes the token (without verifying) and rejects it unless its
issclaim matches the trusted issuer — before any metadata or JWKS request is made. - Resolves the authorization server metadata and JWK Set (both cached across calls).
- Verifies the token signature and the
issandaudclaims (theaudclaim must match the ProtectedResourceMetadataConfig.resource identifier, per the RFC 8707 audience binding the MCP authorization specification requires), plus standard time claims, viajose.jwtVerify. - Requires a non-empty
subclaim (per RFC 9068) and maps the payload to McpAuthInfo:clientIdfromclient_id(falling back toazp),scopesfromscope(space-separated) orscopes(array), andexpiresAtfromexp.
Parameters
token
string
The raw JWT access token.
Returns
Promise<McpAuthInfo>
A promise that resolves to the verified auth info.
Throws
(from @modelcontextprotocol/server, with code invalid_token) if the
token is malformed, from an untrusted issuer, or fails verification. The SDK bearer-auth
helpers map this to a 401 response with a WWW-Authenticate challenge.
Throws
if fetching the authorization server metadata fails; the SDK
bearer-auth helpers map non-OAuthError errors to a 500 response.
Throws
if the authorization server metadata is invalid or has no JWKS URI.
Implementation of
OAuthTokenVerifier.verifyAccessToken