byteforce

CPN 한국어 자습서 · 외부 문서 한국어 미러

MCP 문서 · Extensions

OAuth 클라이언트 자격증명

OAuth Client Credentials · 원문: modelcontextprotocol.io/extensions/auth/oauth-client-credentials

아래는 원문을 한국어로 옮긴 미러입니다. 코드·명령은 원문 그대로이며, 가장 최신 정보는 하단 원문 링크에서 확인하세요.

OAuth 2.0 클라이언트 자격증명 플로우를 사용한 MCP 머신 간 인증

OAuth Client Credentials 익스텐션(io.modelcontextprotocol/oauth-client-credentials)은 MCP에 OAuth 2.0 클라이언트 자격증명 플로우 지원을 추가합니다. 이를 통해 자동화 시스템이 대화형 사용자 인가 없이 MCP 서버에 연결할 수 있습니다.

개요

표준 MCP 인가 플로우는 사용자의 대화형 접근 승인을 요구합니다. OAuth Client Credentials 익스텐션은 클라이언트가 위임된 사용자 자격증명 대신 애플리케이션 수준의 자격증명(클라이언트 ID와 시크릿, 또는 서명된 JWT assertion)으로 인증할 수 있게 하여 이 문제를 해결합니다.

사용 시기

다음 경우에 OAuth Client Credentials를 사용합니다:

작동 방식

JWT Bearer Assertions (권장)

코드 · 명령
sequenceDiagram
    participant Client
    participant AS as Authorization Server
    participant MCP as MCP Server

    Client->>AS: POST /token<br/>grant_type=urn:ietf:params:<br/>oauth:grant-type:jwt-bearer<br/>assertion=<signed JWT>
    AS-->>Client: access_token
    Client->>MCP: MCP request (Bearer token)

JWT assertion에는 일반적으로 iss(클라이언트 ID), sub(클라이언트 ID), aud(인가 서버 토큰 엔드포인트 URL), exp, iat가 포함됩니다.

클라이언트 시크릿

코드 · 명령
sequenceDiagram
    participant Client
    participant AS as Authorization Server
    participant MCP as MCP Server

    Client->>AS: POST /token<br/>grant_type=client_credentials<br/>client_id + client_secret
    AS-->>Client: access_token
    Client->>MCP: MCP request (Bearer token)

주의: 클라이언트 시크릿은 사용자 상호작용 없이 접근을 허용하는 장기 자격증명입니다. 시크릿을 소스 코드에 절대 저장하지 말고 시크릿 매니저를 사용하세요. 정기적으로 시크릿을 교체하고, 가능하면 JWT assertion을 사용하세요 — JWT assertion은 단기적이며 서명 키를 전송할 필요가 없습니다.

구현 가이드

MCP 클라이언트 구현

  1. initialize에서 지원 선언:
코드 · 명령
{
  "capabilities": {
    "extensions": {
      "io.modelcontextprotocol/oauth-client-credentials": {}
    }
  }
}
  1. MCP 서버에 연결하기 전에 인가 서버에서 토큰을 요청합니다.
  2. MCP 서버에 대한 HTTP 요청의 Authorization 헤더에 토큰을 포함합니다: Authorization: Bearer <access_token>
  3. 만료 전에 토큰 갱신 로직을 구현합니다.

MCP 서버 구현

  1. 각 요청에서 인가 서버의 JWKS 엔드포인트를 통해 JWT 서명 및 클레임을 검증합니다.
  2. 필요한 스코프가 토큰에 포함되어 있는지 확인합니다.
  3. 검색 가능성을 위해 initialize 응답에 지원을 광고합니다(선택 사항이지만 권장).

SDK 예제

클라이언트 시크릿 사용 (TypeScript):

코드 · 명령
import {
  Client,
  ClientCredentialsProvider,
  StreamableHTTPClientTransport,
} from "@modelcontextprotocol/client";

const provider = new ClientCredentialsProvider({
  clientId: "my-service",
  clientSecret: "s3cr3t",
});

const client = new Client(
  { name: "my-service", version: "1.0.0" },
  { capabilities: {} },
);

const transport = new StreamableHTTPClientTransport(
  new URL("https://mcp.example.com/mcp"),
  { authProvider: provider },
);

await client.connect(transport);
const tools = await client.listTools();
console.log(
  "Available tools:",
  tools.tools.map((t) => t.name),
);
await transport.close();

클라이언트 시크릿 사용 (Python):

코드 · 명령
from mcp.client.auth.extensions.client_credentials import (
    ClientCredentialsOAuthProvider,
)
from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession

provider = ClientCredentialsOAuthProvider(
    server_url="https://mcp.example.com/mcp",
    client_id="my-service",
    client_secret="s3cr3t",
    scopes="read write",
)

async with streamablehttp_client(
    "https://mcp.example.com/mcp",
    auth_provider=provider,
) as (read_stream, write_stream, _):
    async with ClientSession(read_stream, write_stream) as session:
        await session.initialize()
        tools = await session.list_tools()
        print("Available tools:", [t.name for t in tools.tools])

JWT 개인키 사용 (TypeScript):

코드 · 명령
import {
  Client,
  PrivateKeyJwtProvider,
  StreamableHTTPClientTransport,
} from "@modelcontextprotocol/client";

const provider = new PrivateKeyJwtProvider({
  clientId: "my-service",
  privateKey: process.env.CLIENT_PRIVATE_KEY_PEM,
  algorithm: "RS256",
});

const client = new Client(
  { name: "my-service", version: "1.0.0" },
  { capabilities: {} },
);

const transport = new StreamableHTTPClientTransport(
  new URL("https://mcp.example.com/mcp"),
  { authProvider: provider },
);

await client.connect(transport);
const tools = await client.listTools();
await transport.close();

JWT 개인키 사용 (Python):

코드 · 명령
from mcp.client.auth.extensions.client_credentials import (
    PrivateKeyJWTOAuthProvider,
    SignedJWTParameters,
)
from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession

jwt_params = SignedJWTParameters(
    issuer="my-service",
    subject="my-service",
    signing_key=open("private_key.pem").read(),
    signing_algorithm="RS256",
    lifetime_seconds=300,
)

provider = PrivateKeyJWTOAuthProvider(
    server_url="https://mcp.example.com/mcp",
    client_id="my-service",
    assertion_provider=jwt_params.create_assertion_provider(),
    scopes="read write",
)

async with streamablehttp_client(
    "https://mcp.example.com/mcp",
    auth_provider=provider,
) as (read_stream, write_stream, _):
    async with ClientSession(read_stream, write_stream) as session:
        await session.initialize()
        tools = await session.list_tools()
        print("Available tools:", [t.name for t in tools.tools])

클라이언트 지원

참고: 이 익스텐션에 대한 지원은 클라이언트마다 다릅니다. 익스텐션은 옵트인 방식이며 기본적으로 활성화되지 않습니다.

현재 구현 현황은 클라이언트 매트릭스를 확인하세요.

원문(영어): https://modelcontextprotocol.io/extensions/auth/oauth-client-credentials · 본 문서는 학습용 한국어 번역이며 원본의 권리는 원저작자(Model Context Protocol)에게 있습니다.

원문(영어): https://modelcontextprotocol.io/extensions/auth/oauth-client-credentials