Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Add Docs
MCP Auth Node.js SDK
https://github.com/mcp-auth/js
Admin
MCP Auth is a Node.js SDK that simplifies OAuth 2.1 authentication by enabling quick integration
...
Tokens:
5,186
Snippets:
25
Trust Score:
6.4
Update:
3 months ago
Context
Skills
Chat
Benchmark
57.4
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# MCP Auth Node.js SDK MCP Auth is a plug-and-play authentication library for Model Context Protocol (MCP) servers. It implements OAuth 2.1 and OpenID Connect standards as required by the MCP specification, allowing developers to integrate trusted authentication providers with minimal code. The library handles the complexities of authorization server metadata, JWT verification, protected resource metadata endpoints, and Bearer token authentication for Express-based MCP servers. The SDK supports two operational modes: the newer "resource server" mode (recommended) for applications implementing OAuth 2.0 Protected Resource Metadata (RFC 9728), and a legacy "authorization server" mode for backward compatibility. It works with any OAuth 2.0 or OIDC-compliant provider that meets MCP requirements, including providers like Logto, Auth0, and Keycloak. The library is optimized for both traditional Node.js environments and edge runtimes like Cloudflare Workers through on-demand metadata discovery. ## MCPAuth Class The main class for initializing authentication in MCP servers. It creates authentication policies and Express middleware for protecting endpoints. Supports both resource server mode (recommended) and legacy authorization server mode. ```typescript import express from 'express'; import { MCPAuth, fetchServerConfig } from 'mcp-auth'; // Resource Server Mode (Recommended) - with pre-fetched metadata const resourceIdentifier = 'https://api.example.com/notes'; const authServerConfig = await fetchServerConfig('https://auth.logto.io/oidc', { type: 'oidc' }); const mcpAuth = new MCPAuth({ protectedResources: [ { metadata: { resource: resourceIdentifier, authorizationServers: [authServerConfig], scopesSupported: ['read:notes', 'write:notes'], }, }, ], }); const app = express(); // Serve Protected Resource Metadata endpoint app.use(mcpAuth.protectedResourceMetadataRouter()); // Protect API endpoints with JWT verification app.get( '/notes', mcpAuth.bearerAuth('jwt', { resource: resourceIdentifier, audience: resourceIdentifier, requiredScopes: ['read:notes'], }), (req, res) => { console.log('Authenticated user:', req.auth?.subject); console.log('Token scopes:', req.auth?.scopes); res.json({ notes: [] }); } ); app.listen(3001); ``` ## MCPAuth with Discovery Config (Edge Runtime Compatible) Initialize MCPAuth with discovery config for environments where top-level async fetch is not allowed. Metadata is fetched on-demand when the first request arrives. ```typescript import express from 'express'; import { MCPAuth } from 'mcp-auth'; const resourceIdentifier = 'https://api.example.com/todos'; // Discovery config - metadata fetched on first request const mcpAuth = new MCPAuth({ protectedResources: { metadata: { resource: resourceIdentifier, // Just pass issuer and type - metadata will be fetched on-demand authorizationServers: [{ issuer: 'https://auth.logto.io/oidc', type: 'oidc' }], scopesSupported: ['create:todos', 'read:todos', 'delete:todos'], }, }, }); const app = express(); app.use(mcpAuth.protectedResourceMetadataRouter()); app.use( mcpAuth.bearerAuth('jwt', { resource: resourceIdentifier, audience: resourceIdentifier, }) ); app.post('/todos', (req, res) => { // req.auth contains authenticated user info const userId = req.auth?.subject; res.json({ created: true, owner: userId }); }); app.listen(3001); ``` ## Legacy Authorization Server Mode The deprecated but supported authorization server mode for backward compatibility. Uses delegatedRouter() to serve OAuth 2.0 Authorization Server Metadata. ```typescript import express from 'express'; import { MCPAuth, fetchServerConfig } from 'mcp-auth'; const authServerConfig = await fetchServerConfig('https://auth.logto.io/oidc', { type: 'oidc' }); const mcpAuth = new MCPAuth({ server: authServerConfig, // Legacy server mode }); const app = express(); // Serve Authorization Server Metadata at /.well-known/oauth-authorization-server app.use(mcpAuth.delegatedRouter()); // Protect endpoints with required scopes app.get( '/mcp', mcpAuth.bearerAuth('jwt', { requiredScopes: ['read', 'write'] }), (req, res) => { console.log('Auth info:', req.auth); res.json({ status: 'authenticated' }); } ); app.listen(3001); ``` ## fetchServerConfig Fetches and validates authorization server metadata from the well-known endpoint. Automatically determines the correct metadata URL based on server type (OAuth or OIDC). ```typescript import { fetchServerConfig, fetchServerConfigByWellKnownUrl } from 'mcp-auth'; // Fetch OIDC server configuration // Fetches from: https://auth.logto.io/oidc/.well-known/openid-configuration const oidcConfig = await fetchServerConfig('https://auth.logto.io/oidc', { type: 'oidc' }); console.log('Issuer:', oidcConfig.metadata.issuer); console.log('JWKS URI:', oidcConfig.metadata.jwksUri); console.log('Token endpoint:', oidcConfig.metadata.tokenEndpoint); console.log('Userinfo endpoint:', oidcConfig.metadata.userinfoEndpoint); // Fetch OAuth server configuration // Fetches from: https://auth.example.com/.well-known/oauth-authorization-server/oauth const oauthConfig = await fetchServerConfig('https://auth.example.com/oauth', { type: 'oauth' }); // Or fetch directly from a well-known URL const customConfig = await fetchServerConfigByWellKnownUrl( 'https://custom-auth.example.com/.well-known/openid-configuration', { type: 'oidc' } ); // With custom metadata transformation for non-standard servers const transformedConfig = await fetchServerConfig('https://auth.example.com/oidc', { type: 'oidc', transpileData: (data) => ({ ...data, // Map non-standard fields to expected format jwks_uri: data.keys_url, token_endpoint: data.token_url, }), }); ``` ## bearerAuth Middleware Creates Express middleware for Bearer token authentication. Supports both built-in JWT verification and custom token verification functions. ```typescript import express from 'express'; import { MCPAuth, fetchServerConfig, MCPAuthTokenVerificationError } from 'mcp-auth'; const authServerConfig = await fetchServerConfig('https://auth.logto.io/oidc', { type: 'oidc' }); const resourceIdentifier = 'https://api.example.com'; const mcpAuth = new MCPAuth({ protectedResources: { metadata: { resource: resourceIdentifier, authorizationServers: [authServerConfig], scopesSupported: ['read', 'write', 'admin'], }, }, }); const app = express(); // JWT verification with required scopes app.get( '/protected', mcpAuth.bearerAuth('jwt', { resource: resourceIdentifier, audience: resourceIdentifier, requiredScopes: ['read'], }), (req, res) => { res.json({ user: req.auth?.subject, scopes: req.auth?.scopes, clientId: req.auth?.clientId, expiresAt: req.auth?.expiresAt, }); } ); // Custom token verification (e.g., using userinfo endpoint) const customVerify = async (token) => { const response = await fetch(authServerConfig.metadata.userinfoEndpoint, { headers: { Authorization: `Bearer ${token}` }, }); if (!response.ok) { throw new MCPAuthTokenVerificationError('token_verification_failed', response); } const userInfo = await response.json(); return { token, issuer: authServerConfig.metadata.issuer, subject: userInfo.sub, clientId: userInfo.azp || '', scopes: [], claims: userInfo, }; }; app.get( '/userinfo-auth', mcpAuth.bearerAuth(customVerify, { resource: resourceIdentifier }), (req, res) => { res.json({ claims: req.auth?.claims }); } ); app.listen(3001); ``` ## validateServerConfig Validates authorization server configuration against MCP specification requirements. Checks for required OAuth 2.1 features like PKCE support and authorization code grant. ```typescript import { fetchServerConfig, validateServerConfig } from 'mcp-auth'; const config = await fetchServerConfig('https://auth.logto.io/oidc', { type: 'oidc' }); // Basic validation const result = validateServerConfig(config); if (result.isValid) { console.log('Server configuration is valid'); if (result.warnings.length > 0) { console.log('Warnings:', result.warnings); // Example warning: { code: 'dynamic_registration_not_supported', description: '...' } } } else { console.error('Validation errors:', result.errors); // Example errors: // - { code: 'pkce_not_supported', description: 'PKCE is required by MCP specification' } // - { code: 's256_code_challenge_method_not_supported', description: '...' } } // Verbose validation with success messages const verboseResult = validateServerConfig(config, true); if (verboseResult.isValid) { console.log('Validation successes:', verboseResult.successes); // Example: [ // { code: 'server_metadata_valid', description: '...' }, // { code: 'pkce_supported', description: '...' }, // { code: 's256_code_challenge_method_supported', description: '...' }, // { code: 'authorization_code_grant_supported', description: '...' }, // ] } ``` ## createVerifyJwt Creates a JWT verification function using the jose library. Returns an AuthInfo object with token claims on successful verification. ```typescript import { createRemoteJWKSet } from 'jose'; import { createVerifyJwt, MCPAuthTokenVerificationError } from 'mcp-auth'; // Create a remote JWK Set for fetching public keys const jwksUri = 'https://auth.logto.io/oidc/jwks'; const getKey = createRemoteJWKSet(new URL(jwksUri)); // Create the verification function const verifyJwt = createVerifyJwt(getKey, { // Optional JWT verification options audience: 'https://api.example.com', issuer: 'https://auth.logto.io/oidc', }); // Verify a token try { const authInfo = await verifyJwt('eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...'); console.log('Verified token:', { issuer: authInfo.issuer, // Token issuer (iss claim) subject: authInfo.subject, // User ID (sub claim) clientId: authInfo.clientId, // OAuth client ID (client_id or azp claim) scopes: authInfo.scopes, // Granted scopes (scope claim) audience: authInfo.audience, // Token audience (aud claim) expiresAt: authInfo.expiresAt, // Expiration time (exp claim) claims: authInfo.claims, // All raw JWT claims token: authInfo.token, // Original token string }); } catch (error) { if (error instanceof MCPAuthTokenVerificationError) { console.error('Token verification failed:', error.code, error.message); } } ``` ## Error Classes MCP Auth provides typed error classes for different authentication failure scenarios. Use these for proper error handling and response formatting. ```typescript import { MCPAuthError, MCPAuthConfigError, MCPAuthAuthServerError, MCPAuthBearerAuthError, MCPAuthTokenVerificationError, } from 'mcp-auth'; // Configuration error - thrown when mcp-auth config is invalid try { // Invalid configuration } catch (error) { if (error instanceof MCPAuthConfigError) { console.error('Config error:', error.code, error.message); // error.code: 'fetch_server_config_error' } } // Auth server error - thrown when authorization server issues occur try { // Server metadata issues } catch (error) { if (error instanceof MCPAuthAuthServerError) { console.error('Auth server error:', error.code); // error.code: 'invalid_server_metadata' | 'invalid_server_config' | 'missing_jwks_uri' console.log('Error JSON:', error.toJson()); } } // Bearer auth error - thrown during request authentication try { // Authentication check } catch (error) { if (error instanceof MCPAuthBearerAuthError) { console.error('Bearer auth error:', error.code); // error.code: 'missing_auth_header' | 'invalid_auth_header_format' | // 'missing_bearer_token' | 'invalid_issuer' | 'invalid_audience' | // 'missing_required_scopes' | 'invalid_token' console.log('Missing scopes:', error.cause?.missingScopes); // Convert to HTTP response format const responseBody = error.toJson(true); // true = show details // { error: 'missing_required_scopes', errorDescription: '...', missingScopes: ['admin'] } } } // Token verification error - thrown when JWT verification fails try { // JWT verification } catch (error) { if (error instanceof MCPAuthTokenVerificationError) { console.error('Token error:', error.code); // error.code: 'invalid_token' | 'token_verification_failed' } } ``` ## Complete MCP Server Example with Protected Resources A complete example demonstrating MCP server setup with authentication, scope-based authorization, and multiple tools. ```typescript import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import express from 'express'; import { MCPAuth, MCPAuthBearerAuthError } from 'mcp-auth'; import { z } from 'zod'; const MCP_AUTH_ISSUER = process.env.MCP_AUTH_ISSUER || 'https://auth.logto.io/oidc'; const MCP_RESOURCE_IDENTIFIER = process.env.MCP_RESOURCE_IDENTIFIER || 'https://api.example.com/'; // Initialize MCPAuth with protected resource metadata const mcpAuth = new MCPAuth({ protectedResources: { metadata: { resource: MCP_RESOURCE_IDENTIFIER, authorizationServers: [{ issuer: MCP_AUTH_ISSUER, type: 'oidc' }], scopesSupported: ['create:todos', 'read:todos', 'delete:todos'], }, }, }); // Factory function for MCP server instances (stateless mode) const createMcpServer = () => { const mcpServer = new McpServer({ name: 'Todo Manager', version: '1.0.0', }); // Tool with scope check mcpServer.registerTool( 'create-todo', { description: 'Create a new todo item', inputSchema: { content: z.string() }, }, ({ content }, { authInfo }) => { // Check required scope if (!authInfo?.scopes.includes('create:todos')) { throw new MCPAuthBearerAuthError('missing_required_scopes', { missingScopes: ['create:todos'], }); } return { content: [{ type: 'text', text: JSON.stringify({ id: crypto.randomUUID(), content, ownerId: authInfo.subject, createdAt: new Date().toISOString(), }), }], }; } ); // Tool with conditional scope access mcpServer.registerTool( 'get-todos', { description: 'List todos', inputSchema: {}, }, (_params, { authInfo }) => { const hasReadAll = authInfo?.scopes.includes('read:todos'); return { content: [{ type: 'text', text: JSON.stringify({ accessLevel: hasReadAll ? 'all' : 'own', userId: authInfo?.subject, }), }], }; } ); return mcpServer; }; const app = express(); // Serve Protected Resource Metadata endpoint // GET /.well-known/oauth-protected-resource?resource=https://api.example.com/ app.use(mcpAuth.protectedResourceMetadataRouter()); // Apply JWT authentication middleware app.use( mcpAuth.bearerAuth('jwt', { resource: MCP_RESOURCE_IDENTIFIER, audience: MCP_RESOURCE_IDENTIFIER, }) ); // MCP endpoint app.post('/', async (req, res) => { const mcpServer = createMcpServer(); const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined }); await mcpServer.connect(transport); await transport.handleRequest(req, res, req.body); res.on('close', () => { transport.close(); mcpServer.close(); }); }); app.listen(3001, () => { console.log('MCP server listening on port 3001'); }); ``` ## AuthInfo Interface The AuthInfo interface is extended by mcp-auth to provide additional authentication context available on `req.auth` after successful authentication. ```typescript import { type AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js'; // Extended AuthInfo interface available on req.auth interface AuthInfo { token: string; // Raw access token from request issuer: string; // Token issuer (iss claim) clientId: string; // OAuth client ID (client_id or azp claim) scopes: string[]; // Granted scopes expiresAt?: number; // Token expiration timestamp (exp claim) // Additional fields added by mcp-auth subject?: string; // User ID (sub claim) audience?: string | string[]; // Token audience (aud claim) claims?: Record<string, unknown>; // All raw JWT claims } // Usage in Express handler app.get('/protected', authMiddleware, (req, res) => { const auth = req.auth!; // Access user information console.log('User ID:', auth.subject); console.log('Client:', auth.clientId); console.log('Scopes:', auth.scopes); // Access custom claims from the token const roles = auth.claims?.roles as string[] | undefined; const email = auth.claims?.email as string | undefined; res.json({ userId: auth.subject, email, roles, tokenExpiresAt: auth.expiresAt, }); }); ``` ## Summary MCP Auth is designed for developers building MCP servers that require OAuth 2.1 compliant authentication. The primary use cases include: protecting MCP tool endpoints with JWT-based Bearer authentication, integrating with existing OAuth/OIDC identity providers (Logto, Auth0, Keycloak, etc.), implementing scope-based authorization for fine-grained access control, and serving standardized metadata endpoints for OAuth 2.0 Protected Resources (RFC 9728). The library handles all the complexity of metadata discovery, JWKS fetching, token verification, and issuer validation automatically. Integration follows a straightforward pattern: initialize MCPAuth with your authorization server configuration (either pre-fetched or discovery-based), mount the metadata router for client discovery, and apply the bearerAuth middleware to protected routes. The library works seamlessly with Express 5.x and the official MCP TypeScript SDK. For production deployments, use the resource server mode with proper audience validation and required scopes. The on-demand metadata discovery feature makes the library compatible with edge runtimes where top-level await is restricted.