Claude Code MCP 를 REST 로 떼어내면 토큰이 절약될까 — blog MCP 27 tool 회고

정기창·

모노레포에 @my-blog/coolify-deployer 도구 패키지를 새로 만들어 Coolify 배포를 REST API 로 직접 호출하도록 떼어낸 PR 을 머지한 직후였습니다. 머지 후 며칠 동안 후속 PR 들이 모두 자동 배포로 잘 굴러갔고, Neon 에 쌓인 이력을 들여다보다 자연스럽게 다음 질문이 떠올랐습니다. blog MCP 도 같은 방식으로 REST 로 떼어내면 토큰을 더 절약할 수 있지 않을까.

결론부터 적자면, 답은 도구 단위로 분할하라 였습니다. coolify 가 잘 갔다고 blog MCP 27개를 전부 REST 로 옮길 필요는 없고, 그렇다고 전부 MCP 로 두는 것도 ROI 가 떨어지는 선택입니다. 그 사이 어디에 선을 그어야 하는지, 며칠에 걸쳐 정리한 회고를 남깁니다.

coolify 자동 배포가 잘 굴러간 다음 든 의문

PR #252 로 @my-blog/coolify-deployer 패키지를 신설하면서, 기존에 별도 Claude 인스턴스(cc-coolify)나 @masonator/coolify-mcp 가 처리하던 Coolify 배포 흐름을 REST API 직접 호출 + Neon coolify_deployments 테이블 이력 INSERT 로 갈아엎었습니다. 그 후 후속 PR 들이 머지될 때마다 자동 배포가 따라붙었고, 며칠치 이력이 깔끔하게 적재되었습니다.

id PR app status duration(s)
12 #256 admin-blog finished 121
11 #255 admin-blog finished 151
10 #254 admin-blog finished 121
9 #254 backend-worker finished 423
8 #254 nestjs-backend-blog finished 332

이 표를 들여다보다 보니, MCP 를 거치지 않고도 배포가 더 빠르고 안정적으로 굴러간다는 사실이 눈에 들어왔습니다. 그러자 자연스럽게 따라온 생각이 blog MCP 도 같이 떼어내면 토큰을 더 절약할 수 있지 않을까 였습니다. 단순히 "MCP 는 비싸니까 떼자" 가 아니라, coolify 에서 검증된 패턴을 다른 도구에도 일관되게 적용할 수 있는지 확인해 보고 싶었습니다.

blog MCP 의 실체부터 확인

자르려는 대상이 정확히 무엇인지부터 살펴보는 게 순서였습니다. 현재 blog MCP 는 다음과 같은 형태로 상주하고 있습니다.

  • 위치: packages/personal/mcp/
  • 상주 형태: LaunchAgent (PID 717, RSS 33MB)
  • 엔드포인트: http://localhost:3004/mcp
  • transport: HTTP (stdio 아님)
  • 제공 tool: 27개

tool 면면을 훑어보면 list_posts, get_post, search_posts 같은 단순 조회부터 create_draft, update_draft, propose_edit 같은 창작 흐름, generate_embedding, analyze_seo, generate_blog_image 같은 LLM 호출 기반 도구까지 한 보따리에 묶여 있습니다. 27개를 한 덩어리로 보지 말고 성격별로 나눠서 보는 시야가 필요하다는 생각이 들었습니다.

메모리 두 축을 분리해서 보기

blog MCP 의 비용을 "메모리" 라는 한 단어로 뭉뚱그리다 보면 자꾸 잘못된 답에 도달하게 됩니다. 두 축을 완전히 분리해서 봐야 합니다.

축 실체 현재 상태
macOS RAM LaunchAgent 프로세스 1개의 메모리 사용량 33MB 고정. HTTP transport 라 세션 N개여도 공유
Claude Code 세션 컨텍스트 토큰 27개 tool schema 가 매 turn 시스템 프롬프트에 박힘 대략 6~13k tok/turn. 세션별 독립 → 3 세션 동시면 3배

