제품 개발

MCP OAuth 설명: 401 포인터, PKCE, 동적 클라이언트 등록, 스코프를 처음부터 끝까지

MCP 인가는 OAuth 2.1입니다. 401이 서버 메타데이터를 가리키고, 클라이언트가 스스로 등록하며, PKCE가 코드를 지키고, 스코프 있는 갱신 가능 토큰이 붙여 넣은 키를 대체합니다.

작성 Atrix team게시일 9분 분량
목차
  1. MCP가 OAuth를 쓰는 이유
  2. 흐름을 단계별로
  3. 각 요소가 무엇을 막는가
  4. PKCE: 훔친 코드가 쓸모없는 이유
  5. 동적 클라이언트 등록: 아무도 콘솔에서 앱을 만들지 않는 이유
  6. 스코프: 좁힐 뿐 넓히지 않는다
  7. 실제 서버에서의 같은 흐름
  8. PKCE 흐름 vs 붙여 넣은 토큰: 무엇을 포기하는가
  9. FAQ
  10. 다음 단계

MCP 인가는 몇 가지 필수 요소가 더해진 OAuth 2.1입니다. 원격 MCP 서버에 대한 인증되지 않은 요청은 서버의 메타데이터를 가리키는 401을 받습니다. 클라이언트는 그것을 따라 인가 서버로 가고, 자신을 식별하고, 사용자가 스코프에 동의할 수 있도록 브라우저를 열고, PKCE로 보호된 코드를 수명 짧은 액세스 토큰과 회전하는 리프레시 토큰으로 교환합니다. 그 결과는 설정 파일에 붙여 넣은 키가 아니라, 스코프가 있고 취소 가능한 자격 증명입니다.

이것이 한 문단으로 정리한 전체 흐름입니다. 나머지는 MCP 인가 명세(2025-11-25 개정판)에 따라 단계별로 따라가고, PKCE, 동적 클라이언트 등록, 스코프가 각각 무엇을 막는지 설명하며, 실제 서버, 즉 우리 서버에 대해 흐름이 실제로 어떻게 돌아가는지 보여줍니다. 각 단계가 클라이언트 쪽에서 어떻게 보이는지 알 수 있습니다.

MCP가 OAuth를 쓰는 이유

stdio를 쓰는 로컬 MCP 서버는 환경에서 자격 증명을 읽고, 명세는 OAuth를 쓰지 말아야 한다고 말합니다. 원격 서버는 다릅니다. 하나의 배포가 서로 다른 권한을 가진 많은 사람을, 서버 운영자가 한 번도 본 적 없는 AI 앱으로부터 섬깁니다. 세 가지 문제가 따라옵니다.

  1. 서버는 매 호출마다 누가 요청하는지 알아야 합니다.
  2. 사용자는 모든 것을 넘기지 않고 앱이 무엇을 할 수 있는지 제한해야 합니다.
  3. 둘 다 비밀번호를 바꾸거나 키를 손으로 교체하지 않고 나중에 접근을 끝낼 방법이 필요합니다.

붙여 넣은 API 키는 첫 번째 문제를 제대로 풀지 못하고 나머지 둘은 전혀 풀지 못합니다. OAuth는 정확히 이 형태, 즉 앱이 서비스에서 사람을 대신해 행동하는 상황을 위해 설계되었고, OAuth 2.1은 그것을 통합하고 더 엄격하게 만든 버전입니다. OAuth 2.1 용어집 항목에 2.0에서 제거된 것들이 정리되어 있습니다. MCP와 관련된 부분은 PKCE가 필수이고, 리다이렉트 URI가 정확히 일치해야 하며, 토큰이 쿼리 문자열로 이동할 수 없다는 점입니다.

MCP 인가 명세는 다섯 문서 위에 세워져 있습니다. OAuth 2.1 초안(draft-ietf-oauth-v2-1-13), Authorization Server Metadata(RFC 8414), Dynamic Client Registration(RFC 7591), Protected Resource Metadata(RFC 9728), 그리고 Client ID Metadata Documents 초안입니다. MCP 서버를 쓰기 위해 읽을 필요는 없지만, 각각이 아래 질문 중 하나에 답합니다.

