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 로 갈아엎으면 토큰이 다른 곳에서 새는 지점이 세 군데 생깁니다.
- schema 정보를 어딘가 박아야 함: endpoint 가이드를 시스템 프롬프트나 CLAUDE.md 에 박으면 결국 schema 와 비슷한 토큰을 지불하게 됩니다. 안 박으면 LLM 이 환각으로 잘못된 매개변수를 만듭니다.
- 매개변수가 길고 구조화되어 있음:
content가 5000자 markdown,tags가 배열,seo가 중첩 객체라면, CLI argv 로 표현하기 위해 stdin / here-doc 우회 + shell escaping 토큰을 추가로 지불합니다. - 다단계 연쇄에서 매 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 Code MCP 서버 정리 — 불필요한 도구 제거로 토큰 35% 절약하기
Claude Code의 MCP 서버 10개를 분석해 불필요한 4개를 제거했습니다. MCP 도구 정의가 매 메시지마다 시스템 프롬프트에 들어가 71K 토큰을 소비하고 있었다는 사실, 그리고 실제 정리 과정을 공유합니다.
Claude Code에서 블로그 글 작성하기: MCP를 직접 만들어 활용한 경험
Claude Code로 개발하면서 얻은 지식을 블로그에 정리하고 싶었습니다. 하지만 AI에게 블로그 관리자 권한을 모두 주기엔 불안했고, 필요한 API만 분기 처리하기엔 번거로웠습니다. MCP(Model Context Protocol)를 직접 만들어서 권한을 명확히 분리하고, Few-shot 예시와 SEO 가이드라인을 1회 호출로 제공하도록 개선한 경험을 공유합니다.
Playwright MCP 19개 프로세스 사고, LaunchAgent HTTP 상주로 통합한 회고
Claude Code 대화 세션을 닫으면 stdio Playwright MCP 도 같이 종료될 줄 알았습니다. 8개 세션을 띄워두고서야 19개 프로세스 1.6GB 점유를 측정했고, LaunchAgent HTTP 상주 모델로 통합한 운영 회고입니다.