RAM 쪽은 이미 HTTP transport 가 해결한 문제입니다. stdio 였다면 세션마다 별도 프로세스를 spawn 해서 N배가 되었겠지만, HTTP 로 떠있는 단일 프로세스가 모든 세션 요청을 공유하기 때문에 33MB 가 늘어나지 않습니다. 진짜 비용은 컨텍스트 토큰 축에 있다는 것이 핵심이었습니다.

청구 비용보다 컨텍스트 윈도우가 진짜 비용

토큰 비용을 줄이는 가장 흔한 처방은 Anthropic 의 프롬프트 캐시입니다. 5분 TTL 안에 같은 시스템 프롬프트가 다시 들어오면 cached input 가격(약 1/10)으로 청구되니, 27개 schema 가 매번 박혀도 청구 영향은 미미해 보입니다.

다만 곰곰이 생각해보니 캐시가 막아주지 못하는 게 한 가지 있었습니다. 바로 컨텍스트 윈도우 자체의 소진입니다. 200k 윈도우는 캐시 hit 여부와 무관하게 매 turn 일정 비율로 소진됩니다. 27 tool schema 가 6~13k tok 이라면 한 turn 당 윈도우의 3~6% 가 schema 만으로 먹히는 셈입니다.

100 turn 짜리 긴 세션이라면 누적 600k~1.3M tok 가 schema 만으로 전송됩니다. 청구로는 캐시 hit 덕에 거의 안 보이지만, 컨텍스트 윈도우는 정직하게 깎입니다. 결국 긴 세션의 후반부 압축이 빨리 와서 작업 흐름이 끊기는 형태로 비용이 청구된다는 생각이 들었습니다.

켜진 순간부터 끝까지 박힙니다

MCP 의 가성비를 더 떨어뜨리는 두 번째 요소는 attach 의 입자 단위가 세션이라는 점입니다. 한 번 켜진 세션에서는 blog 도구를 단 한 번도 호출하지 않더라도 매 turn 27개 schema 가 시스템 프롬프트에 박혀 나갑니다.

사용자가 가진 제어 레버는 .mcp.json 에서 blog 블록을 통째로 제거하는 것 하나뿐입니다. "이번 세션은 글 안 쓸 거니까 잠깐 끄자" 같은 동적 제어는 현재 구조에서는 어렵습니다. 즉, blog MCP 를 attach 해 둔 모든 세션이 글쓰기 작업이 아니더라도 schema 비용을 같이 지불하고 있다는 뜻이었습니다.

REST 로 떼어내는 게 항상 이득은 아닙니다

여기까지 정리하고 나니 "그러면 다 REST 로 떼어내자" 가 자연스럽게 다음 결론처럼 보였습니다. 하지만 27개 tool 을 성격별로 다시 들여다보니, REST 전환의 ROI 가 도구마다 크게 갈렸습니다.

결정적 도구 — REST 가 명백히 이김

예시로 get_post, list_posts, generate_all_embeddings, update_related_posts_bidirectional 같은 도구들이 여기에 속합니다. 공통점은 다음과 같았습니다.

  • 매개변수가 1~2개로 단순합니다
  • 호출 1회로 끝나고, 출력은 status 또는 짧은 JSON 입니다
  • CLI argv 한 줄로 충분히 표현됩니다

이 카테고리는 coolify-deployer 패턴이 거의 그대로 들어맞습니다. @my-blog/blog-batch 같은 도구 패키지를 만들어 Bash 한 줄로 호출하면, schema 토큰을 통째로 절약하면서도 동작은 동일합니다.

pnpm --filter @my-blog/blog-batch run generate-all-embeddings
pnpm --filter @my-blog/blog-batch run list-posts --limit 20

비결정적 창작 도구 — MCP 가 ROI 좋음

반면 create_draft, update_draft, propose_edit, get_writing_guidelines, generate_blog_image 는 다른 결의 도구였습니다. 매개변수가 5000자 markdown 본문을 통째로 받고, 다단계 연쇄에서 매 단계마다 LLM 이 판단을 합니다.

같은 작업을 두 방식으로 나란히 그려보면 차이가 분명해집니다.

