MCP 도구 어노테이션: readOnlyHint와 클라이언트 활용법
MCP 도구 어노테이션은 readOnlyHint 같은 선택적 힌트입니다. 각 힌트의 의미와 기본값, 그리고 ChatGPT·VS Code·Copilot이 이를 쓰는 방식을 정리합니다.

MCP 도구 어노테이션(tool annotations)은 서버가 도구마다 붙여 그 도구의 동작을 설명하는 선택적 힌트로, readOnlyHint, destructiveHint, idempotentHint, openWorldHint, 그리고 표시용 title이 있습니다. 클라이언트는 이를 읽고 어떤 호출에 사람의 승인이 필요한지 같은 것을 정하지만, 어노테이션은 보장이 아니라 힌트입니다. 명세는 신뢰할 수 있는 서버에서 온 것이 아니면 어노테이션을 신뢰하지 말라고 합니다.
정의는 MCP 명세 2025-11-25 버전의 스키마 레퍼런스와 Tools 페이지에서 가져왔습니다. 클라이언트 동작은 각 클라이언트의 자체 문서에서, 예시로 든 Sume 호스팅 MCP 서버 내용은 그 코드와 MCP 도구와 게이트에서 가져왔습니다. 모두 2026-09-27에 확인했습니다.
각 어노테이션은 무엇을 뜻하나요?
네 힌트는 모두 불리언이며, 서버가 생략했을 때 적용되는 기본값이 각각 있습니다.
- 이 기본값대로 읽으면, 어노테이션을 보내지 않는 도구는 파괴적일 수 있고 외부 개체에 닿을 수 있는 쓰기 도구입니다.
title은 사람이 읽기 좋은 이름입니다. 표시할 때 명세가 정한 순서는 도구의title, 그다음annotations.title, 그다음name입니다.
| 어노테이션 | true일 때 의미 | 기본값 |
|---|---|---|
readOnlyHint | 도구가 환경을 수정하지 않음 | false |
destructiveHint | 도구가 파괴적 업데이트를 할 수 있음. false는 추가만 하는 업데이트를 뜻함. readOnlyHint가 false일 때만 의미가 있음 | true |
idempotentHint | 같은 인수로 반복 호출해도 추가 효과가 없음. readOnlyHint가 false일 때만 의미가 있음 | false |
openWorldHint | 도구가 웹 검색처럼 외부 개체로 이뤄진 열린 세계와 상호작용할 수 있음. 메모리 도구의 세계는 닫혀 있음 | true |
어노테이션은 도구 정의의 어디에 들어가나요?
서버가 tools/list에서 반환하는 각 도구의 annotations 객체에 들어가며, name, description, inputSchema와 나란히 놓입니다. 아래는 명세의 날씨 예시를 줄이고 어노테이션을 더한 것입니다. 아무것도 바꾸지 않고 외부 서비스를 호출하는 조회 도구입니다.
{
"name": "get_weather",
"title": "Weather Information Provider",
"description": "Get current weather information for a location",
"inputSchema": {
"type": "object",
"properties": {
"location": { "type": "string", "description": "City name or zip code" }
},
"required": ["location"]
},
"annotations": {
"readOnlyHint": true,
"openWorldHint": true
}
}MCP 도구 어노테이션은 강제되나요?
강제되지 않습니다. 명세는 ToolAnnotations의 모든 속성을 도구를 충실하게 설명한다는 보장이 없는 힌트라고 부릅니다. 클라이언트는 신뢰할 수 없는 서버의 어노테이션을 근거로 도구 사용을 결정해서는 절대 안 되며, 신뢰할 수 있는 서버에서 온 것이 아니면 어노테이션을 신뢰할 수 없는 것으로 간주해야 합니다. Mastra 문서는 그 위험을 분명하게 설명합니다. 악의적이거나 버그가 있는 서버는 읽기 전용이 아닌 도구를 읽기 전용이라고 주장할 수 있습니다.
MCP 클라이언트는 readOnlyHint를 어떻게 쓰나요?
클라이언트마다 다릅니다. 읽기 전용으로 표시되지 않은 호출은 모두 먼저 묻는 클라이언트가 있고, 그런 도구를 아예 빼는 클라이언트가 하나 있으며, 정책을 여러분의 코드에 맡기는 클라이언트도 있습니다.
| 클라이언트 | 문서 내용 |
|---|---|
| ChatGPT 개발자 모드 | 쓰기 작업은 기본적으로 확인 필요. readOnlyHint를 따르며, 이 힌트가 없는 도구는 쓰기 작업으로 취급 |
| VS Code | readOnlyHint로 표시되지 않은 모든 도구에 확인 대화상자를 띄움. 읽기 전용 도구는 확인 없이 실행 |
| GitHub Copilot 코드 리뷰 | annotations.readOnlyHint가 true일 때만 도구를 사용. 없거나 false면 제외 |
| AI SDK | 도구 메타데이터에 어노테이션을 노출하지만, 이를 자동으로 승인 정책으로 바꾸지는 않음 |
| Mastra | 어노테이션을 requireToolApproval 함수에 넘김. 어노테이션을 근거로 한 승인 완화는 신뢰하는 서버에만 적용 |
Sume MCP 서버는 어떤 값을 설정하나요?
현재 코드에서 https://mcp.sume.com/mcp의 Sume 호스팅 서버는 모든 도구에 네 가지 힌트를 모두 붙입니다. 그 위에 Sume 자체 게이트가 더해집니다. OAuth 세션에 mcp:write가 생기기 전까지 쓰기·유료 도구는 숨겨지고, 모든 쓰기·유료 호출에는 idempotency_key가 필요합니다. 현재 코드가 설정하는 값은 다음과 같습니다.
tools_list,jobs_status,jobs_wait같은 읽기 도구에는readOnlyHint: true,idempotentHint: true,destructiveHint: false가 설정됩니다.generate_video,video_trim같은 쓰기·유료 도구에는readOnlyHint: false와idempotentHint: false가 설정됩니다.destructiveHint: true인 도구는jobs_cancel하나뿐입니다. 모든 도구는openWorldHint: false를 설정합니다.tools_list는 프로토콜 어노테이션과 별도로 도구마다 Sumesafety블록도 반환하며, 여기에는read_only,paid_generation,requires_idempotency_key같은 필드가 있습니다. 자세한 내용은 Sume MCP 도구 목록에서 다룹니다.- 그래서 ChatGPT는 유료 Sume 도구를 호출하기 전에는 확인을 요청하지만, 상태 읽기는 읽기 전용으로 취급합니다. 이 흐름은 ChatGPT에 MCP 서버를 추가하는 방법에서 볼 수 있습니다.
출처
- Model Context Protocol: 스키마 레퍼런스(2025-11-25) (2026-09-27 확인)
- Model Context Protocol: Tools(2025-11-25) (2026-09-27 확인)
- OpenAI API: ChatGPT 개발자 모드 (2026-09-27 확인)
- VS Code: MCP 개발자 가이드 (2026-09-27 확인)
- GitHub Docs: 저장소용 MCP 서버 설정하기 (2026-09-27 확인)
- AI SDK: MCP 도구 (2026-09-27 확인)
- Mastra: MCPClient 레퍼런스 (2026-09-27 확인)
- MCP 도구와 게이트
- MCP OAuth와 API 키
관련 글
개발자 카테고리의 다른 글
- Python 이미지 생성 API: AI 이미지 생성하고 저장하기
Python에서 Requests로 이미지를 생성하세요. 이미지 API에 프롬프트를 POST하고, 200이면 URL을 읽고 202면 Job을 폴링한 뒤 파일을 하나씩 저장합니다.
- JavaScript 음성 인식 API: Node.js에서 오디오를 텍스트로
서버의 JavaScript 코드에서 음성 인식 API를 호출하세요. Node.js에서 Sume SDK로 오디오 파일 URL을 보내고, Job을 기다린 뒤 텍스트를 읽습니다.
- Python 음성 인식(STT): 오디오를 타임스탬프와 함께 텍스트로
Python에서 Requests로 음성을 텍스트로 변환하세요. 오디오 URL을 보내고 Job을 폴링한 뒤 전사문과 단어별 타임스탬프를 읽는 Sume STT 1.0 스크립트입니다.
- 브라우저에서 Sume API 호출 시 CORS 오류: 해결 방법
브라우저는 내 사이트에서 api.sume.com으로 직접 보내는 호출을 차단하며, API 키는 프론트엔드 코드에 절대 넣으면 안 됩니다. 서버에서 Sume를 호출해 프록시하세요.
작성자 Sume