MCP 도구 인터페이스 설계: 작은 입력 스키마, 오류 반환, 멱등성
모델이 잘 고르고 안전하게 재시도할 수 있는 도구를 만드는 기준
핵심 요약
- 도구 설명에는 언제 쓰는지와 함께 언제 쓰면 안 되는지, 실패 조건을 적는다.
- 입력 스키마는 필드를 줄이고 enum·pattern·additionalProperties: false로 닫는다.
- 업무 오류는 isError: true 결과로, 원인·현재 상태·다음 행동을 담아 반환한다.
- 상태 변경 도구는 idempotency_key로, 다단계 상태는 사용자와 묶인 난수 핸들로 관리한다.
MCP 서버의 품질은 도구 개수보다 도구 하나하나의 인터페이스에서 갈린다. 입력이 많고 설명이 모호한 도구는 모델이 잘못된 인자로 호출하고, 오류 메시지가 불친절하면 같은 실패를 반복한다. 네트워크가 끊겨 재시도했을 때 주문이 두 번 생성되는 문제도 인터페이스 설계에서 막아야 한다. 이 글은 MCP 2026-07-28 Tools 명세를 기준으로 도구 설계 원칙을 참조용으로 정리한다. 재시도 정책 자체는 에이전트 서킷 브레이커와 재시도 전략 글에서 다뤘다.
이름과 설명: 모델이 도구를 고르는 근거
| 항목 | 명세·권장 사항 | 예 |
|---|---|---|
| 이름 길이·문자 | 1~128자, 영문·숫자·_·-·.만, 대소문자 구분 | orders.cancel, get_invoice |
| 이름 고유성 | 서버 안에서 고유. 여러 서버를 묶는 클라이언트는 서버 접두사로 충돌 해소 | search 대신 orders.search |
| title | 사람에게 보여 줄 표시 이름(선택) | "주문 취소" |
| description | 언제 쓰는지, 입력 형식, 실패 조건, 부작용 | "결제 완료 전 주문만 취소한다. 배송 시작 후에는 오류." |
설명에는 "무엇을 하는가"뿐 아니라 "언제 쓰면 안 되는가"를 적는다. 비슷한 도구가 여러 개라면 설명에서 서로의 차이를 밝혀 모델이 고를 수 있게 한다.
입력 스키마는 작고 닫힌 형태로
{
"name": "orders.cancel",
"description": "결제 완료 전 주문을 취소한다. 같은 idempotency_key로 다시 호출하면 첫 결과를 그대로 반환한다.",
"inputSchema": {
"type": "object",
"properties": {
"order_id": { "type": "string", "pattern": "^ORD-[0-9]{8}$" },
"reason": { "type": "string", "enum": ["customer_request", "out_of_stock", "duplicate"] },
"idempotency_key": { "type": "string", "minLength": 16, "maxLength": 64 }
},
"required": ["order_id", "reason", "idempotency_key"],
"additionalProperties": false
},
"annotations": { "destructiveHint": true, "idempotentHint": true, "openWorldHint": false }
}- 필드 수 최소화: 모델이 채워야 할 필드가 늘수록 잘못 채울 가능성도 커진다. 서버가 알 수 있는 값(현재 사용자, 시각)은 입력으로 받지 않는다.
- 자유 문자열 대신 열거형:
enum,pattern,maxLength로 허용 값을 좁힌다. - 닫힌 객체:
additionalProperties: false로 예상하지 못한 필드를 거부한다. 인자가 없는 도구도 명세가 권장하는 이 형태를 쓴다. - 민감 정보 금지: 비밀번호·토큰을 입력으로 받지 않는다. 명세는 민감한 매개변수에 HTTP 헤더로 복사되는
x-mcp-header를 붙이지 말라고 경고한다.
출력은 구조화하고, 텍스트도 함께
outputSchema를 정의하면 서버는 스키마에 맞는 structuredContent를 반환해야 하고, 클라이언트는 이를 검증하는 것이 권장된다. 명세는 하위 호환을 위해 같은 JSON을 텍스트 콘텐츠로도 함께 넣으라고 권한다. 큰 결과는 전부 넣기보다 요약과 함께 resource_link로 상세 데이터를 가리키게 하면 모델 컨텍스트를 아낄 수 있다.
오류는 두 종류로 나눠 반환한다
| 종류 | 언제 | 형식 | 모델의 대응 |
|---|---|---|---|
| 프로토콜 오류 | 알 수 없는 도구, 요청 형식 오류, 서버 오류 | JSON-RPC error(예: -32602) | 복구 가능성이 낮음 |
| 도구 실행 오류 | API 실패, 입력값 검증 실패, 업무 규칙 위반 | result.isError: true와 설명 텍스트 | 메시지를 읽고 인자를 고쳐 재시도 |
{
"result": {
"content": [{ "type": "text", "text": "주문 ORD-20261003은 이미 배송이 시작되어 취소할 수 없습니다. returns.create 도구로 반품을 접수하세요." }],
"isError": true
}
}좋은 오류 메시지는 원인, 현재 상태, 다음에 할 수 있는 행동을 담는다. 명세의 예시도 "출발일은 미래여야 한다. 현재 날짜는 …"처럼 모델이 스스로 고칠 수 있는 정보를 준다.
멱등성: 재시도해도 결과가 한 번만 생기게
클라이언트는 도구 호출에 타임아웃을 두는 것이 권장되므로, 서버가 처리 중일 때 같은 요청이 다시 들어올 수 있다. 상태를 바꾸는 도구는 다음 순서로 멱등성을 보장한다.
- 입력에
idempotency_key를 필수로 둔다. - 처리 전에 (사용자 ID, 키) 조합으로 이전 결과가 저장돼 있는지 확인한다.
- 있으면 저장된 결과를 그대로 반환하고, 없으면 처리 후 결과를 저장한다.
- 키 보존 기간(예: 24시간)을 도구 설명에 적어 모델이 알 수 있게 한다.
도구 주석의 idempotentHint, destructiveHint, readOnlyHint, openWorldHint는 클라이언트가 확인 절차를 정하는 데 쓰는 힌트다. 명세는 신뢰하는 서버가 아니면 주석을 신뢰하지 말라고 하므로, 주석은 보조 정보일 뿐 서버 쪽 검증을 대신하지 않는다.
여러 호출에 걸친 상태는 명시적 핸들로
2026-07-28 명세에는 프로토콜 수준 세션이 없다. 장바구니, 브라우저 컨텍스트, DB 트랜잭션처럼 상태가 필요하면 생성 도구가 핸들을 반환하고 이후 호출이 그 핸들을 인자로 받는다. 보안 모범 사례는 핸들을 인증 수단으로 취급하지 말고, 예측 불가능한 난수로 만들며, 서버 쪽에서 인증된 사용자와 묶어(예: 사용자ID:핸들) 다른 사용자가 쓰지 못하게 하라고 권한다. 만료된 핸들로 호출하면 도구 실행 오류로 알려 모델이 새 핸들을 만들게 한다.
무상태 전환에 따른 기존 서버 점검 순서는 2026-07-28 스펙 마이그레이션 글에 정리했다.
초보자가 자주 실수하는 포인트
- 서버가 알 수 있는 사용자 ID를 입력으로 받아 다른 사용자 데이터에 접근할 여지를 주는 경우
- 모든 실패를 "error"라는 한 단어로 반환하는 경우
- 재시도를 고려하지 않아 같은 주문이 두 번 생성되는 경우
- 순차 증가하는 번호를 상태 핸들로 써서 추측 가능하게 만드는 경우
체크리스트
- 도구 이름이 서버 안에서 고유하고 명세 문자 규칙을 지키는가
- 입력 스키마가 닫힌 객체이며 필수 필드가 최소인가
- 업무 오류 메시지에 다음 행동이 포함되는가
- 상태 변경 도구가 멱등성 키를 받는가
- 상태 핸들이 난수이며 사용자와 묶여 검증되는가
자주 묻는 질문
도구를 잘게 나누는 것과 하나로 합치는 것 중 무엇이 좋나요?
모델이 구분해서 고를 수 있을 만큼 목적이 다르면 나눈다. 다만 도구가 너무 많으면 목록이 길어지므로, 같은 목적의 변형은 enum 인자로 합치는 것을 검토한다.
도구 목록 순서도 중요한가요?
명세는 도구 집합이 바뀌지 않았다면 같은 순서로 반환하라고 권한다. 클라이언트 캐시와 프롬프트 캐시 적중률에 영향을 준다.
outputSchema를 꼭 정의해야 하나요?
선택 사항이지만 정의하면 클라이언트가 결과를 검증하고 프로그래밍 언어 타입으로 다루기 쉬워진다.
참고 자료 · 검증 기준
위 자료와 내용을 대조한 날짜: . 도구·서비스 정책은 이후 바뀔 수 있으므로 적용 전 공식 문서를 다시 확인하세요.
이 글은 위 참고 자료를 바탕으로 정리했으며, 내용은 운영 과정에서 순차적으로 보완될 수 있습니다.