지식위키

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 객체 아래에 서버 이름을 키로 둔다.

  • typehttp(=streamable-http 별칭) / sse(deprecated) / stdio / ws. stdio는 생략 가능
  • command·args·env — stdio 전용. 실행 파일·인수·환경변수
  • url — http/sse/ws 필수. 원격 엔드포인트
  • headers — 정적 인증 헤더 (http/ws)
  • headersHelper — 연결 시 헤더를 동적 생성하는 셸 명령 (10초 타임아웃, stdout에 JSON)
  • oauthclientId/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.jsonmcpServers 래퍼를 쓴다.

명령줄로 추가하면 같은 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줄 요약

  1. 내장 도구는 Claude Code가 직접 구현해 항상 메뉴판에 있고, MCP 도구는 .mcp.json으로 외부 서비스를 콘센트처럼 꽂아 추가한다.
  2. 도구 정의는 세션 시작 시 모델에게 주입되지만, MCP 도구는 컨텍스트 절약을 위해 평소 “이름표만” 보여 주고(연기) 모델이 ToolSearch로 필요할 때 펼친다.
  3. 도구를 실제로 실행하기 직전 권한 규칙(허용/질문/거부)이 검사되고, 프로젝트 범위 .mcp.json은 첫 사용 시 승인을 요구한다.

스스로 답해 보기

  • 내장 도구와 MCP 도구의 가장 큰 차이는 무엇이고, 각각 어디서 정의되는가?
  • 서버를 많이 꽂아도 컨텍스트 압박이 작은 이유는 무엇인가? (힌트: 연기와 ToolSearch)
  • mcp__github__create_issue라는 도구를 명령에서 미리 허용하려면 어디에 무엇을 써야 하는가?

연결

CC_개요 · _분석축_루브릭


근거 파일

  • /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-tools frontmatter에 MCP 도구 풀네임을 미리 허용한다.