To secure your MCP server, wrap your handler using the withMcpAuth function. This requires a verifyToken function that validates the incoming request and returns an AuthInfo object.
AuthInfo includes:
token: The validated bearer token.scopes: An array of granted scopes.clientId: The unique identifier for the client.extra: An object for additional metadata.
Once wrapped, you can access the authenticated user's information within your tool handlers via ctx.http?.authInfo.
import { createMcpHandler, withMcpAuth } from "mcp-handler";
import type { AuthInfo } from "@modelcontextprotocol/server";
const handler = createMcpHandler((server) => {
server.registerTool(
"example",
{ /* ... schema ... */ },
async (input, ctx) => {
const authInfo = ctx.http?.authInfo;
// Use authInfo.clientId or authInfo.token
return { content: [{ type: "text", text: `Hello ${authInfo?.clientId}` }] };
}
);
}, {});
// Token verification function
const verifyToken = async (req: Request, bearerToken?: string): Promise<AuthInfo | undefined> => {
// Implement your actual validation logic here
if (!bearerToken) return undefined;
return {
token: bearerToken,
scopes: ["read:stuff"],
clientId: "user123",
extra: { userId: "123" },
};
};
// Wrap handler with authorization
const authHandler = withMcpAuth(handler, verifyToken, {
required: true,
requiredScopes: ["read:stuff"],
resourceMetadataPath: "/.well-known/oauth-protected-resource",
});
export { authHandler as GET, authHandler as POST };