[MCP 방식 — 시스템 프롬프트에 schema 있음]
turn 1: LLM → mcp__blog__get_writing_guidelines()
turn 2: LLM → mcp__blog__create_draft({ title, content: 5000자, tags })
turn 3: LLM → mcp__blog__generate_seo_metadata({ draftId, content })
turn 4: LLM → mcp__blog__update_draft({ draftId, metaTitle, ... })

이걸 REST/CLI 로 갈아엎으면 토큰이 다른 곳에서 새는 지점이 세 군데 생깁니다.

  1. schema 정보를 어딘가 박아야 함: endpoint 가이드를 시스템 프롬프트나 CLAUDE.md 에 박으면 결국 schema 와 비슷한 토큰을 지불하게 됩니다. 안 박으면 LLM 이 환각으로 잘못된 매개변수를 만듭니다.
  2. 매개변수가 길고 구조화되어 있음: content 가 5000자 markdown, tags 가 배열, seo 가 중첩 객체라면, CLI argv 로 표현하기 위해 stdin / here-doc 우회 + shell escaping 토큰을 추가로 지불합니다.
  3. 다단계 연쇄에서 매 turn lookup: 한 작업이 4~5 turn 으로 이어지면 매 turn 마다 endpoint 가이드를 다시 읽어와야 하고, 캐시 hit 효과는 약해집니다.

결국 이 카테고리는 MCP tool-use 의 표현력이 REST 보다 명백히 우위였습니다. 비결정적 창작 연쇄에서 MCP 가 ROI 가 좋다는 게 며칠 들여다보고 나서 도달한 결론입니다.

도구 단위 분할이 답

27개를 한 덩어리로 보지 않고 성격별로 나누면, 다음과 같은 매트릭스가 자연스럽게 나옵니다.

유형 예시 처리 방식
결정적 배치 generate_all_embeddings, save_related_posts 도구 패키지로 분리
결정적 단발 get_post, list_posts, search_posts 도구 패키지 (curl 한 줄)
비결정적 창작 create_draft, update_draft, propose_edit MCP 유지

분할 후 효과는 세션 성격별로 다시 계산됩니다.

  • 글쓰기 세션: MCP 5~7개만 attach → schema 토큰이 현재의 약 1/4 수준으로
  • 일반 개발 세션: blog MCP 자체를 attach 하지 않음 → schema 토큰 0
  • 결정적 배치 작업: Bash 1회 호출 → 토큰 거의 발생하지 않음

다만 REST 전환에는 숨은 비용도 있었습니다. 지금 MCP 가 처리해 주는 OAuth 60일 자동 갱신을 잃게 됩니다. 도구 패키지 안에 토큰 갱신 로직을 박거나, coolify-deployer 가 COOLIFY_ACCESS_TOKEN 을 .env 에 두는 것처럼 정적 토큰 방식을 쓰게 됩니다. 이 부분은 보안과 운영 편의성 사이에서 별도로 한 번 더 결정해야 할 지점입니다.

정리

며칠 회고해 보고 정리한 결론은 단순합니다.

  • MCP 의 가성비는 작업이 결정적인가, 창작 연쇄인가 로 갈립니다
  • 매 turn 의 schema 토큰은 청구가 아니라 컨텍스트 윈도우 를 소진하는 점이 함정입니다
  • coolify 가 잘 갔다고 blog 전체를 같은 방식으로 갈 필요는 없습니다 — 도구 단위 분할이 정답이라는 생각이 들었습니다

돌이켜 생각해보면 "MCP 좋다 / 나쁘다" 라는 이분법으로 접근했다면 어느 쪽으로도 잘못된 답에 도달했을 것 같습니다. 도구의 성격을 한 단계 더 들여다보고, 각 도구가 결정적 작업에 쓰이는지 창작 연쇄에 쓰이는지 따져본 다음에야 비로소 분할선을 그을 수 있었습니다. 이번 회고에서 얻은 가장 큰 교훈은 그것이었습니다.

Claude CodeMCPREST API토큰 최적화컨텍스트 윈도우프롬프트 캐시회고