Cloudflare Workers에 원격 MCP 서버 구축하기: 제로부터 프로덕션까지의 실용 가이드
요약
본 가이드는 MCP(Model Context Protocol) 서버를 로컬 환경 대신 Cloudflare Workers에 원격으로 구축하고 배포하는 실용적인 방법을 안내합니다. 이를 통해 에이전트 기능을 팀 전체가 공유할 수 있으며, 개별 장치 설치의 불편함과 비밀 정보 분산 문제를 해결합니다.
핵심 포인트
- MCP 서버를 클라우드(Cloudflare)로 옮겨 팀 협업 및 접근성을 높일 수 있습니다.
- 원격 MCP는 Streamable HTTP 전송 방식을 사용하며, Cloudflare Workers가 이를 구현하기에 적합합니다.
- 프로젝트 구축 시 `wrangler`와 `@modelcontextprotocol/sdk`, Durable Objects를 활용하는 것이 핵심입니다.
- 무료 플랜에서 SQLite 기반의 Durable Object를 사용하는 방법을 숙지해야 합니다.
이번 주 Hacker News에서 흥미롭지만 작은 Show HN 글을 발견했습니다. 누군가 Cloudflare를 이용해 WhatsApp MCP 서버를 무료로 구동하는 내용이었습니다. 이 글은 점수가 높지는 않지만, 제가 한국 개발자들이 빨리 시도해 봐야 할 방향성을 보여줍니다. MCP (Model Context Protocol) 서버는 더 이상 로컬 노트북에 설치하고 stdio를 통해 실행할 필요가 없습니다. 에지(edge)에 배포하여 HTTP로 호출하고 팀 전체가 공유할 수 있습니다. 저는 내부 도구 몇 가지(주문 조회, 로그 읽기, 메모 저장 등)를 로컬 MCP에서 Cloudflare Workers로 옮겼습니다. 이 글은 그 방법을 기록했으며, 주의해야 할 지점들도 함께 다룹니다.
왜 MCP 서버를 원격으로 구축해야 하는가?
대부분의 MCP 튜토리얼은 서버를 로컬에서 실행하는 방법을 안내합니다. 클라이언트(Claude Desktop, Cursor, VS Code 등)가 프로세스를 생성하고 stdin/stdout을 통해 통신하는 방식입니다. 이 방법은 혼자 작업할 때는 괜찮지만, 다음과 같은 문제에 직면하게 됩니다:
- 모든 장치에 개별 설치 필요: Node 버전이 다르고, 환경 변수(env var)가 부족하거나, 사람마다 설정이 달라집니다.
- 비밀 정보 분산 저장: 데이터베이스나 타사 API 키가 각자의 컴퓨터에 있는 설정 파일에 복사됩니다.
- 웹 기반 클라이언트에서 사용 불가: 클라우드에서 실행되는 에이전트가 사용자 장치에 프로세스를 생성할 수 없습니다.
원격 MCP는 Streamable HTTP 전송 방식을 사용합니다 (MCP 사양 2025-03-26 버전부터 도입되었으며, 이전의 HTTP+SSE를 대체함). 클라이언트는 URL과 토큰만 있으면 됩니다. 비밀 정보는 서버에 저장되며, 변경 사항이 생기면 한 번 배포하면 팀 전체가 새 버전을 사용하게 됩니다.
Cloudflare Workers는 이 작업에 적합합니다. 왜냐하면 무료 티어에서 하루 100,000 요청을 제공하고, 콜드 스타트(cold start) 시간이 거의 0에 가깝기 때문입니다. 또한 Durable Objects (SQLite 버전)도 무료 플랜에서 사용할 수 있습니다. 각 MCP 세션은 별도의 Durable Object에 상태를 저장합니다.
flowchart LR
A[Claude / Cursor / Agent] -->|HTTPS + Bearer token| B[Cloudflare Worker]
B --> C{Auth check}
...
5분 만에 프로젝트 구축하기
저는 wrangler 4.x, Cloudflare의 agents 패키지, 그리고 공식 @modelcontextprotocol/sdk를 사용했습니다. Node 20 이상이 필요합니다.
npm create cloudflare@latest mcp-notes -- --type=hello-world --lang=ts
dc mcp-notes
npm install agents @modelcontextprotocol/sdk zod
...
Sửa wrangler.jsonc để khai báo Durable Object và KV binding:
{
"name": "mcp-notes",
"main": "src/index.ts",
...
많은 사람이 실수하는 부분: free plan에서는 반드시 new_sqlite_classes를 사용해야 합니다. 만약 new_classes (구형 Durable Object)를 선언하면, 배포 시 오류가 발생합니다.
서버 작성: 도구(tool), 입력값 검증 및 인증
이것은 src/index.ts 파일입니다. 서버에는 두 가지 도구가 있습니다: KV에 메모를 저장하는 save_note와 키워드를 기반으로 메모를 검색하는 search_notes.
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
...
실제 구동 후 얻은 몇 가지 유의사항:
- 항상 Zod로 제한을 설정 (
max(5000),min(2)). LLM은 때때로 수십 KB에 달하는 긴 텍스트 전체를 전송할 수 있습니다. 스키마가 있으면 해당 요청은 처음부터 차단되어 KV로 전달되지 않습니다. - 도구의 설명(Description)이 곧 프롬프트입니다. 모델은 설명을 읽고 도구를 호출할지 결정하므로, 간결하게 작성하고 도구가 무엇을 하는지 명확히 언급해야 합니다.
- 반환 결과 수를 제한 (여기서는 10개). 너무 많은 텍스트를 반환하면 모델의 컨텍스트 창(context window)을 소모하며, 토큰 비용은 사용자(당신)가 지불합니다.
- 정적 bearer token은 내부 도구에 사용하기에 충분합니다. 외부 사용자에게 공개할 경우,
@cloudflare/workers-oauth-provider를 사용하여 OAuth로 전환하는 것이 좋습니다.
테스트, 배포 및 클라이언트 연결
먼저 로컬에서 실행한 후, MCP Inspector를 사용하여 각 도구를 개별적으로 호출해 보세요:
npx wrangler dev # http://localhost:8787 에서 실행
# 다른 터미널
...
Accept 헤더에는 text/event-stream이 반드시 포함되어야 합니다. 이것이 누락되면 서버는 406 오류를 반환하며, 왜 문제가 생겼는지 이해하지 못한 채 디버깅 시간을 모두 낭비할 수 있습니다.
도구 호출 한 번의 처리 흐름은 다음과 같습니다:
sequenceDiagram
participant C as MCP Client
participant W as Worker
...
클라이언트가 stdio만 지원하는 경우(예: 일부 구형 Claude Desktop 버전), mcp-remote를 브릿지 역할로 사용할 수 있습니다: npx mcp-remote https://.../mcp --header "Authorization: Bearer ${TOKEN}".
비용 측면: 저희 팀 6명이 매일 몇 천 건의 요청을 사용하며, 여전히 무료 티어 내에 있습니다. 주의할 점은 KV 읽기(하루 10만 회 읽기까지 무료 티어) 횟수입니다. 위 search_notes의 get 루프는 읽기 비용이 상당히 많이 듭니다. 노트 수가 몇 천 개로 늘어나면, Durable Object 내부에 SQLite에 저장하고 LIKE를 사용하여 검색하는 방식으로 전환했습니다.
결론
Cloudflare Workers에서 원격 MCP(Remote MCP)를 구축하는 것은 팀 전체와 AI 도구를 공유할 수 있는 빠르고 저렴한 방법입니다. 요약하자면, 다음 사항들을 수행해야 합니다:
- 가장 유용한 1~2개의 도구부터 시작하세요 (내부 검색, 로그 읽기 등). 처음부터 모든 API를 감싸려고 시도하지 마세요.
- 무료 플랜에서 실행할 수 있도록 마이그레이션에
new_sqlite_classes를 사용하세요. - Zod로 모든 입력을 검증하고 출력 크기를 제한하여 토큰을 절약하세요.
- 첫날부터 인증(Auth) 구현:
wrangler secret을 통해 bearer token으로 시작하고, 공개할 때는 OAuth로 업그레이드하세요. - 실제 클라이언트에 연결하기 전에 MCP Inspector를 사용하여 테스트하고, 반드시
Accept: application/json, text/event-stream헤더를 기억하세요. - 대시보드에서 KV/DO 할당량을 모니터링하세요. 읽기(read)가 빠르게 증가하면 검색 부분을 SQLite로 전환하세요.
첫 번째 버전을 오후 한 번 만에 완성할 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기