~22 min · tools, side-effects, schema, annotations
Level 0호기심 많은 독자
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete
MCP 의 Tool 은 여느 provider tool-calling API 의 tool 과 생김새가 같아. 이름, description, input schema. Resource 와 갈리는 핵심은 tool 이 일을 벌인다 는 거야 — 세상에 side effect 를 남길 수 있거든. Protocol 도 이걸 인정해서, tool description 마다 annotation 을 붙일 수 있게 열어놨어 (readOnlyHint, destructiveHint, idempotentHint, openWorldHint). Host 는 user 한테 승인을 물을 때 이걸 꺼내 보여줄 수 있어.
흐름은 이래. Client 가 tool 목록을 받아오고, host 가 그걸 LLM 의 tool 목록에 합쳐 넣고, LLM 이 tool call 을 내놓고, host 가 server 에 tools/call 을 보내고, server 가 실행해서 정돈된 결과를 돌려주고, host 가 그 결과를 LLM 에 다시 넣어주고, LLM 이 더 부르거나 끝내. Server 는 인자를 검사하고, 재시도에도 안전하도록 idempotency 를 지키고, 에러를 정돈된 모양으로 돌려줄 책임을 져. Host 는 파괴적인 의도를 user 눈앞에 꺼내 보일 책임을 지고.
미묘한 지점이 하나 있어. Tool 결과는 그냥 문자열이 아니라 정돈된 content 야. 결과는 content item 의 목록이고, 각 item 은 텍스트일 수도, 이미지일 수도, 오디오일 수도, resource 참조일 수도 있어. Tool 하나가 차트 이미지와 요약 텍스트를 같이 돌려줘도 되고, host 가 읽어갈 resource URI 목록을 돌려줘도 돼. Tool 결과를 문자열 하나로만 다루면 protocol 이 준 걸 반쯤 버리는 셈이야.
// Client -> Server
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
// Server -> Client
{"jsonrpc":"2.0","id":2,"result":{"tools":[
{"name":"refund_order","description":"Issue a refund. Idempotent on (order_id, amount_cents).",
"inputSchema":{"type":"object","properties":{...},"required":["order_id","amount_cents","reason"]},
"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true}}
]}}
// Client -> Server
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"refund_order","arguments":{...}}}
작은 server 에 write tool 을 하나 붙여. destructiveHint=true 와 openWorldHint=true 로 표시해. Claude Desktop 이나 MCP 를 아는 client 로 붙어서, 모델이 처음 그걸 부르려 할 때 host 가 경고를 꺼내는지 봐. Read-only tool 보다 확인 창이 더 무섭게 보인다면 annotation 이 제대로 동작하는 거야.
Progress
Progress is local-only — sign in to sync across devices.