2026 Practical Guide

MCP & Tool
설계 가이드

모델에게 능력을 주는 일은 곧 인터페이스를 설계하는 일이다
좋은 Tool은 좋은 API와 다르다 — 소비자가 사람이 아니라 모델이기 때문이다

3 핵심 프리미티브
10 Tool 설계 원칙
6 피해야 할 안티패턴

MCP란 무엇인가

Model Context Protocol — 모델과 외부 세계 사이의 표준 어댑터

MCP는 "AI를 위한 USB-C"다. 모델 하나에 도구·데이터·시스템을 붙일 때마다 매번 다른 연결 방식을 발명하던 시절이 있었다. MCP는 그 연결을 하나의 프로토콜로 표준화한다. 한쪽엔 호스트(Claude, IDE, 에이전트)가, 다른 쪽엔 MCP 서버(깃허브, DB, 사내 시스템)가 있고, 둘은 약속된 메시지 규격으로만 대화한다. 서버 하나를 만들어 두면 그 프로토콜을 말하는 어떤 호스트에도 꽂힌다.
관점MCP 이전MCP 이후
통합 방식 호스트마다 전용 플러그인 (N×M 문제) 서버 1개 → 모든 호스트가 사용 (N+M)
표준 제각각의 함수 호출 포맷 JSON-RPC 2.0 기반 공통 규격
생태계 벤더 종속 2026년 들어 주요 코딩 에이전트가 폭넓게 채택, Linux Foundation 산하로 거버넌스 이관
역할 "모델이 무엇을 아는가" "모델이 무엇을 할 수 있는가"

* 생태계 수치·채택 현황은 2026년 6월 기준 스냅샷입니다. 최신 현황은 modelcontextprotocol.io에서 확인하세요.

3가지 프리미티브

MCP 서버가 호스트에 제공하는 것은 결국 이 세 가지다

1

Tools — 실행하는 함수

모델이 호출해 부작용을 일으키는 행동. "쓰기"의 자리

검색하기, 이슈 만들기, 쿼리 실행하기 — 모델이 결정하고 호출하는 능동적 행동이다. 입력 스키마(JSON Schema)와 설명을 가지며, 이 가이드 §4의 설계 원칙 대부분이 여기에 해당한다. 부작용이 있을 수 있으므로 annotations로 읽기 전용·파괴적 여부를 표시한다.

2

Resources — 읽기 전용 컨텍스트

모델/호스트가 읽어 들이는 데이터. "읽기"의 자리

파일 내용, DB 레코드, 문서 — URI로 식별되는 읽기 전용 데이터다. Tool과의 핵심 차이는 부작용이 없고, 보통 호스트(앱)가 주도해 컨텍스트로 끌어온다는 점이다. "이 PDF를 컨텍스트에 넣어줘" 같은 흐름이 Resource다.

3

Prompts — 재사용 워크플로우 템플릿

사용자가 골라 쓰는 정형화된 작업. "슬래시 명령"의 자리

"이 코드 리뷰해줘", "릴리스 노트 만들어줘"처럼 인자를 받아 펼쳐지는 프롬프트 템플릿이다. 보통 사용자가 명시적으로 선택한다(슬래시 명령·메뉴). 자주 쓰는 작업을 서버가 검증된 형태로 제공해, 매번 프롬프트를 다시 쓰지 않게 한다.

누가 주도하는가로 구분하면 쉽다. Tools는 모델이 골라 호출하고, Resources는 이 컨텍스트로 끌어오며, Prompts는 사용자가 선택해 실행한다. 셋을 헷갈려 전부 Tool로 만들면, 읽기 전용 데이터까지 모델이 매번 "호출 결정"을 해야 해서 도구 목록만 비대해진다.

동작 원리

메시지 규격, 전송 방식, 인증 — 만들기 전에 알아야 할 골격

A

Host · Client · Server

세 역할의 분리
Host / Client

호스트는 모델을 품은 앱(Claude, IDE). 각 서버 연결마다 클라이언트를 하나씩 띄워 1:1로 통신한다.

Server

