MCP 서버를 안전하게 설계하는 방법: OAuth와 권한 관리 기초

권한을 서버가 아니라 사용자 단위로 설계하는 기준과 실무 팁

MCP 서버를 만들 때 가장 먼저 고민하는 부분은 대개 어떤 도구를 연결하고 어떤 데이터를 모델에게 보여줄지다. 하지만 운영 환경에 실제로 배포하려면 연결 자체보다 먼저 정리해야 할 질문이 있다. 이 서버가 누구를 대신해 요청을 수행하는지, 어떤 범위의 데이터에 접근할 수 있는지, 나중에 요청 기록을 근거로 설명할 수 있는지가 정리되어 있지 않으면 작은 자동화 하나도 금세 보안 부담으로 돌아온다.

특히 사내 문서, 이슈 트래커, 배포 시스템처럼 권한 차이가 큰 리소스를 MCP 도구로 열어둘 때는 API 키 하나로 모든 요청을 처리하는 방식이 위험해지기 쉽다. 처음에는 간단해 보이지만 사용자가 늘어날수록 누가 무엇을 요청했는지 구분하기 어려워지고, 특정 사용자의 권한보다 넓은 데이터가 모델에게 전달될 가능성도 함께 커진다.

권한을 연결 단위가 아니라 사용자 단위로 설계해야 하는 이유

중간 계층이라는 위치가 만드는 위험

MCP 서버는 AI 클라이언트와 내부 시스템 사이에 놓인 중간 계층처럼 동작한다. 여러 도구와 데이터를 하나의 인터페이스로 묶어준다는 점에서 편리하지만, 그만큼 권한 경계가 흐려지기도 쉽다. 서버 하나가 모든 사용자를 대표하는 방식으로 동작하면 실제 사용자가 가진 권한을 있는 그대로 반영하기 어렵다.

그래서 설계 기준을 서버가 접근할 수 있는가가 아니라 지금 요청한 사용자가 접근할 수 있는가로 바꿔야 한다. 문서 검색 도구라면 사용자가 원래 열람할 수 없는 문서는 검색 결과에도 나타나지 않아야 하고, 배포 도구라면 사용자에게 실행 권한이 없는 환경으로는 요청 자체가 전달되지 않아야 한다.

OAuth가 필요한 이유

OAuth는 사용자의 자격 증명을 서버에 직접 맡기지 않고, 정해진 범위와 기간을 가진 토큰으로 접근을 위임하는 방식이다. MCP 서버가 외부 문서 저장소나 이슈 트래커, 메신저 서비스와 연결된다면 OAuth로 사용자별 동의와 접근 범위를 관리하는 구조가 잘 맞는다. 사용자가 연결을 끊거나 권한 범위를 줄이면 서버도 그 변화를 곧바로 반영할 수 있기 때문이다.

다만 OAuth를 붙였다는 사실만으로 안전해지는 것은 아니다. 토큰을 어디에 저장할지, 갱신 토큰을 어떻게 관리할지, scope를 어디까지 요청할지, 로그에 남는 값을 어떻게 가릴지, 토큰을 폐기하는 절차까지 함께 설계해야 실질적인 의미가 있다. 권한 범위를 필요 이상으로 넓게 잡으면 OAuth를 쓰더라도 결과적으로는 과도한 권한을 내준 것과 다르지 않다.

최소한의 범위부터 시작하는 원칙

MCP 도구는 처음부터 넓은 권한을 부여하기보다 읽기 전용, 특정 프로젝트, 특정 폴더처럼 좁은 범위에서 출발하는 편이 안전하다. 실제로 필요한 기능이 확인된 뒤에 범위를 넓히면 운영 중 사고 가능성을 상당히 줄일 수 있다. 문서 검색처럼 읽기 권한만으로 충분한 기능에 수정 권한까지 함께 부여하면, 모델의 오작동이나 의도치 않은 요청이 곧바로 실제 데이터 변경으로 이어질 위험이 생긴다.

실제로 적용할 수 있는 방법

기능별로 scope를 나누기

하나의 큰 범위로 모든 기능을 묶어 처리하지 말고 검색, 조회, 생성, 수정, 삭제를 가능한 만큼 분리해두는 편이 좋다. 사용자가 검색 기능만 필요로 한다면 검색과 읽기 범위만 요청하고, 쓰기 기능은 별도 동의가 필요한 단계로 남겨둔다. 이렇게 나눠두면 나중에 기능을 추가할 때도 권한이 얼마나 넓어지는지 사용자에게 명확히 설명할 수 있다.

도구 이름과 설명에 위험도를 드러내기

도구 이름과 설명은 모델이 어떤 도구를 선택할지 판단하는 중요한 단서가 된다. 문서를 삭제하는 도구처럼 되돌리기 어려운 동작을 하는 도구는 삭제 대상, 복구 가능 여부, 사전 확인 필요 여부를 설명에 분명히 적어야 한다. 반대로 조회만 하는 도구는 읽기 전용이라는 점을 명확히 밝혀두면 모델이 불필요하게 위험한 도구를 고를 가능성을 줄일 수 있다.

