SDK reference
The mcpauth npm package is the fastest way to protect an MCP server with OAuth 2.1. Its main export, mcpAuth(), is an Express middleware that wraps the official @modelcontextprotocol/sdk's requireBearerAuth middleware, so every request to your MCP route is verified against a real bearer token before it ever reaches your handlers.
Install
@modelcontextprotocol/sdk is a peer dependency either way. express is only needed if you use mcpAuth() — Next.js and other Fetch-API frameworks use createMcpAuthHandler() instead, with no Express dependency at all.
npm install getmcpauth @modelcontextprotocol/sdk expressImport what you need from the package root:
import {
mcpAuth,
createMcpAuthHandler,
McpAuthTokenVerifier,
mintToken,
protectedResourceMetadata,
mcpAuthResourceMetadataHandler,
} from "getmcpauth";mcpAuth(options)
Returns an Express middleware. Mount it on whatever route your MCP server listens on.
| Option | Type | Description |
|---|---|---|
| registrationSecret | string required | Your project's registration secret, from the dashboard. Used to authenticate calls back to mcpauth for token verification. Keep it server-side — never ship it to a client. |
| issuer | string optional | The base URL of your mcpauth authorization server. Defaults to https://getmcpauth.dev. |
| cacheTtlMs | number optional | How long a successful token verification is cached in-process, in milliseconds. Defaults to 30000 (30 seconds). A chatty agent conversation can call your MCP server many times per minute — without this cache, every single tool call would trigger a network round-trip back to mcpauth just to re-verify the same token. Raise it to reduce load further, or lower it if you need faster revocation propagation. |
| requiredScopes | string[] optional | Scopes a token must carry to be accepted. Requests with a valid but insufficiently-scoped token are rejected. |
| resourceMetadataUrl | string optional | The URL of your MCP server's protected-resource metadata document (RFC 9728), included in the WWW-Authenticate header on 401 responses so clients can locate it. Pair with mcpAuthResourceMetadataHandler below. |
Usage
A typical Express app exposing an MCP server behind mcpAuth():
import express from "express";
import { mcpAuth } from "getmcpauth";
import { yourMcpServerHandler } from "./mcp-server";
const app = express();
app.use(
"/mcp",
mcpAuth({
registrationSecret: process.env.MCPAUTH_SECRET!,
requiredScopes: ["mcp:tools"],
}),
yourMcpServerHandler
);
app.listen(3000);Every request to /mcp now passes through mcpAuth() before it reaches yourMcpServerHandler. Nothing in your handler needs to know how OAuth works — by the time it runs, the request has already been verified.
createMcpAuthHandler(options) — Next.js
The Next.js equivalent of mcpAuth(). Instead of returning Express middleware, it returns a plain (request: Request) => Promise<Response> function — drop it straight into a Route Handler. It wraps the official SDK's WebStandardStreamableHTTPServerTransport (Fetch-API based, works in Next.js, Cloudflare Workers, Deno, Bun) the same way mcpAuth() wraps requireBearerAuth for Express. It takes the same options as mcpAuth(), plus:
| Option | Type | Description |
|---|---|---|
| buildServer | () => McpServer required | Builds a fresh MCP server instance per request. Only called after the request's bearer token has been verified — unauthenticated requests never reach it. |
// app/api/mcp/route.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { createMcpAuthHandler } from "getmcpauth";
const handler = createMcpAuthHandler({
registrationSecret: process.env.MCPAUTH_SECRET!,
buildServer: () => {
const server = new McpServer({ name: "my-server", version: "1.0.0" });
server.registerTool(/* ... */);
return server;
},
});
export { handler as GET, handler as POST, handler as DELETE };This is exactly what protects mcpauth's own live demo server — same export, same code path, running in production.
Error handling
If a request arrives with no bearer token, an expired token, or a token that doesn't satisfy requiredScopes, mcpAuth() rejects it automatically — your handler never runs. The response is a spec-correct 401 Unauthorized with a WWW-Authenticate header pointing the client at how to authenticate (including your resourceMetadataUrl, if set), exactly as MCP clients expect when they encounter a protected server. You don't write any of this response logic yourself — it comes for free from wrapping the official SDK's requireBearerAuth middleware.
Lower-level access: McpAuthTokenVerifier
If you're not using Express, or you need more control than the mcpAuth() middleware gives you, use McpAuthTokenVerifierdirectly. It implements the official SDK's OAuthTokenVerifier interface, so it plugs into any code path that already expects that interface — you get the same token verification and caching behavior as mcpAuth(), without the Express-specific wiring.
Related
- Dynamic Client Registration — how MCP clients register themselves with mcpauth automatically.
- Endpoint reference — every REST endpoint mcpauth exposes, including
/api/oauth/token/exchangefor server-to-server token minting viamintToken().