콘텐츠로 건너뛰기

MCP 클라이언트는 Authorization Server를 어떻게 찾는가: 공식 MCP TypeScript SDK와 VS Code 구현 비교

  • 테크

이전에 작성한 MCP 소개: LLM과 외부 시스템을 연결하는 컨텍스트 표준에서는 MCP의 기본 개념과 함께, MCP 서버가 외부 도구 및 데이터를 AI 애플리케이션에 제공하는 구조를 살펴봤습니다.

이번 글에서는 HTTP 기반 원격 MCP 서버에서 OAuth 권한 부여 서버와 주요 엔드포인트를 탐색하는 방식을 다룹니다. MCP 클라이언트가 원격 서버에 접근하려면, 권한 부여를 담당하는 서버와 주요 엔드포인트를 먼저 발견해야 합니다. 이를 위해 클라이언트는 Protected Resource Metadata와 Authorization Server Metadata를 순차적으로 조회하게 됩니다.

본문에서는 다음 핵심 주제를 바탕으로 MCP 클라이언트가 OAuth 서버와 주요 엔드포인트를 탐색하고 메타데이터를 처리하는 과정을 단계별로 알아봅니다.

  • MCP 클라이언트의 OAuth 권한 부여 정보 탐색 메커니즘
  • Authorization Server issuer에 하위 경로가 존재할 때의 discovery URL 처리 방식
  • 공식 MCP TypeScript SDK의 메타데이터 처리 구조 (Version 2025-11-25와 TypeScript SDK v1.29.0 기준)
  • VS Code 실제 구현 방식에서 발견되는 차이점

1. MCP 클라이언트에 자동 탐색 기능이 필요한 이유

특정 Authorization Server와 사전에 통합된 OAuth 클라이언트는 endpoint와 Client ID 등의 정보를 설정값으로 미리 제공받는 경우가 많습니다.
하지만 다양한 외부 MCP 서버와 연동되어야 하는 범용 MCP 클라이언트는 환경이 다릅니다.
범용 MCP 클라이언트는 연결 대상마다 이러한 정보를 미리 설정하기 어렵습니다. 사용자는 일반적으로 MCP 엔드포인트를 등록하고, 클라이언트는 이를 출발점으로 Authorization Server의 위치와 권한 부여에 필요한 엔드포인트 및 지원 기능을 동적으로 탐색합니다.

2. MCP 클라이언트의 Authorization Server Discovery

MCP 클라이언트가 보호된 원격 서버에 접근하려면 먼저 해당 MCP 서버가 사용하는 Authorization Server와 OAuth 엔드포인트를 확인해야 합니다.

[MCP Client]
    │
    │ 1. Access Token 없이 MCP 요청
    │    GET/POST https://example.com/mcp
    ▼
[MCP Server / Protected Resource]
    │
    │ 2. 401 Unauthorized 응답
    │
    │    WWW-Authenticate:
    │    Bearer resource_metadata="..."
    ▼
[Protected Resource Metadata]
    │ RFC 9728
    │
    │ 3. authorization_servers에서
    │    Authorization Server의 issuer 확인
    ▼
[Authorization Server]
    │
    │ 4. 다음 메타데이터 중 하나를 조회
    │
    │    - Authorization Server Metadata
    │    - OpenID Provider Metadata
    ▼
[OAuth 권한 부여 정보 확보]
    ├─ authorization_endpoint
    ├─ token_endpoint
    ├─ registration_endpoint
    ├─ scopes_supported
    └─ code_challenge_methods_supported