흐름을 단계별로

원격 서버를 추가한 순간부터 모델이 첫 도구 호출을 하는 순간까지 일어나는 일입니다. 클라이언트가 전부 처리하고, 여러분에게는 브라우저 탭 하나만 보입니다.

  1. 클라이언트가 토큰 없이 서버를 호출합니다. OAuth 리소스 서버로 동작하는 서버는 URL인 resource_metadata를 담은 WWW-Authenticate: Bearer 헤더와 함께 401 Unauthorized로 답합니다. 명세는 서버에 RFC 9728 구현을, 클라이언트에 이 헤더 파싱을 요구합니다. 헤더가 없으면 클라이언트는 대신 well-known URI를 시도해야 합니다.
  2. 클라이언트가 보호 리소스 메타데이터를 가져옵니다. 문서는 최소 하나의 authorization_servers 항목을 명시하고 scopes_supported를 나열할 수 있습니다.
  3. 클라이언트가 인가 서버를 발견합니다. RFC 8414(/.well-known/oauth-authorization-server) 또는 OpenID Connect Discovery로 그 서버의 메타데이터를 가져옵니다. 클라이언트는 둘 다 지원해야 합니다. 메타데이터에는 인가, 토큰, 등록 엔드포인트, 지원하는 PKCE 방식, 있다면 client_id_metadata_document_supported가 나열됩니다.
  4. 클라이언트가 PKCE 지원을 확인합니다. 메타데이터에 code_challenge_methods_supported가 없으면 클라이언트는 진행을 거부해야 합니다. 조용한 다운그레이드는 없습니다.
  5. 클라이언트가 자신을 식별합니다. 명세의 우선순위에 따라 세 가지 선택지가 있습니다. 가지고 있다면 사전 등록된 자격 증명. 클라이언트 ID가 클라이언트가 호스팅하는 JSON 파일의 HTTPS URL인 Client ID Metadata Document. 또는 등록 엔드포인트에 POST해 즉시 client_id를 받는 동적 클라이언트 등록. 명세는 이제 서버와 클라이언트가 메타데이터 문서를 지원해야 하고, 동적 등록은 대비책으로 지원할 수 있다고 말합니다.
  6. 클라이언트가 브라우저를 엽니다. 인가 URL에는 클라이언트 ID, 리다이렉트 URI, 요청 스코프, state 값, code_challenge_method=S256이 붙은 PKCE code_challenge, 그리고 MCP 서버를 가리키는 resource 매개변수(RFC 8707)가 담깁니다. 사용자는 로그인하고 클라이언트 이름과 스코프가 나열된 동의 화면을 봅니다.
  7. 인가 서버가 코드와 함께 리다이렉트합니다. 코드는 수명이 짧고 한 번만 쓸 수 있습니다.
  8. 클라이언트가 코드를 토큰으로 교환합니다. 토큰 요청에는 코드, 원래의 PKCE code_verifier, 같은 resource 매개변수가 담깁니다. 응답은 액세스 토큰과, 보통은 리프레시 토큰입니다.
  9. 모든 MCP 요청이 토큰을 싣습니다. Authorization: Bearer에 넣고 URL에는 절대 넣지 않으며, 서버는 매 호출마다 토큰이 유효하고 바로 이 서버를 위해 발급되었는지 검증합니다.
  10. 호출에 더 넓은 스코프가 필요하면, 서버는 error="insufficient_scope"와 필요한 스코프를 담아 403으로 답합니다. 클라이언트는 더 넓은 집합으로 흐름을 다시 실행합니다. 명세는 이를 스텝업 인가라 부르고 클라이언트에게 재시도 횟수를 제한하라고 합니다.

각 요소가 무엇을 막는가

