MCP 도구에 annotations 달기 — description 밖에서 행동을 힌트하는 법
MCP 도구는 description 말고도 annotations라는 채널로 자신의 행동 특성을 알릴 수 있다. readOnlyHint·destructiveHint·idempotentHint·openWorldHint 네 필드가 각각 무엇을 뜻하는지, 왜 힌트일 뿐 보장이 아닌지, registerTool에 실제로 붙이는 코드까지 정리한다.
32개의 글 · 2 / 4 페이지
MCP 도구는 description 말고도 annotations라는 채널로 자신의 행동 특성을 알릴 수 있다. readOnlyHint·destructiveHint·idempotentHint·openWorldHint 네 필드가 각각 무엇을 뜻하는지, 왜 힌트일 뿐 보장이 아닌지, registerTool에 실제로 붙이는 코드까지 정리한다.
MCP 도구가 URL을 인자로 받아 대신 요청을 보낼 때 생기는 SSRF 취약점을 다룬다. 문자열 패턴 매칭으로는 왜 못 막는지, 호스트명이 아니라 실제 연결되는 IP를 검사해야 하는 이유, DNS 리바인딩의 한계와 허용 목록이라는 더 단순한 대안까지 코드로 정리한다.
MCP의 세 primitive(Tools, Resources, Prompts)는 클라이언트가 서버에게 요청하는 방향이지만, Sampling은 그 반대다 — 서버가 클라이언트에게 LLM 완성을 요청한다. 서버가 API 키 없이도 지능을 빌리는 이 흐름의 동작 방식과, 이 블로그의 무인 발행 파이프라인이 대신 헤드리스 호출을 택한 이유를 코드로 정리한다.
MCP 도구가 셸 명령을 실행할 때, 그 인자를 채우는 것은 사람이 아니라 LLM이다. 문자열을 조합해 exec에 넘기는 흔한 패턴이 왜 커맨드 인젝션으로 이어지는지, 간접 프롬프트 인젝션이 이 위험을 어떻게 키우는지, execFile로 셸을 아예 거치지 않는 해법까지 코드로 정리한다.
MCP가 에이전트 아래로 도구를 꽂는 수직 연결이라면, A2A는 에이전트끼리 옆으로 대화하는 수평 연결이다. 상대를 스키마가 정해진 함수로 보느냐, 속을 알 수 없는 행위자로 보느냐 — 두 프로토콜이 다른 문제를 푸는 이유를 Agent Card와 Task 개념으로 정리한다.
MCP 서버의 진짜 검증은 단위 테스트가 아니라 실전 클라이언트다. claude mcp add 한 줄로 Claude Code에 붙이고, 도구 선택·거부 메시지·경계 강제라는 상호작용 단위의 테스트법과 stdout 오염·재빌드 미스 같은 함정을 이 프로젝트의 Phase 2 경험으로 정리한다.
MCP와 function calling은 경쟁 관계가 아니라 다른 층에 있다. function calling은 모델이 도구 호출 의사를 표현하는 출력 형식이고, MCP는 그 형식에 흘려 넣을 도구를 조달하는 공급 규격이다. 두 층이 한 번의 도구 호출에서 어떻게 맞물리는지 실제 요청 형태로 구분한다.
MCP에서 도구 실패는 프로토콜 에러와 실행 에러 두 층으로 나뉘고, 실행 에러는 isError: true를 얹은 정상 결과로 돌아간다. 이 텍스트는 LLM이 읽고 행동을 바꾸는 입력이다 — 무엇이·왜 실패했고 다음에 뭘 하면 되는지를 담는 에러 메시지 설계법을 실제 코드로 정리한다.
MCP 도구는 LLM이 스스로 고른다. 이때 모델이 보는 건 구현 코드가 아니라 이름·description·입력 스키마뿐이다. 설명문이 곧 도구의 인터페이스인 이유와, 무엇을·언제·경계를 담아 선택률을 높이는 실무 규칙을 예제로 정리한다.
MCP 도구는 description 말고도 annotations라는 채널로 자신의 행동 특성을 알릴 수 있다. readOnlyHint·destructiveHint·idempotentHint·openWorldHint 네 필드가 각각 무엇을 뜻하는지, 왜 힌트일 뿐 보장이 아닌지, registerTool에 실제로 붙이는 코드까지 정리한다.
MCP 도구가 URL을 인자로 받아 대신 요청을 보낼 때 생기는 SSRF 취약점을 다룬다. 문자열 패턴 매칭으로는 왜 못 막는지, 호스트명이 아니라 실제 연결되는 IP를 검사해야 하는 이유, DNS 리바인딩의 한계와 허용 목록이라는 더 단순한 대안까지 코드로 정리한다.
MCP의 세 primitive(Tools, Resources, Prompts)는 클라이언트가 서버에게 요청하는 방향이지만, Sampling은 그 반대다 — 서버가 클라이언트에게 LLM 완성을 요청한다. 서버가 API 키 없이도 지능을 빌리는 이 흐름의 동작 방식과, 이 블로그의 무인 발행 파이프라인이 대신 헤드리스 호출을 택한 이유를 코드로 정리한다.
MCP 도구가 셸 명령을 실행할 때, 그 인자를 채우는 것은 사람이 아니라 LLM이다. 문자열을 조합해 exec에 넘기는 흔한 패턴이 왜 커맨드 인젝션으로 이어지는지, 간접 프롬프트 인젝션이 이 위험을 어떻게 키우는지, execFile로 셸을 아예 거치지 않는 해법까지 코드로 정리한다.
MCP가 에이전트 아래로 도구를 꽂는 수직 연결이라면, A2A는 에이전트끼리 옆으로 대화하는 수평 연결이다. 상대를 스키마가 정해진 함수로 보느냐, 속을 알 수 없는 행위자로 보느냐 — 두 프로토콜이 다른 문제를 푸는 이유를 Agent Card와 Task 개념으로 정리한다.
MCP 서버의 진짜 검증은 단위 테스트가 아니라 실전 클라이언트다. claude mcp add 한 줄로 Claude Code에 붙이고, 도구 선택·거부 메시지·경계 강제라는 상호작용 단위의 테스트법과 stdout 오염·재빌드 미스 같은 함정을 이 프로젝트의 Phase 2 경험으로 정리한다.
MCP와 function calling은 경쟁 관계가 아니라 다른 층에 있다. function calling은 모델이 도구 호출 의사를 표현하는 출력 형식이고, MCP는 그 형식에 흘려 넣을 도구를 조달하는 공급 규격이다. 두 층이 한 번의 도구 호출에서 어떻게 맞물리는지 실제 요청 형태로 구분한다.
MCP에서 도구 실패는 프로토콜 에러와 실행 에러 두 층으로 나뉘고, 실행 에러는 isError: true를 얹은 정상 결과로 돌아간다. 이 텍스트는 LLM이 읽고 행동을 바꾸는 입력이다 — 무엇이·왜 실패했고 다음에 뭘 하면 되는지를 담는 에러 메시지 설계법을 실제 코드로 정리한다.
MCP 도구는 LLM이 스스로 고른다. 이때 모델이 보는 건 구현 코드가 아니라 이름·description·입력 스키마뿐이다. 설명문이 곧 도구의 인터페이스인 이유와, 무엇을·언제·경계를 담아 선택률을 높이는 실무 규칙을 예제로 정리한다.
비공개로 의견 보내기
작성자에게만 전달돼요. 이름·이메일을 비우면 완전 익명입니다.