MCP
OAuth MCP
MCP 플러그인을 사용하면 앱이 MCP 클라이언트를 위한 OAuth 제공자로 작동할 수 있습니다. 인증을 처리하고 MCP 애플리케이션용 액세스 토큰을 쉽게 발급하고 관리할 수 있습니다.
설치
플러그인 추가
auth 구성에 MCP 플러그인을 추가하고 로그인 페이지 경로를 지정합니다.
import { betterAuth } from "better-auth";
import { mcp } from "better-auth/plugins";
export const auth = betterAuth({
plugins: [
mcp({
loginPage: "/sign-in" // 로그인 페이지 경로
})
]
});이것은 클라이언트 플러그인이 없으므로 authClient를 변경할 필요가 없습니다.
스키마 생성
마이그레이션을 실행하거나 스키마를 생성하여 필요한 필드와 테이블을 데이터베이스에 추가합니다.
npx @better-auth/cli migratenpx @better-auth/cli generateMCP 플러그인은 OIDC Provider 플러그인과 동일한 스키마를 사용합니다. 자세한 내용은 OIDC Provider 스키마 섹션을 참조하세요.
사용법
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로 기본 설정할 수 있습니다(예를 들어 CORS 구성이 WWW-Authenticate를 노출하지 않는 경우 발생할 수 있습니다). 이러한 이유로 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 플러그인은 OIDC Provider 플러그인과 동일한 스키마를 사용합니다. 자세한 내용은 OIDC Provider 스키마 섹션을 참조하세요.