장치정의 문서막는 공격
보호 리소스 메타데이터RFC 9728클라이언트가 잘못된 인가 서버를 추측하거나 속아서 사용하는 것
인가 서버 메타데이터RFC 8414서버가 바뀌면 깨지는 하드코딩된 엔드포인트
PKCE(S256)RFC 7636, OAuth 2.1훔친 인가 코드를 다른 사람이 교환하는 것
리다이렉트 URI 정확 일치OAuth 2.1코드를 공격자에게 보내는 오픈 리다이렉트
state 매개변수OAuth 2.1콜백에 대한 사이트 간 요청 위조
resource 매개변수RFC 8707한 서버용 토큰이 다른 서버에서 재사용되는 것
서버 측 대상 검증RFC 8707, OAuth 2.1토큰 패스스루와 혼동된 대리인 공격
수명 짧은 액세스 토큰OAuth 2.1유출된 토큰이 오래 유효한 것
회전하는 리프레시 토큰OAuth 2.1훔친 리프레시 토큰이 조용히 재사용되는 것
스코프와 동의OAuth 2.0/2.1앱이 사용자가 동의한 것 이상을 하는 것

이 중 둘은 사람들이 자주 묻는 것이라 더 자세히 볼 가치가 있습니다.

PKCE: 훔친 코드가 쓸모없는 이유

대부분의 MCP 클라이언트는 퍼블릭 클라이언트입니다. 데스크톱 앱, 에디터, CLI처럼 비밀을 지킬 수 없는 것들입니다. 인가 코드 흐름에서 코드는 리다이렉트를 통해 돌아오는데, 노트북이나 휴대폰에서는 같은 URL에 등록된 다른 프로그램이 그 리다이렉트를 가로챌 수 있습니다. PKCE 이전에는 코드를 가진 사람이 누구든 교환할 수 있었습니다.

PKCE는 로그인마다 한 번 쓰는 비밀을 더합니다. 클라이언트는 무작위 code_verifier를 만들어 보관하고, 인가 요청과 함께 code_challenge = BASE64URL(SHA256(code_verifier))를 보냅니다. 코드를 교환할 때 원래의 verifier를 제시합니다. 인가 서버는 이를 해시해 저장된 challenge와 비교하고, 다르면 교환을 거부합니다. 코드는 있지만 verifier가 없는 도둑은 아무것도 얻지 못합니다. PKCE 항목은 plain 방식과, OAuth 2.1과 MCP가 가능한 한 S256을 쓰라고 하는 이유를 다룹니다.

동적 클라이언트 등록: 아무도 콘솔에서 앱을 만들지 않는 이유

고전적인 OAuth는 개발자가 각 앱을 미리 등록한다고 가정했습니다. 수천 개의 AI 클라이언트 중 어느 것이든 사전 관계 없이 수천 개의 MCP 서버 중 어느 것에든 연결할 수 있는 세계에서는 그것이 확장되지 않습니다. 동적 클라이언트 등록(RFC 7591)은 클라이언트가 이름과 리다이렉트 URI 같은 자기 메타데이터를 등록 엔드포인트에 POST하고 즉시 client_id를 받을 수 있게 합니다.

2025-11-25 개정판은 더 깔끔한 답인 Client ID Metadata Documents를 추가합니다. 클라이언트 ID 자체가 클라이언트를 설명하는 JSON 문서를 가리키는 HTTPS URL입니다. 인가 서버는 이를 가져와 문서의 client_id가 URL과 정확히 일치하는지 확인하고, 리다이렉트 URI를 그에 비추어 검증합니다. 명세는 클라이언트와 서버가 이를 지원해야 하며 호환성을 위해 동적 등록을 유지할 수 있다고 말합니다. 어떤 클라이언트든 등록할 수 있으므로, 신중한 인가 서버는 등록이 아무런 신뢰도 부여하지 않는 것으로 취급합니다. 동의 화면에 클라이언트 이름과 리다이렉트 호스트를 분명히 보여주고, 리다이렉트가 단순한 localhost 포트일 때 경고합니다. 명세는 메타데이터 문서만으로는 이를 완전히 보호할 수 없다고 적고 있습니다.

