당신의 MCP 서버가 파일 인자를 받을 수 없는 이유와 해결 방법
요약
MCP(Model Context Protocol) 서버 설계 시 대용량 파일을 도구 인자로 직접 전달할 때 발생하는 토큰 제한 문제를 분석합니다. 모델의 출력 토큰 한계로 인한 실패 원인을 설명하고, 파일 경로를 전달하는 참조 방식의 해결책을 제시합니다.
핵심 포인트
- 도구 호출 인자는 모델의 출력 토큰 제한을 받음
- 대용량 텍스트 인자는 파싱 실패나 내용 축약 유발
- 비싼 출력 토큰 비용과 데이터 손상 위험 존재
- 파일 데이터 대신 파일 경로(reference)를 전달하여 해결
저는 HTML 파일을 게시하는 MCP 서버를 구축했는데, 어디에서도 문서화된 적 없는 벽에 부딪혔습니다. 바로 MCP 도구 (tool) 인자로 큰 파일을 전달할 수 없다는 점입니다. 단순히 "느리다"거나 "번거롭다"는 수준이 아닙니다. 모델이 물리적으로 이를 수행할 수 없습니다.
실패 사례와 그 원인, 그리고 이를 해결하는 단 한 줄의 설계 변경 방법을 소개합니다.
설정 (The setup)
제 에이전트들(주로 Claude Code)은 Chart.js가 포함된 대시보드, 데이터가 많은 보고서, PRD 등 많은 양의 대화형 HTML을 생성합니다. 저는 에이전트가 도구 호출(tool call) 한 번으로 해당 파일들을 웹에 게시하기를 원했고, 처음에는 당연한 방식으로 접근했습니다:
server.tool(
"publish_html",
{ html: z.string(), title: z.string() },
...
에이전트가 HTML을 생성하여 html 인자로 전달하면, 서버가 이를 업로드합니다. 5KB 정도의 "hello world" 페이지에서는 아주 멋지게 작동했습니다.
하지만 데이터가 인라인(inlined)된 1.4MB 규모의 실제 결과물에 적용해 보았더니, 시스템이 무너져 버렸습니다.
왜 절대 작동할 수 없는가
모델이 도구를 호출할 때, 인자는 파일 핸들(file handle)이나 포인터(pointer)가 아닙니다. 그것은 모델이 응답 내에서 토큰(token) 단위로 생성하는 텍스트입니다. 도구 호출의 인자는 모델 출력의 일부이므로, 모델의 최대 출력 토큰(maximum output tokens) 제한을 받게 됩니다.
계산을 해봅시다: 1MB의 HTML은 대략 250k~350k 토큰입니다. 일반적인 최대 출력량은 이보다 훨씬 적습니다. 모델은 말 그대로 인자를 "말하는" 것을 끝마칠 수 없습니다. 실제로 다음과 같은 현상이 발생합니다:
- 파싱에 실패하는 잘린(truncated) 도구 호출,
- 모델이 "친절하게도" HTML을 요약하거나 축약하여 내용을 손상시키는 경우,
- 또는 거대한 데이터 덩어리(blob)를 내보내는 것을 피하려고 시도하며 발생하는 거절에 가까운 지연.
설령 파일이 제한 범위 내에 들어온다 하더라도, 이미 디스크에 존재하는 파일을 바이트 단위로 모델이 다시 타이핑하게 함으로써 비싼 출력 토큰(output-token) 비용을 지불해야 하며, 그 과정에서 모델이 무언가를 "수정"해버릴 확률도 존재합니다.
이것은 MCP의 버그가 아닙니다. 도구 호출 (tool calling)의 본질적인 특성입니다: 인자 (arguments)는 모델의 출력 (output)입니다. 대량의 콘텐츠를 인자로 받도록 설계된 모든 MCP 도구는 누군가 실제로 업무에 사용하기 시작하는 순간 한계에 부딪히게 됩니다.
해결 방법: 바이트 (bytes)가 아닌 참조 (reference)를 전달하세요
서버는 stdio를 통해 로컬에서 실행됩니다. 서버는 에이전트(agent)가 작업 중인 것과 동일한 파일 시스템을 가지고 있습니다. 따라서 도구는 **경로 (path)**를 받습니다:
server.tool(
"publish_file",
{
...
이제 모델의 도구 호출은 파일 크기에 관계없이 약 50 토큰 (tokens) 내외가 됩니다:
{ "path": "/Users/me/reports/q2-dashboard.html", "title": "Q2 Dashboard" }
에이전트는 바이트를 전혀 운반하지 않습니다. 에이전트는 자신의 일반적인 파일 도구(스트리밍 방식을 사용하며 이러한 제약이 동일하게 적용되지 않는 도구)를 사용하여 파일을 작성한 다음, MCP 서버에 _참조 (reference)_를 전달합니다. 그러면 MCP 서버가 디스크에서 파일을 읽어 직접 멀티파트 업로드 (multipart upload)를 수행합니다. 1.4 MB이든 14 MB이든, 모델이 수행하는 작업의 크기는 동일합니다.
이 한 가지 설계 결정이 장난감 파일로 작동하는 데모와 실제 결과물(artifacts)에 유용한 도구 사이의 차이를 만듭니다.
일반적인 규칙
MCP 서버를 구축하고 있다면, 모든 도구 인자를 검토하고 다음과 같이 질문하십시오: 이것이 커질 수 있는가? 만약 그렇다면, 대신 참조를 받으십시오:
| ...를 받는 대신 | ...를 받으세요 |
|---|---|
| 파일 내용 (file contents) | 파일 경로 (a file path) |
| ... | ... |
_출력 (outputs)_에 대한 결론도 동일합니다: 거대한 페이로드 (payload)를 반환하는 도구는 모델의 컨텍스트 윈도우 (context window)를 가득 채웁니다. 참조(URL, 경로, 요약 + 핸들)를 반환하고, 모델이 필요할 경우에만 부분적으로 가져오도록(fetch slices) 하십시오.
로컬 stdio 서버는 에이전트와 파일 시스템을 공유하기 때문에 이 패턴에 완벽하게 부합합니다. 원격 MCP 서버의 경우, URL이나 사전 서명된 업로드 (pre-signed uploads)를 사용하여 동일한 개념을 적용할 수 있습니다. 즉, 인자에 바이트를 직접 넣는 함정만 피하면 됩니다.
시도해보기 / 소스
서버는 npm에 있는 stelaspace-mcp (MIT 라이선스)입니다. 이 서버는 HTML 파일을 StelaSpace에 게시하며, 각 결과물(artifact)에 영구적이고 샌드박스화된 접근 제어 링크를 제공합니다 (제가 직접 만들었으며, 무료 티어가 존재합니다). Claude Code를 사용한 한 줄 설정 방법은 다음과 같습니다:
claude mcp add stelaspace --scope user \
--env STELASPACE_API_KEY=ss_sk_... \
-- npx -y stelaspace-mcp
이렇게 게시된 라이브 대시보드 예시를 확인해 보세요 —
어떤 모델도 도구 인자 (tool argument)로 전달할 수 없는 1 MB 이상의 인터랙티브한 Chart.js HTML 파일입니다.
MCP 서버를 구축하면서 다른 문제에 부딪혔다면, 진심으로 그 사례들을 듣고 싶습니다 — 저는 이러한 주의 사항 (gotchas)들을 수집하고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기