당신이 만드는 쪽. Tools·Resources·Prompts를 노출한다. 호스트가 무엇인지 몰라도 동작한다.

서버는 호스트에 독립적이다 — 한 번 만들면 프로토콜을 말하는 모든 호스트에서 재사용된다. 이게 MCP의 핵심 이득이다.

B

JSON-RPC 2.0 · 전송 방식

메시지는 어떻게 오가나

모든 메시지는 JSON-RPC 2.0 규격을 따른다. 전송 계층은 두 갈래다 — 로컬 프로세스는 stdio(표준 입출력), 원격 서버는 Streamable HTTP. 같은 메시지 규격을 쓰므로 서버 로직은 전송 방식과 분리해 작성한다.

// tools/call 요청 (호스트 → 서버) { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "search_orders", "arguments": { "status": "shipped" } } }
C

인증 — OAuth 2.1

원격 서버의 권한 관문

원격 HTTP 서버는 OAuth 2.1 기반 인증을 표준으로 쓴다. 핵심은 최소 권한이다 — 토큰 스코프를 작업에 필요한 만큼만 발급하고, 비밀 키는 서버 쪽에만 둔다. 모델이 보는 도구 정의에 자격 증명이 새어 나가지 않게 한다.

Tool 설계 10원칙

소비자가 사람이 아니라 모델이라는 점이 모든 것을 바꾼다

1

이름은 동사+명사, 의도가 드러나게

모델은 이름만 보고 쓸지 말지 추론한다

search_orders·create_issue처럼 행동이 즉시 읽히는 이름을 쓴다. do_action·handle 같은 모호한 이름은 모델을 헷갈리게 한다. 이름은 모델이 도구를 고르는 첫 번째 신호다.

2

설명(description)이 곧 프롬프트다

언제 쓰고, 언제 안 쓰는지까지

description은 사람용 주석이 아니라 모델에게 주는 지시문이다. "무엇을 하는가"뿐 아니라 "언제 적절하고, 언제는 다른 도구를 써야 하는가"를 적는다. 가장 ROI 높은 한 줄 투자다.

3

파라미터는 적게, 타입은 엄격하게

JSON Schema · enum · required 활용

자유 텍스트 파라미터는 모델이 틀리기 쉽다. 가능한 값이 정해져 있으면 enum으로 고정하고, 필수값은 required로 못박는다. 파라미터가 많을수록 잘못 채울 확률이 올라가니, 꼭 필요한 것만 남긴다.

4

출력은 모델이 읽기 쉬운 형태로

그리고 토큰을 아끼게

응답은 모델이 다시 파싱한다. 군더더기 없는 구조화된 결과를 돌려주고, 사람용 장식(HTML·과한 메타데이터)은 뺀다. 응답 한 번이 곧 컨텍스트 토큰이라는 점을 늘 의식한다.

5

에러는 모델이 복구할 수 있게

실패 이유 + 다음 행동 힌트

스택 트레이스를 그대로 던지지 말 것. "주문 ID를 찾을 수 없음 — 형식은 ORD-XXXX입니다" 처럼 왜 실패했고 어떻게 고치는지를 자연어로 준다. 그래야 모델이 재시도로 자가 복구한다.

6

파괴적 작업엔 승인 게이트

human-in-the-loop는 선택이 아니다

삭제·결제·외부 발송처럼 되돌리기 어려운 작업은 실행 전 사람 승인을 거치게 한다. annotations.destructiveHint로 표시하고, 호스트가 확인 단계를 띄울 수 있게 한다. 자동화의 편리함보다 안전이 먼저다.

7

도구 개수를 통제하라

많을수록 선택 정확도가 떨어진다

도구 50개를 한꺼번에 던지면 모델이 엉뚱한 걸 고른다(컨텍스트 로트). 비슷한 기능은 하나로 묶고, 맥락에 따라 노출할 도구를 라우팅한다. "있는 기능 전부 노출"이 아니라 "지금 필요한 것만"이 원칙이다.

8

부작용과 멱등성을 표시하라

readOnlyHint · idempotentHint