스코프: 좁힐 뿐 넓히지 않는다

스코프는 동의 화면에 있는 이름들입니다. work.read, crm.write 같은 것입니다. 앱이 집합을 요청하고, 사용자가 일부 또는 전부를 승인하고, 토큰이 그 결과를 싣습니다. MCP 명세는 클라이언트에게 401 챌린지의 scope 매개변수가 있으면 그것을, 없으면 서버의 scopes_supported를 요청하고, 한 번에 모든 것을 요구하기보다 나중에 스텝업하라고 말합니다.

가장 중요한 규칙은 OAuth 표준이 각 API에 맡긴 것입니다. 스코프는 앱이 사용자를 대신해 요청할 수 있는 것을 기술하며, 그 사용자 자신이 할 수 있는 것을 결코 넘어서는 안 됩니다. 좋은 서버는 매 호출마다 둘 다 확인합니다. 토큰이 그 스코프를 가지고 있는가, 그리고 그 뒤의 사람이 이 레코드에 이 일을 할 권한이 있는가.

실제 서버에서의 같은 흐름

위 단계들이 우리가 운영하고 매일 쓰는 https://atrix.dev/api/mcp의 Atrix MCP 서버에서는 이렇게 보입니다. 추상적인 흐름을 구체적인 동작과 맞춰볼 수 있습니다. 개발자 가이드에 클라이언트별 안내가 있습니다.

Claude Code에서 설정 전체는 claude mcp add --transport http atrix https://atrix.dev/api/mcp, 그다음 /mcp와 Authenticate입니다. 이 명령은 의도적으로 자격 증명을 싣지 않습니다. 그다음에 일어나는 일은 이렇습니다.

  • 첫 요청은 RFC 9728 포인터와 함께 401을 받습니다. 발견은 RFC 8414와 RFC 9728을 따릅니다.
  • 클라이언트는 동적으로 스스로 등록합니다. 클라이언트 시크릿은 어디에도 없습니다. 우리 자신의 앱을 포함해 모든 클라이언트가 퍼블릭 클라이언트이기 때문입니다.
  • PKCE는 S256만 씁니다. 서버는 메타데이터에 S256만 공개하고 plain은 거부합니다.
  • 브라우저가 열리고, 워크스페이스를 고르고 스코프를 승인합니다. 코드는 60초 동안 살고 한 번만 동작합니다.
  • 클라이언트는 한 시간 유효한 atx_oat_ 접두사의 액세스 토큰과, 90일 유효하고 사용할 때마다 회전하는 atx_ort_ 접두사의 리프레시 토큰을 받습니다.
  • 스코프는 결코 권한을 더하지 않습니다. 매 호출마다 토큰 뒤의 계정에 대해 해석되므로, 팀원의 접근이 취소되면 그 사람이 만든 모든 토큰은 다음 요청부터 아무것에도 닿지 못합니다. 아홉 개 스코프는 거래 금액이나 고용 기록처럼 계정의 해당 권한도 요구하며, 급여는 아예 부여할 수 없습니다.
  • 제한은 토큰당 분당 120회 호출과 30회 쓰기입니다. 모든 호출은 도구, 결과, 대상별로 감사되며 내용은 기록하지 않습니다.

CI 작업과 브라우저 없는 서버를 위해서는 대신 atx_pat_ 접두사의 개인 액세스 토큰이 있고, --header "Authorization: Bearer ..."로 보냅니다. 동작은 하지만 브라우저가 있는 곳에서는 어디서나 더 나쁜 선택입니다. 디스크에 평문으로 있고, 만들 때 고른 만큼 오래 살며, 동의 화면을 건너뜁니다. 우리는 이 선택지를 파이프라인용으로 남겨두고 사람에게는 OAuth를 권합니다.

PKCE 흐름 vs 붙여 넣은 토큰: 무엇을 포기하는가

