
MCP 도구는 필요 이상의 컨텍스트를 6.6배 더 소모합니다: 새로운 사양을 기준으로 측정한 결과
요약
MCP(Model Context Protocol) 사용 시 모델이 실제로 필요로 하는 정보보다 약 6.6배 더 많은 컨텍스트를 소모한다는 분석 결과입니다. 모든 도구의 전체 JSON Schema를 사전에 제공하는 프로토콜 구조로 인해 발생하는 토큰 낭비 문제를 수치로 증명했습니다.
핵심 포인트
- MCP는 도구 사용 여부와 상관없이 모든 도구의 전체 스키마를 컨텍스트에 주입함
- 실제 필요량 대비 약 6.6배의 컨텍스트 중복 발생
- 도구 72개 기준 약 33,709 토큰을 점유하여 컨텍스트 창의 17%를 소모함
- 도구당 약 468 토큰의 일정한 비용이 발생하여 규모에 따라 비용 예측 가능
에이전트(Agent)는 무엇인가를 수행하기 전에 세금을 지불합니다. 호스트(Host)가 MCP 서버에 연결되는 순간, tools/list는 사용자가 단 한 마디를 입력하기도 전, 모델이 무엇인가에 대해 추론하기도 전에 모든 도구의 전체 JSON Schema를 모델의 컨텍스트(Context)에 쏟아붓습니다. 이 스키마들 중 대부분은 이번 세션 동안 전혀 사용되지 않을 것입니다. 하지만 당신은 어쨌든 비용을 지불합니다. 매 세션마다 말이죠.
저는 정확히 어느 정도인지 알고 싶었습니다. 막연한 느낌이 아니라, 방어할 수 있는 수치를 원했습니다. 그래서 실제 로컬 MCP 서버를 기준으로 측정했습니다. stdio를 통한 실제 JSON-RPC, 실제 프로덕션 서버에서 배포되는 장황한 github 스타일로 작성된 도구들, 그리고 cl100k_base로 계산된 토큰(Token)을 사용했습니다. 테스트 프레임워크(Harness)는 공개되어 있으며, 의존성이 없고, 1분 이내에 재실행이 가능합니다.
결과는 다음과 같습니다: 모델이 실제로 필요로 하는 것보다 약 6.6배 더 많은 컨텍스트를 소모하며, 이는 도구 12개에서 72개 사이에서 안정적으로 유지됩니다. 도구가 72개일 경우 이는 33,709 토큰에 달하며, 이는 200k 컨텍스트 창의 약 17%가 대화가 시작되기도 전에 유휴 상태로 자리 잡고 있음을 의미합니다.

실제 수치는 어떠한가
| 도구 수 (tools) | 도구 정의 토큰 (tool-def tokens) | 최소 하한선 (minimal floor) | 중복성 (redundancy) | 200k 컨텍스트 대비 비율 (% of 200k ctx) |
|---|---|---|---|---|
| 12 | 5,589 | 815 | 6.9× | 2.8% |
| ... |
"최소 하한선(minimal floor)"은 각 도구의 이름을 명시하고, 한 줄의 목적을 제공하며, 매개변수를 name:type 형식으로 나열하는 가장 작은 직렬화(Serialization) 형태를 의미합니다. 즉, 모델이 도구를 선택하고 호출하는 데 실제로 필요한 모든 것입니다. 열 사이의 격차는 프로토콜이 강제하는 중복성(Redundancy)입니다. 작업이 해당 도구를 사용하든 안 하든, 모든 도구에 대해 전체 JSON Schema를 사전에 제공하기 때문입니다.
해당 표에서 두 가지 사실이 저를 놀라게 했습니다. 첫째, 비율이 규모에 따라 거의 변하지 않는다는 점입니다. 이는 대규모 카탈로그에서 발생하는 병리적 현상이 아니라, 이 형식 자체의 기본 비용입니다. 둘째, 도구당 비용이 약 468 토큰으로 지루할 정도로 일정하다는 점입니다. 이는 도구 개수만으로도 당신이 지불해야 할 세금을 추정할 수 있음을 의미합니다.

