MCP
用于 Better Auth 的 MCP 提供者插件
OAuth MCP
此插件即将被弃用,推荐改用 OAuth Provider Plugin。
MCP 插件让你的应用可以作为 MCP 客户端的 OAuth 提供者。它处理认证,并简化了为 MCP 应用颁发和管理访问令牌的流程。
此插件基于 OIDC Provider 插件。未来将移至 OAuth Provider 插件。
安装
添加插件
在你的认证配置中添加 MCP 插件,并指定登录页面路径。
import { betterAuth } from "better-auth";
import { mcp } from "better-auth/plugins";
export const auth = betterAuth({
plugins: [
mcp({
loginPage: "/sign-in" // 你的登录页面路径
})
]
});此插件无客户端插件,因此你无需更改 authClient。
生成数据库 Schema
运行迁移或生成 Schema,将必要的字段和表添加到数据库。
npx auth migratenpx auth generateMCP 插件使用与 OIDC Provider 插件相同的 Schema。详情请参阅OIDC Provider Schema。
使用
OAuth 发现元数据
Better Auth 已自动处理 /api/auth/.well-known/oauth-authorization-server 路由,但有些客户端可能无法解析 WWW-Authenticate 头而默认访问 /.well-known/oauth-authorization-server(例如,当 CORS 配置未暴露 WWW-Authenticate 时)。因此,建议添加路由来暴露 MCP 客户端的 OAuth 元数据:
import { oAuthDiscoveryMetadata } from "better-auth/plugins";
import { auth } from "../../../lib/auth";
export const GET = oAuthDiscoveryMetadata(auth);OAuth 受保护资源元数据
Better Auth 同样自动处理 /api/auth/.well-known/oauth-protected-resource 路由,但某些客户端同样可能无法解析 WWW-Authenticate 头而默认访问 /.well-known/oauth-protected-resource。因此建议添加路由暴露 MCP 客户端的 OAuth 元数据:
import { oAuthProtectedResourceMetadata } from "better-auth/plugins";
import { auth } from "@/lib/auth";
export const GET = oAuthProtectedResourceMetadata(auth);MCP 会话处理
你可以使用辅助函数 withMcpAuth 来获取会话,并自动处理未认证调用。
import { auth } from "@/lib/auth";
import { createMcpHandler } from "@vercel/mcp-adapter";
import { withMcpAuth } from "better-auth/plugins";
import { z } from "zod";
const handler = withMcpAuth(auth, (req, session) => {
// session 包含带有作用域和用户 ID 的访问令牌记录
return createMcpHandler(
(server) => {
server.tool(
"echo",
"Echo a message",
{ message: z.string() },
async ({ message }) => {
return {
content: [{ type: "text", text: `Tool echo: ${message}` }],
};
},
);
},
{
capabilities: {
tools: {
echo: {
description: "Echo a message",
},
},
},
},
{
redisUrl: process.env.REDIS_URL,
basePath: "/api",
verboseLogs: true,
maxDuration: 60,
},
)(req);
});
export { handler as GET, handler as POST, handler as DELETE };你也可以使用 auth.api.getMcpSession 来通过 MCP 客户端发送的访问令牌获取会话:
import { auth } from "@/lib/auth";
import { createMcpHandler } from "@vercel/mcp-adapter";
import { z } from "zod";
const handler = async (req: Request) => {
// session 包含带有作用域和用户 ID 的访问令牌记录
const session = await auth.api.getMcpSession({
headers: req.headers
})
if(!session){
// 这一步很重要,必须返回 401
return new Response(null, {
status: 401
})
}
return createMcpHandler(
(server) => {
server.tool(
"echo",
"Echo a message",
{ message: z.string() },
async ({ message }) => {
return {
content: [{ type: "text", text: `Tool echo: ${message}` }],
};
},
);
},
{
capabilities: {
tools: {
echo: {
description: "Echo a message",
},
},
},
},
{
redisUrl: process.env.REDIS_URL,
basePath: "/api",
verboseLogs: true,
maxDuration: 60,
},
)(req);
}
export { handler as GET, handler as POST, handler as DELETE };配置
MCP 插件接受以下配置选项:
Prop
Type
OIDC 配置
通过 oidcConfig 参数,插件支持额外的 OIDC 配置选项:
Prop
Type
远程 MCP 客户端
上面的示例使用 withMcpAuth,要求 Better Auth 实例与 MCP 服务器在同一进程中运行。如果你的 MCP 服务器作为独立服务运行(不同仓库、不同时运行时环境、不同语言),你可以使用 MCP 客户端 — 一个轻量、框架无关的 HTTP 客户端,用于验证发送给远程 Better Auth 服务器的 Bearer 令牌。
无需额外安装包 — MCP 客户端已包含在 better-auth 中。
设置
创建客户端
指向你的 Better Auth 服务器地址(与你的认证配置中的 baseURL + basePath 相同):
import { createMcpAuthClient } from "better-auth/plugins/mcp/client"
const mcpAuth = createMcpAuthClient({
authURL: "http://localhost:3000/api/auth"
}) 保护你的 MCP 路由
使用 handler 包装 Web 标准的 Request/Response(适用于 Deno、Bun、Cloudflare Workers 等):
const handler = mcpAuth.handler(async (req, session) => {
// session.userId, session.scopes, session.clientId
return new Response(JSON.stringify({
jsonrpc: "2.0",
result: { userId: session.userId },
id: 1
}))
})
Deno.serve(handler)挂载发现端点
MCP 客户端需要发现你的 OAuth 服务器。请在 MCP 服务器根路径挂载:
const discovery = mcpAuth.discoveryHandler()
const protectedResource = mcpAuth.protectedResourceHandler("http://localhost:4000")
// GET /.well-known/oauth-authorization-server → 代理转发自 Better Auth
// GET /.well-known/oauth-protected-resource → 指向 MCP 客户端的 Better Auth这些代理并缓存来自 Better Auth 服务器的元数据,使 MCP 客户端能够自动发现授权、令牌和注册端点。
框架适配器
import { Hono } from "hono"
import { mcpAuthHono } from "better-auth/plugins/mcp/client/adapters"
const app = new Hono()
const { middleware, discoveryRoutes } = mcpAuthHono({
authURL: "http://localhost:3000/api/auth"
})
// 挂载 OAuth 发现端点(MCP 规范要求)
discoveryRoutes(app, "http://localhost:4000")
// 保护 MCP 路由
app.use("/mcp/*", middleware)
app.post("/mcp", (c) => {
const session = c.get("mcpSession")
// session.userId, session.scopes 等
})import express from "express"
import { createMcpAuthClient } from "better-auth/plugins/mcp/client"
const app = express()
const mcpAuth = createMcpAuthClient({
authURL: "http://localhost:3000/api/auth"
})
app.use("/mcp", mcpAuth.middleware())
app.post("/mcp", (req, res) => {
const session = req.mcpSession
// session.userId, session.scopes 等
})import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"
import { mcpAuthOfficial } from "better-auth/plugins/mcp/client/adapters"
const auth = mcpAuthOfficial({
authURL: "http://localhost:3000/api/auth"
})
const mcpServer = new McpServer({ name: "my-server", version: "1.0.0" })
const app = express() // 你的 HTTP 框架
app.post("/mcp", auth.handler(async (req, session) => {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => crypto.randomUUID()
})
await mcpServer.connect(transport)
return transport.handleRequest(req)
}))完全替代 oauthWorkOSProvider、oauthSupabaseProvider 等:
import { MCPServer } from "mcp-use/server"
import { mcpAuthMcpUse } from "better-auth/plugins/mcp/client/adapters"
const server = new MCPServer({
name: "my-server",
version: "1.0.0",
oauth: mcpAuthMcpUse({
authURL: "http://localhost:3000/api/auth"
})
})选项
Prop
Type
会话对象
verifyToken 返回并传递给处理函数的会话对象包含:
Prop
Type
Schema
MCP 插件使用与 OIDC Provider 插件相同的 Schema。详情请参阅OIDC Provider Schema章节。