PKCE를 쓰는 OAuth 2.1붙여 넣은 개인 액세스 토큰
연결 방법URL 추가, 브라우저에서 승인설정에서 토큰 생성, 설정 파일에 붙여 넣기
수명액세스 1시간, 리프레시 90일 회전(Atrix)30일부터 영구까지, 선택에 따라
저장 위치클라이언트의 보안 저장소설정 파일, 흔히 평문
범위 결정동의 화면, 이후 스텝업생성 시 선택
취소 방법권한 부여나 계정 취소토큰 삭제
브라우저 필요예아니요
적합한 용도AI 앱을 쓰는 사람CI, cron, 헤드리스 서버

FAQ

MCP는 OAuth를 요구하나요?

프로토콜에서 인가는 선택 사항입니다. 서버가 HTTP 전송을 쓰고 인가를 지원할 때, 명세는 OAuth 2.1 기반 인가 명세를 따라야 한다고 말합니다. stdio 서버는 이를 쓰지 않고 환경에서 자격 증명을 가져와야 합니다.

MCP에서 OAuth 2.0과 OAuth 2.1의 차이는 무엇인가요?

OAuth 2.1은 암묵적 그랜트와 비밀번호 그랜트를 제거하고, 인가 코드 흐름에 PKCE를 요구하며, 리다이렉트 URI 정확 일치를 요구하고, 쿼리 문자열의 베어러 토큰을 금지하며, 퍼블릭 클라이언트에 리프레시 토큰 회전 또는 발신자 제약을 요구합니다. MCP는 이 모두를 물려받습니다.

내 MCP 클라이언트가 인가 서버 연결을 거부하는 이유는 무엇인가요?

가장 흔한 이유는 PKCE 지원 누락입니다. 인가 서버 메타데이터에 code_challenge_methods_supported가 없으면 MCP 클라이언트는 진행을 거부해야 합니다. 두 번째는 401의 WWW-Authenticate 헤더가 없거나 형식이 잘못된 경우입니다.

동적 클라이언트 등록은 여전히 필수인가요?

아니요. 2025-11-25 개정판은 클라이언트와 서버가 Client ID Metadata Documents를 지원해야 하고, 동적 등록은 대비책으로 지원할 수 있다고 말합니다. Atrix를 포함한 많은 서버가 오래된 클라이언트가 의존하기 때문에 여전히 동적 등록을 제공합니다.

MCP 토큰이 만든 사람보다 더 많은 일을 할 수 있나요?

그래서는 안 됩니다. 스코프는 접근을 좁힐 뿐 더하지 않습니다. 잘 만든 서버는 매 호출마다 사람의 권한을 해석하므로, 토큰은 소유자 이상에 결코 닿을 수 없고, 소유자가 접근을 잃는 순간 토큰도 잃습니다.

OAuth 대신 개인 액세스 토큰을 써야 할 때는 언제인가요?

브라우저가 없는 곳에서만입니다. CI 파이프라인, cron 작업, 헤드리스 서버입니다. 그 밖의 모든 곳에서는 OAuth가 디스크에 비밀을 저장하지 않고도 더 짧은 수명의, 스코프가 있고 취소 가능한 자격 증명을 줍니다.

다음 단계

개발자 가이드는 Claude Code, Claude Desktop, ChatGPT, Cursor용 정확한 명령과 함께 Atrix 흐름을 클라이언트별로 안내합니다. 위의 용어가 낯설었다면 OAuth 2.1과 PKCE 항목이 우리가 아는 가장 짧은 설명입니다.

이 글 공유하기

이 글 공유하기

함께 읽으면 좋은 글

전체 글

이 글의 내용을 바로 실천해 보세요.

7일간 써 보세요. 시작하려면 카드 등록이 필요하며, 취소하지 않으면 체험 종료 시 결제됩니다. 체험 중 취소하면 비용이 들지 않습니다.

7일 체험 · 카드 필요 · 언제든 해지 가능