MCP

OAuth MCP

MCP 플러그인을 사용하면 앱이 MCP 클라이언트를 위한 OAuth 제공자로 작동할 수 있습니다. 인증을 처리하고 MCP 애플리케이션용 액세스 토큰을 쉽게 발급하고 관리할 수 있습니다.

설치

플러그인 추가

auth 구성에 MCP 플러그인을 추가하고 로그인 페이지 경로를 지정합니다.

auth.ts
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 migrate
npx @better-auth/cli generate

MCP 플러그인은 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 메타데이터를 노출하는 경로를 추가하는 것이 좋습니다:

.well-known/oauth-authorization-server/route.ts
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 메타데이터를 노출하는 경로를 추가하는 것이 좋습니다:

/.well-known/oauth-protected-resource/route.ts
import { oAuthProtectedResourceMetadata } from "better-auth/plugins";
import { auth } from "@/lib/auth";

export const GET = oAuthProtectedResourceMetadata(auth);

MCP 세션 처리

헬퍼 함수 withMcpAuth를 사용하여 세션을 가져오고 인증되지 않은 호출을 자동으로 처리할 수 있습니다.

api/[transport]/route.ts
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 클라이언트에서 전송된 액세스 토큰을 사용하여 세션을 가져올 수 있습니다:

api/[transport]/route.ts
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 스키마 섹션을 참조하세요.

On this page