2.1 Protected Resource Metadata 조회 (RFC 9728)
클라이언트가 인증 없이 MCP 엔드포인트(https://example.com/mcp)를 호출하면 서버는 401 Unauthorized 응답의 WWW-Authenticate 헤더로 Protected Resource Metadata URL을 전달할 수 있습니다.
해당 값이 없으면 클라이언트는 MCP 엔드포인트를 기준으로 well-known URL을 구성해 메타데이터를 탐색합니다.
예를 들어 MCP 엔드포인트가 https://example.com/mcp라면 클라이언트는 먼저 https://example.com/.well-known/oauth-protected-resource/mcp를 시도합니다. 이 요청이 실패하면 https://example.com/.well-known/oauth-protected-resource로 fallback합니다.

클라이언트는 이를 통해 토큰을 발급받아야 하는 Authorization Server의 issuer(https://example.com/auth)를 파악합니다.

{
  "resource": "https://example.com/mcp",
  "authorization_servers": [
    "https://example.com/auth"
  ],
  "scopes_supported": ["read", "read_write"],
  "bearer_methods_supported": ["header"]
}

2.2 Authorization Server Metadata 조회 (RFC 8414 또는 OIDC Discovery)
인증 서버의 issuer를 확인한 클라이언트는 실제 권한 부여 및 토큰 발급 엔드포인트를 찾기 위해 Authorization Server Metadata 조회를 시작합니다.
클라이언트는 이 응답을 통해 필요한 실제 엔드포인트와 지원 기능 목록을 확보할 수 있습니다.

{
  "issuer": "https://example.com/auth",
  "authorization_endpoint": "https://example.com/auth/oauth/authorize",
  "token_endpoint": "https://example.com/auth/oauth/token",
  "registration_endpoint": "https://example.com/auth/oauth/register",
  "scopes_supported": ["read", "read_write"],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["none"]
}

3. issuer에 하위 경로가 있을 때의 discovery URL

Authorization Server의 issuer가 Origin 형태라면 Discovery URL은 단순하지만, issuer에 하위 경로가 포함된 경우 URL 구성 방식 규칙을 따라야 합니다.

RFC 8414 Section 3.1에 따르면 issuer에 하위 경로가 있으면 well-known suffix를 Origin과 issuer path 사이에 삽입해 metadata URL을 구성합니다. 이 구조를 사용하면 하나의 host에서 서로 다른 경로를 가진 여러 issuer를 제공할 수 있습니다.

MCP는 OAuth Authorization Server Metadata와 OpenID Connect(OIDC) Discovery 간의 호환성을 위해, issuer에 경로가 존재할 때 다음 3가지 URL을 순서대로 탐색하도록 규정하고 있습니다.

  • https://example.com/.well-known/oauth-authorization-server/auth
  • https://example.com/.well-known/openid-configuration/auth
  • https://example.com/auth/.well-known/openid-configuration

여기서 주의할 점은 RFC 8414 Section 5가 openid-configuration suffix를 OpenID Connect에 한정된 식별자로 취급하지 않는다는 것입니다.

4. OAuth와 OIDC metadata의 필수 항목 차이

OAuth 2.0 Authorization Server Metadata(RFC 8414)와 OpenID Connect Discovery Metadata는 공유하는 필드가 많지만 각 규격에서 요구하는 필수 메타데이터 항목에는 차이가 있습니다.

  • OAuth Authorization Server Metadata (RFC 8414): 권한 부여 및 토큰 엔드포인트와 지원 기능을 정의합니다.
  • OIDC Provider Metadata: OAuth 정보에 더해 사용자 인증과 ID Token 검증에 필요한 다음 필수 필드들을 추가로 요구합니다. OIDC Provider Metadata에서 요구되는 대표적인 OIDC 전용 필수 항목은 다음과 같습니다.
    • jwks_uri
    • subject_types_supported
    • id_token_signing_alg_values_supported

5. 공식 TypeScript SDK와 VS Code 구현 비교

  • 공식 TypeScript SDK의 경우
    • https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.29.0/src/client/auth.ts
    • 공식 TypeScript SDK의 buildDiscoveryUrls() 함수는 discovery 후보 URL을 생성하고, 각 후보를 oauth 또는 oidc 타입으로 분류합니다. 이후 discoverAuthorizationServerMetadata()는 이 타입에 따라 OAuth Metadata Schema 또는 OpenID Provider Metadata Schema를 적용합니다.
    • 두 번째와 세 번째 후보는 oidc로 분류됩니다. 따라서 해당 URL에서 200 OK 응답을 받으면 OpenID Provider Metadata 검증이 적용되며, OIDC 필수 항목이 없으면 검증에 실패합니다.
  • VS Code의 경우
    • https://github.com/microsoft/vscode/blob/main/src/vs/base/common/oauth.ts
    • VS Code의 내부 OAuth 타입 정의(IAuthorizationServerMetadata)는 OIDC 전용 필드를 요구하지 않는 공통 인터페이스 구조를 채택하고 있습니다.
    • VS Code의 메타데이터 검증은 issuer가 존재하는지 확인합니다. 또한 issuer, authorization_endpoint, token_endpoint, registration_endpoint, jwks_uri가 제공된 경우, 해당 값이 문자열이며 http:// 또는 https://로 시작하는지 검사합니다. 반면 subject_types_supported나 id_token_signing_alg_values_supported 등의 OIDC 전용 필드는 요구하지 않습니다.따라서 OAuth 흐름에 필요한 endpoint가 실제 응답에 포함되어 있다면 다음 권한 부여 단계로 진행할 수 있습니다.

6. 서버 구성에 따른 동작 차이

서버가 다음과 같이 동작하도록 구성되어 있다고 가정해 보겠습니다.
Issuer:
https://example.com/auth

  • https://example.com/.well-known/oauth-authorization-server/auth → 404 Not Found
  • https://example.com/.well-known/openid-configuration/auth → 404 Not Found
  • https://example.com/auth/.well-known/openid-configuration → 200 OK (OAuth 핵심 필드만 포함된 JSON 반환)
{
  "issuer": "https://example.com/auth",
  "authorization_endpoint": "https://example.com/auth/oauth/authorize",
  "token_endpoint": "https://example.com/auth/oauth/token",
  "registration_endpoint": "https://example.com/auth/oauth/register",
  "scopes_supported": ["read", "read_write"],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["none"]
}
  • 공식 MCP TypeScript SDK의 discoverAuthorizationServerMetadata()를 사용하는 경우, 세 번째 URL은 OIDC 후보로 분류됩니다. 응답에 OIDC 필수 필드가 없으므로 OpenIdProviderDiscoveryMetadataSchema 검증이 실패하고 discovery 함수가 오류를 발생시킵니다.
  • 반면 VS Code는 동일한 응답을 Authorization Server Metadata로 수용하여 discovery 단계를 통과합니다. 후속 권한 부여 흐름의 성공 여부는 클라이언트 등록 정보와 각 OAuth 엔드포인트의 동작에 따라 달라집니다.
  • 이와 같이 OIDC URL에서 OAuth 중심의 메타데이터를 반환하면 두 구현의 동작이 달라질 수 있습니다.

7. 마무리

이번 글에서는 HTTP 기반 원격 MCP 서버에서 Protected Resource Metadata와 Authorization Server Metadata를 탐색하는 과정과, 공식 MCP TypeScript SDK v1.29.0 및 VS Code의 메타데이터 처리 차이를 살펴봤습니다.

두 구현체는 동일한 discovery URL 후보를 시도하지만, OIDC 후보 URL에서 반환된 응답에 적용하는 검증 기준이 다릅니다. 이 차이 때문에 OAuth 핵심 필드만 포함한 문서는 VS Code의 discovery를 통과할 수 있지만, TypeScript SDK에서는 OIDC 필수 필드 누락으로 실패할 수 있습니다.

RFC 8414 자체는 OAuth 애플리케이션이 openid-configuration suffix를 일반 OAuth metadata 게시에 사용할 수 있다고 설명합니다. 그러나 MCP 2025-11-25 명세는 두 번째와 세 번째 후보를 OIDC Discovery endpoint로 구분하며, 공식 TypeScript SDK도 해당 응답에 OpenID Provider Metadata 검증을 적용합니다.

다양한 MCP 클라이언트와의 상호운용성을 확보하려면 일반 OAuth metadata는 oauth authorization server 위치에서 제공하는 것이 가장 안전합니다.

Ref.
MCP 소개: LLM과 외부 시스템을 연결하는 컨텍스트 표준
MCP Authorization Server Discovery
RFC 8414: OAuth 2.0 Authorization Server Metadata
MCP TypeScript SDK v1.29.0 OAuth 클라이언트 코드
VS Code OAuth 구현

최신 마케팅/고객 데이터 활용 사례를 받아보실 수 있습니다.

비즈스프링 뉴스레터 구독하기 →