Claude Code · 도구 시스템과 MCP (도구 정의·노출)
Claude Code · 도구 시스템과 MCP (도구 정의·노출)
한 줄 요약
Claude Code의 도구 시스템은 “글만 쓸 수 있는 모델”에게 파일 읽기·명령 실행 같은 손발을 쥐여 주는 메뉴판이고, MCP는 그 메뉴판에 외부 서비스(Notion·GitHub·Slack 등)를 콘센트처럼 꽂는 표준 규격이다. 왜 배우나: 에이전트가 “무엇을 할 수 있는지”는 결국 이 도구 목록이 정하기 때문에, 도구를 켜고 끄고 외부 기능을 붙이는 법을 알아야 원하는 자동화를 안전하게 구성할 수 있다.
그림
flowchart TD
A[세션 시작] --> B[내장 도구 스키마 주입]
A --> C[.mcp.json 파싱 후 서버 연결]
C --> D{"툴 서치 켜짐?"}
D -- 켜짐 기본값 --> E["도구 이름과 서버 지침만 로드, 본체는 연기"]
D -- 꺼짐 또는 alwaysLoad --> F[전체 도구 스키마 미리 로드]
E --> G[모델이 ToolSearch로 필요한 도구 검색]
G --> H[도구 호출 블록 출력]
F --> H
B --> H
H --> I["권한 규칙 허용/질문/거부 검사"]
I -- 허용 --> J[Claude Code가 실제 실행]
J --> K[실행 결과를 다음 턴 컨텍스트로 반환]
쉽게 풀기
1단계 — 모델은 원래 손이 없다. LLM 모델은 텍스트만 만들어 낸다. 스스로 파일을 열거나 터미널 명령을 돌릴 수 없다. 식당에 비유하면, 모델은 “메뉴를 보고 주문만 외치는 손님”이다.
2단계 — Claude Code가 메뉴판을 건넨다(내장 도구).
Claude Code는 세션을 시작할 때 모델에게 “너는 Read로 파일을 읽고, Edit로 고치고, Bash로 명령을 돌릴 수 있어”라는 메뉴판을 함께 넘긴다. 이게 내장 도구다. 모델이 “이 파일을 Read 할게”라고 주문하면, 주방장 역할인 Claude Code가 실제로 파일을 열어 결과를 접시에 담아 돌려준다.
3단계 — 외부 서비스는 콘센트로 꽂는다(MCP).
기본 메뉴판만으로는 Notion 문서를 검색하거나 GitHub 이슈를 만들 수 없다. 여기서 MCP(Model Context Protocol) 가 등장한다. MCP는 “외부 서비스를 도구로 변환하는 표준 콘센트 규격”이다. .mcp.json이라는 설정 파일에 “Notion 서버를 꽂아줘”라고 적으면, Notion의 기능들이 mcp__notion__notion-search 같은 새 메뉴 항목으로 메뉴판에 추가된다.
4단계 — 메뉴가 너무 많으면 접어 둔다(툴 서치).
서버를 여러 개 꽂으면 메뉴가 수백 개로 불어난다. 메뉴판이 두꺼우면 손님(모델)이 메뉴를 읽느라 머리(컨텍스트)를 다 써 버린다. 그래서 Claude Code는 툴 서치라는 장치로 외부 도구를 평소엔 “이름표만” 보여 주고 본문은 접어 둔다(이를 “연기 deferred”라 한다). 모델이 필요할 때 ToolSearch로 “결제 관련 도구 줘”라고 찾으면 그때 펼친다.
5단계 — 주문마다 문지기가 검사한다(권한).
도구를 실제로 실행하기 직전, 권한 규칙이라는 문지기가 “이건 허용”, “이건 물어보고”, “이건 금지”를 판정한다. 특히 프로젝트에 들어 있는 .mcp.json은 처음 쓸 때 사용자에게 승인을 받는다(낯선 사람이 가져온 콘센트를 함부로 꽂지 않는 것과 같다).
핵심 정리
| 구분 | 정체 | 어떻게 들어오나 |
|---|---|---|
| 내장 도구 | Claude Code가 직접 구현, 항상 존재 | 세션 시작 시 자동 주입 |
| MCP 도구 | 외부 서비스 기능을 콘센트로 연결 | .mcp.json 설정으로 추가 |
[!note] 자주 쓰는 내장 도구
Read(권한 불필요) — 파일을 줄번호와 함께 반환, 이미지·PDF·노트북 지원Edit(권한 필요) — 정확한 문자열 교체, 수정 전 반드시 Read 선행Write(권한 필요) — 파일 생성·덮어쓰기, 기존 파일은 Read 선행Bash(권한 필요) — 셸 명령 실행, 기본 2분·최대 10분 타임아웃Grep/Glob(권한 불필요) — 내용 검색 / 파일명 패턴 검색WebFetch/WebSearch(권한 필요) — URL 가져오기 / 검색Agent(권한 불필요) — 별도 컨텍스트의 서브에이전트에 작업 위임Skill(권한 필요) — 메인 대화에서 skill 실행
[!note] 권한 규칙 형식
도구이름(specifier)specifier는 도구마다 다르다.
- 명령 패턴:
Bash(npm run *)- 경로 패턴:
Read(~/secrets/**)→ Read·Grep·Glob·LSP에 적용- 경로 패턴:
Edit(/src/**)→ Edit·Write·NotebookEdit에 적용 (Edit 허용은 같은 경로 Read도 자동 부여)- 도메인:
WebFetch(domain:example.com)- specifier 없음:
WebSearch(전체 허용/거부)- 도구를 완전히 끄려면 permission
deny배열에 이름을 넣는다.
[!note]
.mcp.json서버 구성 필드mcpServers객체 아래에 서버 이름을 키로 둔다.
type—http(=streamable-http별칭) /sse(deprecated) /stdio/ws. stdio는 생략 가능command·args·env— stdio 전용. 실행 파일·인수·환경변수url— http/sse/ws 필수. 원격 엔드포인트headers— 정적 인증 헤더 (http/ws)headersHelper— 연결 시 헤더를 동적 생성하는 셸 명령 (10초 타임아웃, stdout에 JSON)oauth—clientId/callbackPort/scopes/authServerMetadataUrl등timeout— 도구 호출당 하드 월클록 제한(ms, 예600000)alwaysLoad— 툴 서치 연기에서 제외, 세션 시작 시 항상 로드 (v2.1.121+)- 환경변수 확장
${VAR}·${VAR:-default}를command/args/env/url/headers에서 쓸 수 있다. 필수 변수가 없고 기본값도 없으면 파싱 실패.
[!note] MCP 도구 이름 짓는 법
- 사용자 구성 서버:
mcp__<server>__<tool>(예mcp__github__create_issue)- 플러그인 제공 서버:
mcp__plugin_<plugin-name>_<server-name>__<tool-name>- MCP 프롬프트(명령):
/mcp__<servername>__<promptname>- MCP 리소스 참조:
@<server>:<protocol>://<resource/path>(예@github:issue://123)- 이 이름은 permission rule·subagent
tools목록·hook matcher에서 쓰는 정확한 문자열이다.
실제 예시
플러그인이 번들한 stdio 서버(oh-my-claudecode 실제 파일):
// /home/seunghyeong/.claude/plugins/cache/omc/oh-my-claudecode/4.14.6/.mcp.json
{
"mcpServers": {
"t": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/bridge/mcp-server.cjs"]
}
}
}
원격 HTTP 서버 + Bearer 헤더(공식 GitHub 플러그인 실제 파일):
// /home/seunghyeong/.claude/plugins/marketplaces/claude-plugins-official/external_plugins/github/.mcp.json
{
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {
"Authorization": "Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}"
}
}
}
[!note] 래퍼 유무 차이 위 GitHub 예시는
mcpServers래퍼 없이 서버 이름이 최상위 키다. 플러그인 전용.mcp.json은 두 형태(래퍼 유무) 모두 통용된다. 반면 사용자가 직접 작성하는 프로젝트 범위.mcp.json은mcpServers래퍼를 쓴다.
명령줄로 추가하면 같은 JSON이 생성된다(mcp.md 출처):
# 원격 HTTP (권장)
claude mcp add --transport http notion https://mcp.notion.com/mcp
# 로컬 stdio (옵션은 서버 이름 앞, -- 뒤는 서버 명령)
claude mcp add --transport stdio --env AIRTABLE_API_KEY=YOUR_KEY airtable \
-- npx -y airtable-mcp-server
직접 만들 때 — 프로젝트 범위 .mcp.json(팀 공유, 버전관리 체크인):
// <project-root>/.mcp.json
{
"mcpServers": {
"weather-api": {
"type": "http",
"url": "${API_BASE_URL:-https://api.weather.com}/mcp",
"headers": { "Authorization": "Bearer ${WEATHER_API_KEY}" },
"timeout": 600000,
"alwaysLoad": false
},
"local-db": {
"command": "npx",
"args": ["-y", "@bytebase/dbhub", "--dsn", "${DB_DSN}"],
"env": { "LOG_LEVEL": "info" }
}
}
}
명령/skill에서 MCP 도구를 미리 허용:
---
allowed-tools: [
"mcp__weather-api__get_forecast",
"mcp__local-db__query"
]
---
구성 체크리스트:
-
type이 stdio/http/sse/ws 중 하나(stdio는 생략 가능), 유형별 필수 필드(command또는url) 완비 - 비밀값 하드코딩 금지 —
${VAR}/headers/env로 주입, README에 필요 변수 문서화 - 원격은 HTTPS/WSS 사용, 인증은 OAuth(
/mcp) 또는 헤더 토큰 - 플러그인 번들이면 경로에
${CLAUDE_PLUGIN_ROOT}사용 -
claude mcp list//mcp로 서버 연결·도구 개수 확인,claude --debug로 연결 로그 확인 - 프로젝트 범위 서버는 첫 사용 시 승인 (
claude mcp reset-project-choices로 초기화) -
allowed-tools는 와일드카드(mcp__server__*) 대신 개별 도구를 나열 (보안) - 매 턴 필요한 소수만
alwaysLoad:true, 나머지는 연기 유지로 컨텍스트 절약 - 큰 출력 도구는
_meta["anthropic/maxResultSizeChars"]주석 또는MAX_MCP_OUTPUT_TOKENS상향
요약 & 셀프체크
3줄 요약
- 내장 도구는 Claude Code가 직접 구현해 항상 메뉴판에 있고, MCP 도구는
.mcp.json으로 외부 서비스를 콘센트처럼 꽂아 추가한다. - 도구 정의는 세션 시작 시 모델에게 주입되지만, MCP 도구는 컨텍스트 절약을 위해 평소 “이름표만” 보여 주고(연기) 모델이
ToolSearch로 필요할 때 펼친다. - 도구를 실제로 실행하기 직전 권한 규칙(허용/질문/거부)이 검사되고, 프로젝트 범위
.mcp.json은 첫 사용 시 승인을 요구한다.
스스로 답해 보기
- 내장 도구와 MCP 도구의 가장 큰 차이는 무엇이고, 각각 어디서 정의되는가?
- 서버를 많이 꽂아도 컨텍스트 압박이 작은 이유는 무엇인가? (힌트: 연기와
ToolSearch) mcp__github__create_issue라는 도구를 명령에서 미리 허용하려면 어디에 무엇을 써야 하는가?
연결
근거 파일
/mnt/d/6study/10_프레임워크분석/_원문아카이브/claude-code/tools-reference.md(내장 도구 카탈로그·권한 규칙 형식·도구별 동작)/mnt/d/6study/10_프레임워크분석/_원문아카이브/claude-code/mcp.md(전송 유형·범위·OAuth·Tool Search·네이밍·출력 제한, 전체 1085줄)/home/seunghyeong/harness-work/claude-code/plugins/plugin-dev/skills/mcp-integration/SKILL.md(플러그인 MCP 통합·mcp__plugin_*네이밍·allowed-tools·서버 유형 표)/home/seunghyeong/.claude/plugins/cache/omc/oh-my-claudecode/4.14.6/.mcp.json(실제 stdio +${CLAUDE_PLUGIN_ROOT}예시)/home/seunghyeong/.claude/plugins/marketplaces/claude-plugins-official/external_plugins/github/.mcp.json(실제 http + Bearer 헤더 예시)/home/seunghyeong/.claude/plugins/marketplaces/claude-plugins-official/external_plugins/playwright/.mcp.json(실제 최소 stdio 예시)
[!tip] 도구가 모델 컨텍스트를 소비하는 메커니즘 (보존) 도구 정의(
name/description/input_schema)는 세션 시작 시 모델 API 요청의tools배열로 주입된다. 모델은 이 메뉴판을 보고 tool_use 블록으로 호출을 출력하고, Claude Code가 실제 실행 후 tool_result를 다음 턴에 돌려준다.
- 툴 서치(기본 활성): MCP 도구는 미리 로드되지 않고 연기(deferred)된다. 세션 시작 시 도구 이름과 서버 지침만 로드되고, 모델은
ToolSearch로 필요한 도구를 검색해 끌어온다.tool_reference블록 지원 모델(Sonnet 4+/Opus 4+) 필요, Haiku 미지원, Vertex AI에서 기본 비활성.ENABLE_TOOL_SEARCH값:true(전체 연기) /auto(컨텍스트 10% 이내면 preload) /auto:N/false(전체 preload). 매 턴 필요한 소수는 서버alwaysLoad:true또는 도구_meta["anthropic/alwaysLoad"]:true로 연기 제외.- 설명 자르기: Claude Code는 도구 설명·서버 지침을 각각 2KB에서 자르므로 핵심을 앞에 둬야 한다.
- 출력 제한: MCP 출력은 10,000토큰 초과 시 경고, 기본 상한 25,000토큰(
MAX_MCP_OUTPUT_TOKENS), 도구별_meta["anthropic/maxResultSizeChars"](최대 500,000자)로 상향 가능. 초과분은 디스크에 저장되고 대화에는 파일 참조로 대체된다.- 권한 게이팅: 호출 시점에 permission rule(allow/deny/ask)이 검사된다. 프로젝트 범위
.mcp.json서버는 사용 전 승인을 요구하며(claude mcp list에⏸ 승인 대기 중), 명령/skill의allowed-toolsfrontmatter에 MCP 도구 풀네임을 미리 허용한다.