읽기 전용인지(readOnlyHint), 같은 호출을 반복해도 안전한지(idempotentHint)를 명시한다. 호스트와 모델이 재시도·병렬 호출을 안전하게 결정하는 근거가 된다.

9

큰 응답엔 페이지네이션·상한

거대 결과는 컨텍스트를 잡아먹는다

10만 행을 그대로 반환하면 컨텍스트가 터지고 비용이 폭발한다. 기본 개수 제한과 커서 기반 페이지네이션을 두고, 모델이 필요하면 더 요청하게 한다.

10

권한은 최소로, 비밀은 서버에

OAuth 2.1 · 스코프 최소화

도구가 가진 권한이 곧 사고 시 피해 범위다. 작업에 필요한 최소 스코프만 부여하고, API 키·토큰은 서버 내부에만 둔다. 모델이 보는 인터페이스에 자격 증명을 절대 노출하지 않는다.

흔한 실수 6가지

대부분의 MCP 서버가 같은 곳에서 넘어진다

!

이미 있는 서버를 다시 만든다

가장 흔한 낭비. 깃허브·슬랙·DB 등 주요 시스템은 공식·커뮤니티 서버가 대개 이미 있다.

→ 만들기 전에 레지스트리부터 검색한다. 없을 때만 만든다.
!

REST 엔드포인트를 1:1로 노출

기존 API 50개를 그대로 도구 50개로 만든다. 모델은 사람과 다르게 쓴다 — 도구가 너무 잘고 많아진다.

→ 모델의 "의도" 단위로 묶는다. get_user+get_ordersget_customer_summary.
!

description을 비우거나 사람용으로 쓴다

"주문 조회 API" 한 줄로 끝낸다. 모델은 언제 이 도구를 써야 할지 단서를 못 얻는다.

→ 언제 쓰고 언제 안 쓰는지, 입력 예시까지 모델 관점으로 적는다.
!

거대한 응답을 그대로 반환

전체 테이블·전체 로그를 통째로 돌려준다. 컨텍스트가 터지고 토큰 비용이 폭증한다.

→ 기본 상한 + 페이지네이션 + 필요한 필드만 추린 요약.
!

파괴적 작업에 승인 게이트가 없다

모델이 곧장 삭제·송금·메일 발송을 실행하게 둔다. 한 번의 오판이 돌이킬 수 없는 결과를 만든다.

→ destructiveHint 표시 + 실행 전 사람 확인 단계.
!

도구 50개 던져놓고 알아서 고르길 기대

"많이 줄수록 똑똑해지겠지"는 거꾸로다. 선택지가 많을수록 오선택이 늘고 비용도 늘어난다.

→ 맥락별 라우팅으로 노출 도구를 좁히고, 비슷한 건 통합한다.

시작하기 — 살까, 만들까

새 서버를 만들기 전에 거치는 3단계 판단

Step 1

이미 있는가?

공식·커뮤니티 MCP 서버 레지스트리를 먼저 검색한다. 깃허브·슬랙·구글드라이브·Postgres 등은 대부분 이미 존재한다. 있으면 쓴다 — 자체 구현은 유지보수 부채다.

Step 2

내부 전용인가?

사내 시스템·자체 DB·도메인 로직처럼 공개 서버가 있을 수 없는 경우에만 직접 만든다. 공식 SDK(파이썬·타입스크립트 등)로 시작하고, §4의 설계 원칙을 체크리스트로 쓴다.

Step 3

읽기부터, 쓰기는 게이트와 함께

읽기 전용 도구로 먼저 출시해 모델이 잘 쓰는지 관찰한다. 쓰기·파괴적 작업은 승인 게이트를 붙여 점진적으로 연다. 처음부터 전권을 주지 않는다.

MCP 서버 설계는 결국 API 설계의 연장선이다. 다만 소비자가 사람이 아니라 모델이라는 점이 다르다. 좋은 이름, 명확한 계약, 엄격한 타입, 안전한 권한 — API를 잘 설계하던 감각이 그대로 쓰인다. 차이는 "설명을 사람이 아니라 모델이 읽는다"는 것, 그리고 "잘못 쓰면 모델이 알아서 헤맨다"는 것이다.