감사 로그를 남기기

누가 어떤 도구를 언제 호출했고 어떤 대상을 다뤘는지 기록해두어야 문제가 생겼을 때 원인을 되짚을 수 있다. 다만 로그에 토큰이나 민감한 본문, 개인정보가 그대로 남지 않도록 마스킹 규칙을 함께 정해야 한다. 감사 로그는 단순한 디버깅용 로그와는 목적이 달라서, 운영자가 이후 권한 정책을 점검할 때 근거 자료로 쓸 수 있어야 한다.

실패했을 때는 보수적으로 판단하기

권한 확인 절차가 실패했거나 토큰 상태를 확인할 수 없을 때는 요청을 막는 쪽이 안전하다. 네트워크 오류나 인증 서버 장애를 이유로 임시 우회 경로를 열어두면, 오히려 가장 취약한 순간에 가장 넓은 권한이 열리는 결과로 이어질 수 있다. 다소 불편하더라도 실패 시에는 요청을 차단하고 사용자에게 재인증을 안내하는 편이 낫다.

놓치기 쉬운 함정

OAuth 토큰을 서버 설정 파일이나 환경 변수 하나에 고정해 모든 사용자가 함께 쓰는 방식은 피해야 한다. 초기 테스트 단계에서는 간편해 보이지만, 운영 단계로 넘어가면 사용자별 권한 구분과 감사 추적이 사실상 불가능해진다. 특히 사내 시스템과 연결할 때는 테스트용으로 발급했던 넓은 권한의 토큰이 배포 이후에도 그대로 남아 있지 않은지 반드시 확인해야 한다.

또 하나 자주 놓치는 부분은 모델에게 보여주는 도구 설명에 내부 권한 정책을 지나치게 자세히 적어두는 것이다. 도구 설명은 필요한 행동 제약을 알려주는 선에서 유지하고, 내부 시스템 구조나 우회에 쓰일 수 있는 정보는 담지 않는 편이 좋다. 보안과 관련된 상세 설명은 운영 문서 쪽에 남겨두고, 모델용 설명은 행동 경계 중심으로 짧게 정리하는 방식이 안전하다.

정리

MCP 서버의 안전성은 어떤 인증 방식을 붙였는지보다 권한 경계를 얼마나 일관되게 유지하는지에 더 크게 좌우된다. OAuth는 사용자별 위임과 회수를 관리하는 데 유용한 기반이지만, scope 설계와 최소 권한 원칙, 감사 로그, 실패 시 기본값까지 함께 갖춰야 실제 운영에서 의미가 생긴다. 읽기 전용과 좁은 범위에서 시작해, 필요성이 검증된 기능만 단계적으로 넓혀가는 접근이 현실적인 출발점이다.

핵심 요약

  • MCP 서버 권한은 서버 단위가 아니라 사용자 단위로 판단해야 한다.
  • OAuth는 scope 설계, 토큰 저장, 폐기 흐름까지 함께 갖춰야 의미가 있다.
  • 읽기, 쓰기, 삭제 권한을 나누면 기능별 위험도를 관리하기 쉬워진다.
  • 권한 확인이 실패했을 때 기본값은 허용이 아니라 차단이어야 안전하다.

초보자가 자주 실수하는 포인트

  • 테스트용으로 발급한 넓은 권한의 토큰을 운영 서버에 그대로 사용하는 경우
  • 읽기 기능만 필요한 도구에 쓰기나 삭제 권한까지 함께 부여하는 경우
  • 감사 로그를 남기지 않아 나중에 어떤 요청이 실행됐는지 추적하지 못하는 경우

체크리스트

  • 사용자별 인증과 권한 확인 흐름이 마련되어 있는가
  • OAuth scope가 기능별로 분리되어 있는가
  • 토큰과 민감한 정보가 로그에 그대로 남지 않도록 마스킹하는가
  • 권한 확인에 실패하면 요청을 차단하도록 되어 있는가
  • 되돌리기 어려운 도구에는 별도 확인 절차가 있는가

자주 묻는 질문

MCP 서버 하나로 여러 외부 서비스를 연결할 때도 OAuth를 각각 따로 적용해야 하나요?

서비스마다 권한 체계와 토큰 발급 방식이 다르기 때문에 일반적으로는 서비스별로 별도의 OAuth 연동을 두는 편이 안전하다. 하나의 토큰으로 여러 서비스를 한꺼번에 처리하면 특정 서비스의 권한 범위가 다른 서비스에도 그대로 적용될 위험이 있다.

이 글은 초보자 기준으로 이해하기 쉽게 정리되었으며, 내용은 운영 과정에서 순차적으로 보완될 수 있습니다.