제가 입장을 표명하고자 하는 부분은 바로 이것입니다: 2026-07-28 릴리스 후보(release candidate) — 권한 부여 이후 가장 큰 MCP 개정판 — 는 이 문제를 다루지 않습니다. 이 버전은 상태 비저장 전송(stateless transport), OAuth 강화, JSON Schema 2020-12를 포함하며, Roots, Sampling, Logging을 지원 중단(deprecate)합니다. 토큰 세금(token tax) 문제는 포함되어 있지 않으며, 핵심 로드맵에도 없습니다. 이 문제를 제기했던 두 개의 커뮤니티 스레드(#2808 및 SEP-1576)는 명세(spec) 수준의 답변 없이 종료되었습니다. 저는 이것이 실수라고 생각하며, 형용사를 사용하여 논쟁하기보다는 재현 가능한 수치를 테이블 위에 올려놓고 논쟁하고 싶습니다.
해결책은 지루합니다. 그것이 핵심입니다.
해결책에 있어 새로운 것은 없으며, 그렇지 않은 척하지도 않겠습니다. 이는 점진적 공개(progressive disclosure) 방식입니다. Anthropic의 Tool Search 및 기타 서비스들이 이미 비슷한 규모로 보고하고 있는 패턴이죠: 카탈로그를 인덱싱하고, 가공되지 않은 스키마(raw schemas)를 쏟아내는 대신 tool_search(query) 및 tool_load(name) 메타 도구(meta-tools)를 노출하며, 작업이 도구를 필요로 할 때만 해당 도구의 전체 정의를 로드하는 방식입니다.
제가 추가할 수 있는 것은 아래의 보안 점검과 동일한 경계에서 생성된, 현재의 릴리스 후보(release candidate)와 비교한 측정값입니다:

작업당 비용이 33,709 토큰에서 750~883 토큰으로 급감하며, 이는 97% 이상의 감소를 의미합니다. 이때 항상 지불해야 하는 오버헤드는 일회성인 209 토큰의 인덱스입니다. 세 개의 실제 작업, 세 개의 실제 도구 로드, 동일한 하네스(harness), 동일한 토크나이저(tokenizer)를 사용했습니다.
두 번째 격차 또한 동일한 경계에 존재합니다
tools/list를 응시하고 있는 동안, 또 다른 문제가 저를 계속 응시했습니다. MCP 사양(spec)은 도구 설명(tool descriptions)을 "신뢰할 수 없는 것으로 간주해야 한다(should be considered untrusted)"라고 명시하지만, 정작 그에 따라 조치할 수 있는 메커니즘은 제공하지 않습니다. 설명은 서버에서 모델의 컨텍스트(context)로 있는 그대로 넘어오며, 모델은 이를 지시 사항(instruction)처럼 읽습니다.
이 문제의 가장 고약한 형태는 제가 **승인 뷰 충실도 격차 (approval-view fidelity gap)**라고 부르는 것입니다. 도구 설명은 인간의 승인 대화창에서는 깨끗하고 무해한 텍스트로 렌더링되지만, 유니코드의 보이지 않는 TAG 범위(U+E0000–U+E007F) 내에 숨겨진 지시 사항을 포함할 수 있으며, 모델은 이를 온전히 수신합니다. 인간은 눈에 보이는 것을 승인하고, 모델은 눈에 보이지 않는 것에 복종합니다.
여기에는 다섯 가지 핵심 은닉 기술이 있으며, 각각 명확한 이름이 필요합니다: TAG-블록 미러(TAG-block mirror), 제로 너비 바이너리(zero-width binary), bidi 트로이 목마 소스(bidi Trojan-Source) 트릭, 변형 선택자 밀수(variation-selector smuggling), 그리고 호모글리프 스푸핑(homoglyph spoof)입니다. 저의 하네스(harness)는 제어 가능한 로컬 서버를 대상으로 각 기술을 시연하며, 인간용 뷰(human-view)와 모델용 뷰(model-view)를 나란히 출력하고 경계에서의 차이를 표시합니다.
논점의 형태를 주목하십시오. 최적화 질문("왜 이 모든 것이 컨텍스트 안에 있는가?")과 보안 질문("왜 이 모든 것이 신뢰되는가?")은 동일한 지점, 즉 도구 메타데이터가 서버에서 모델의 컨텍스트로 넘어가는 순간에 대해 던져지는 동일한 질문입니다. tools/list에서의 하나의 중재자(mediator)가 두 질문 모두에 답할 수 있습니다. 모두가 원하는 토큰 절약을 위해 어차피 해당 경계를 중재하고 있다면, 무결성 검사(integrity checks)는 거의 비용이 들지 않습니다.
저는 "오탐(false positives) 제로"라고 주장했습니다. 그러고 나서 제가 거짓말쟁이임을 증명하려 했습니다.
이 부분은 제가 이 프로젝트에서 가장 자랑스럽지 않으면서도, 동시에 발생하기를 가장 잘했다고 생각하는 부분입니다.
초기에 저는 하나의 핵심적인 주장을 내놓았습니다: i18n-honest — 정당한 국제 텍스트에 대해 오탐(false positive)이 전혀 없음. 이는 매우 엄격하게 들렸습니다. 그러고 나서 저는 가장 먼저 했어야 할 일을 했습니다. 약 40개의 문자 체계와 메커니즘에 걸쳐 새로운 정당한 문자열 세트(battery)를 구축했습니다. 태국어와 크메르어의 제로 너비 단어 구분(zero-width word breaks), 페르시아어 ZWNJ(Zero Width Non-Joiner), 인디(Indic) 결합 문자(conjuncts), 이모지-ZWJ(Zero Width Joiner) 직업 표현, 키캡(keycap) 및 ©®™ 프레젠테이션 선택자(presentation selectors), CJK 이데오그래프 변형 시퀀스(ideographic variation sequences), RTL-plus-Latin 양방향(bidi) 텍스트, 과학적 표기법에서 라틴 문자와 결합된 그리스 문자 등이 포함되었습니다. 그리고 제가 만든 탐지기를 이 데이터에 실행해 보았습니다.
실패했습니다. 아주 처참하게 말이죠. 완벽하게 실제적인 텍스트에서 수십 개의 오탐이 발생했습니다. 제 주장은 제가 그것을 작성할 때 보고 있었던 몇 안 되는 예시들에 대해서만 참이었던 것입니다.
그래서 저는 다른 원칙을 중심으로 탐지기를 다시 구축했습니다: 공격인지 정당한 것인지를 **코드 포인트(codepoint)의 정체성이 아닌 문맥(context)**으로 결정하는 것입니다. 가시적인 기본 문자 뒤에 오는 변형 선택자(variation selector)는 타이포그래피입니다. 반면 보이지 않는 기본 문자 뒤에 고립되어 나열된 변형 선택자들은 바이트 채널(byte channel)입니다. 단어 구분으로서의 제로 너비 문자는 태국어가 작성되는 방식이지만, 밀집된 나열로서의 제로 너비 문자는 페이로드(payload)입니다. 그 후 동일한 루프를 반복했습니다: 깨뜨려 보고, 깨진 것을 고치고, 모든 것을 다시 실행하는 과정을 말이죠.
이 코퍼스(corpus)에 대해 Python과 TypeScript 구현체 모두에서 동일한 수준으로 검증된 결과는 다음과 같습니다:
[
35개의 문자열로 구성된 i18n 코퍼스와 139개의 적대적 테스트 세트(adversarial battery) 중 98개의 모든 정당한 문자열에 대해 오탐이 0건이었으며, 동시에 5개의 핵심 기술과 테스트 세트 내 41개의 의도적인 회피 변형 중 27개를 잡아냈습니다. 전 과정이 결정론적(deterministic)입니다. LLM, 네트워크 호출, 무작위성(randomness)이 전혀 없으므로 동일한 입력은 항상 동일한 판정을 내리며, 누구나 그 이유를 감사(audit)할 수 있습니다.
그리고 이 도구는 여전히 의도적으로 몇 가지 사항을 놓치고 있으며, README(읽기 파일)에 그 이유가 정확히 명시되어 있습니다: 완전히 비라틴 계열인 호모글리프(homoglyph, 유사 형태) 단어들(이를 포착하려면 전체 UTS #39 fold 테이블이 필요하며, 단순한 fold 방식은 실제 키릴 문자에서 오탐(false-positive)을 발생시킵니다), 아르메니아어 유사 형태를 포함하는 라틴 브랜드 단어들(아르메니아어는 라틴어 단어에 정당하게 교착(agglutinate)될 수 있음), 인간 검토자가 이미 식별할 수 있는 명확히 구분되는 유사 형태들(전각 문자, 소문자 대문자(small-caps), 수학적 알파뉴메릭(math alphanumerics)), 양방향(bidi) 임베딩 및 격리자(isolates)(RTL 텍스트에서 정당하게 사용됨 — 오직 고전적인 RLO/LRO 재정의만 플래그가 지정됨), 그리고 텍스트를 눈에 띄게 부풀리는 대가로 임계값(floor)을 피하기 위해 30% 미만의 밀도로 흩뿌려진 제로 너비(zero-width) 페이로드 등이 있습니다.
탐지기를 구축하려는 모든 이들에게 제가 제안하고 싶은 교훈은 다음과 같습니다: 예측 가능한, 문서화된 미탐(false negative)은 정직한 엔지니어링이지만, 누군가의 언어에 대해 잘못된 경보를 울리는 오탐(false positive)은 그렇지 않습니다. 저는 실제 페르시아어, 태국어, 힌디어 텍스트를 망가뜨릴 수 있는 허술한 규칙 대신, 잔차(residuals)가 명시된 오탐 없는(FP-free) 탐지기를 선택했습니다. 그것은 있으면 좋은 기능이 아니라 필수 요구 사항이었습니다.
제가 명시적으로 주장하지 않는 것들
이 분야는 이미 포화 상태이며 기존 기술(prior art)도 훌륭합니다. 러그풀(rug-pulls)을 위한 바이트 고정(Byte-pinning)은 Invariant Labs의 MCP-Scan에 포함되어 있습니다. 결정론적 숨겨진 유니코드(Deterministic hidden-Unicode) 탐지는 Microsoft의 에이전트 거버넌스(agent-governance) 도구와 Cisco의 YARA 규칙에 포함되어 있습니다. 토큰 비용 산정(Token-costing)은 mcp-checkup에 존재합니다. 여기서 다루는 기본 요소(primitives) 중 새로운 것은 없습니다.
본 도구의 기여는 이들의 결합입니다: 정적 tools/list 카탈로그의 토큰 가격 책정(token-pricing)과 컨텍스트 인식 은닉 감사(context-aware concealment audit)를 의존성 없는 단일 오프라인 패스(offline, dependency-free pass)로 수행하며, 이를 현재의 출시 후보(release candidate) 버전과 비교 측정한다는 점입니다. 저는 이 경계에서 두 가지를 모두 수행하는 다른 도구를 찾지 못했습니다. 성적표(report card)에 나타나는 주입(injection) 및 유출(exfiltration) 신호는 검토를 위한 의도적인 노이즈 힌트일 뿐, 보안 경계(security boundary)가 아닙니다. 바이트 고정(byte-pinning)은 최초 사용 시 신뢰(trust-on-first-use) 방식이므로, 최초 접촉 시의 포이즈닝(poisoning)이 아니라 승인 후의 변조(mutation)를 포착합니다. 진정한 방어는 심층 방어(defense-in-depth)로 유지되어야 합니다. 이 도구는 보고하고 등급을 매길 뿐, 방어(guard)하지는 않습니다.
귀하의 서버에서 직접 실행해 보십시오. 제가 틀렸다면 말씀해 주십시오.
위의 모든 과정은 Python 3.10 외의 의존성 없이, 깨끗한 체크아웃(clean checkout) 상태에서 1분 이내에 다시 실행됩니다:
git clone https://github.com/singhpratech/mcp-turnstile && cd mcp-turnstile && python3 -m bench.token_tax
그리고 CLI는 로컬이든 원격이든 귀하의 서버를 평가할 것입니다: mcpturn scan --stdio -- <your server command>를 실행하면 성적표가 출력되며 CI 종료 코드(exit code)를 반환합니다.
만약 귀하의 비율이 6.6배와 다르게 나온다면, 저는 그 사실을 알고 싶습니다. 만약 탐지기가 귀하의 언어에서 오탐(false-positive)을 발생시킨다면, 저는 정말로 알고 싶습니다. 그것이 바로 제가 이미 한 번 틀렸던 주장이며, 이 배터리(battery)가 존재하는 이유 전체이기 때문입니다. 리포지토리(Repo): github.com/singhpratech/mcp-turnstile · 문서(docs): singhpratech.github.io/mcp-turnstile · 출처를 포함한 전체 벤치마크(benchmark) 보고서는 report/BENCHMARK.md에서 확인할 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기