접근할 수 있는 범위
솔직한 경계.
어떤 도구가 존재하는지는 역할이 정한다
서버는 사용자 본인으로서, 본인이 활성화해 둔 연결을 대상으로 동작합니다. 별도의 서비스 계정도 없고 본인보다 넓은 접근 권한도 없습니다. 역할이 도입된 뒤로는 본인의 역할보다 넓은 접근 권한도 없습니다. 클라이언트에 주어지는 도구 목록은 활성 워크스페이스에서 보유한 권한으로 만들어지므로, 뷰어의 클라이언트에는 sendEmail, createRule, sendWithTemplate이 아예 나열되지 않습니다.
이것은 호출을 거부하는 것보다 강한 조치입니다. 목록에 없는 도구는 모델이 고려하는 도구가 아니고, 컨텍스트를 잡아먹지도 않으며, 누군가를 대신해 시도했다가 사과할 일도 없습니다. 또한 클라이언트가 비어 보인다면 대개 이 서버에 없는 기능이 아니라 내가 보유하지 않은 권한 때문이라는 뜻이고, whoAmI는 바로 그것을 알려 주려고 존재합니다.
등록과 호출은 두 개의 관문이지만 실제로 막아 주는 것은 두 번째뿐입니다. 목록은 세션이 열릴 때 한 번 만들어지는데, setActiveConnection이 그 세션을 권한이 더 적은 메일함으로 옮길 수 있으므로 목록은 구조적으로 낡을 수밖에 없고, 프로토콜에는 세션 도중에 도구를 회수할 방법이 없습니다. 그래서 권한이 걸린 모든 도구는 실행 전에 현재 연결을 기준으로 역할을 다시 확인합니다. 등록은 배려이고, 호출이 경계입니다.
거부는 양쪽을 모두 밝힙니다. 예를 들어 Refused (missing_permission): your role in this mailbox is Viewer, which does not include “Send email”처럼 알려 주므로, 에이전트가 자신이 대신 일하는 사람에게 설명하고 시도를 멈출 수 있고, 불투명한 오류를 누군가 포기할 때까지 재시도하지 않아도 됩니다. 세션이 열려 있는 동안 관리자가 역할을 바꾼 경우에도 바로 다음 호출에서 같은 방식으로 나타납니다.
주소는 또 하나의 축이며 이 모든 것의 영향을 받지 않습니다. 역할은 무엇을 할 수 있는지를 말하고, 부여받은 주소는 어떤 메일함에 대해 그 일을 할 수 있는지를 말하며, 메시지가 나가려면 둘 다 맞아야 합니다.
토큰 자체에는 여전히 스코프가 없다
바뀌지 않은 것은 권한 부여입니다. 앱이 받는 토큰은 승인하면서 고른 일부가 아니라 역할이 허용하는 모든 것에 닿으므로, 클라이언트를 승인한다는 것은 그 워크스페이스에서 내가 할 수 있는 모든 일을 승인한다는 뜻입니다. 무엇이 요청하는지는 무언가가 부여되기 전에 표시되고, 계정 → 연결된 앱에서 나중에 제거하면 그 앱이 보유한 모든 토큰과 그 뒤의 승인까지 삭제되지만, "이 앱에는 읽기 전용으로"를 고르는 기능은 만들어져 있지 않습니다.
그래서 MCP 클라이언트의 상한은 사용자 본인의 상한입니다. 앱이 할 수 있는 일을 좁히려면 그것을 연결한 사람의 역할을 좁혀야 하고, 그러면 그 사람이 앱에서 할 수 있는 일도 함께 좁아집니다. 이것이 오늘의 솔직한 모습이고, 권한 부여별 스코프를 여전히 만들 가치가 있는 이유입니다.
어휘는 이미 공유되어 있습니다. 역할의 권한과 API 키의 스코프는 하나의 알파벳에서 나오며, 그래서 키의 권한을 둘의 교집합으로 계산할 수 있습니다. 권한 부여별 MCP 스코프도 나올 때는 같은 말로 표현될 것입니다.