MCP 배포: MCP 서버 호스팅에 대해 말해주지 않는 것들 (3개월간의 운영 중 겪은 고통으로부터)
요약
MCP(Model Context Protocol) 서버를 로컬 환경을 넘어 실제 서비스로 배포할 때 발생하는 문제점과 경험을 다룹니다. Heroku와 같은 플랫폼 사용 시 발생하는 콜드 스타트, 타임아웃, 휘발성 파일 시스템 등의 기술적 한계를 분석합니다.
핵심 포인트
- MCP 서버의 실질적인 활용을 위해서는 24/7 가용성을 위한 공개 배포가 필수적임
- Heroku 무료 티어는 수면 모드로 인한 연결 타임아웃 문제가 발생함
- 상태 비저장(Stateless) 설계가 아니면 휘발성 파일 시스템 환경에서 데이터 유실 위험이 있음
- AI 클라이언트의 타임아웃 제한을 고려한 서버 응답 속도 확보가 중요함
MCP 배포: MCP 서버 호스팅에 대해 말해주지 않는 것들 (3개월간의 운영 중 겪은 고통으로부터)
솔직하게 말씀드리겠습니다. 저는 약 3개월 동안 저의 1,800시간 분량의 개인 지식 베이스를 위한 MCP 서버를 구축해 왔습니다. 설계 교훈, 에러 처리 시 주의사항(gotchas), 인증 문제 등 모든 측면에 대해 75개의 글을 작성했습니다.
하지만 저는 **배포 (deployment)**에 대해서는 제대로 이야기하지 않았습니다. 그리고 솔직히 말해서? 바로 그 지점에서 대부분의 진짜 고통이 발생합니다.
자, 문제는 이렇습니다. 모든 튜토리얼은 MCP 서버를 로컬(locally)에서 구축하는 방법만 보여줍니다. 엔드포인트(endpoints) 코드를 제공하고, 인증을 처리하는 방법을 보여준 뒤 여러분을 떠나보냅니다. 하지만 여러분의 AI 어시스턴트가 어디서든 연결할 수 있도록 해당 서버를 24시간 내내 실제로 구동하는 문제에 있어서는... 아무런 말이 없습니다.
저는 고생하며 배웠습니다. 여러분이 그 고통을 겪지 않도록 제가 도와드리겠습니다.
문제점: MCP는 공개 액세스(Public Access)가 필요함
로컬 개발 서버와 달리, MCP 서버는 AI 클라이언트(clients)가 접근할 수 있어야 합니다. Claude Desktop을 사용 중이라면 로컬에서 실행할 수 있습니다. 하지만 다음과 같은 경우를 원한다면 상황이 달라집니다:
- 여러 AI 클라이언트 (데스크톱 + 모바일 + 웹)
- 팀원 또는 서버를 사용하는 다른 사람들
- localhost에 접근할 수 없는 클라우드 기반 AI 어시스턴트
- 컴퓨터를 계속 켜두지 않고도 가능한 24/7 가용성
여러분은 서버를 어딘가 공개된 곳에 배포해야 합니다.
그리고 바로 여기서부터 재미있는 일이 시작됩니다.
나의 첫 번째 시도: Heroku Free Dyno
저는 쉬웠기 때문에 Heroku로 시작했습니다. 이전에도 사이드 프로젝트에 사용한 적이 있었습니다. 무료 티어(Free tier), 쉬운 Git 배포, 자동 HTTPS... 무엇이 잘못될 수 있겠습니까?
음... 그 부분에 대해 이야기해 봅시다.
장점:
- 매우 쉬운 배포 (
git push heroku main) - 즉시 사용 가능한 자동 HTTPS
- 시작하기 좋은 무료 티어
- 필요할 경우 확장 가능 (단, 비용 발생)
단점:
- 무료 dyno(dyno)는 30분 동안 활동이 없으면 sleep(수면) 상태로 전환됩니다. 즉, 30분 후에 AI 클라이언트가 연결을 시도하면 dyno를 깨워야 한다는 뜻입니다. 이 과정은 10~30초가 소요됩니다. 그리고 때로는... 그냥 실패하기도 합니다.
- MCP 클라이언트는 긴 타임아웃 (timeout)을 잘 처리하지 못합니다. 연결이 10초 이상 걸리면 연결을 끊어버립니다.
- 매달 550시간의 무료 런타임 (runtime)이 제공됩니다. 이는 약 18일 정도에 불과합니다. 24/7(연중무휴) 운영을 원한다면 비용을 지불해야 합니다 (최소 월 $5).
- 휘발성 파일 시스템 (Ephemeral filesystem) — dyno가 재시작되면 작성한 모든 데이터가 사라집니다. 외부 데이터베이스에 연결하는 상태 비저장 (stateless) MCP 서버라면 괜찮지만, 간단한 마크다운 (markdown) 파일을 로컬에 저장하려 한다면... 안 됩니다.
나의 경험: 10점 만점에 3점. 테스트용으로는 작동하지만, 일상적인 사용에는 끔찍합니다. 지식 베이스를 검색하고 싶을 때마다 발생하는 "연결 시간 초과 (connection timed out)" 오류에 지쳐버렸습니다.
참고용으로, 제 Heroku Procfile이 어떻게 생겼었는지 보여드립니다:
web: java -jar target/mcp-knowledge-server-1.0.0.jar --port=$PORT
복잡하지는 않습니다. 단지 24/7 사용을 위해 안정적으로 작동하지 않았을 뿐입니다.
두 번째 시도: Fly.io
사이드 프로젝트를 하는 친구들로부터 Fly.io에 대해 좋은 이야기를 들었습니다. 그래서 한번 시도해 보았습니다.
장점:
fly launch를 통한 매우 쉬운 배포- 글로벌 애니캐스트 (anycast) 네트워크 — 사용자 근처에 배포할 수 있음
- 무료 티어에서 하나의 작은 공유 CPU 앱 허용
- Let's Encrypt를 통한 자동 HTTPS
- 월 $0.15/GB 가격으로 지속성 볼륨 (Persistent volumes) 사용 가능
단점:
- 무료 티어 앱은 168시간(일주일) 동안 활동이 없으면 중단 (stop) 됩니다. 앱을 깨워두려면 크론 잡 (cron job)을 실행해야 합니다.
- 지속성 볼륨은 특정 리전 (region) 및 호스트에 종속됩니다. 만약 Fly가 앱을 다른 호스트로 이동시켜야 한다면, 볼륨을 수동으로 이동시켜야 합니다.
- 가격 체계가 혼란스러울 수 있습니다 — 송신 데이터 (egress), 스토리지 등에 대해 비용을 지불합니다. 하지만 작은 앱의 경우 여전히 꽤 저렴합니다 (제가 하던 작업 기준 월 약 $2-3).
- CLI는 훌륭하지만, 배포 문제를 디버깅하는 것은 까다로울 수 있습니다.
나의 경험: 6/10. 내 사용 사례에서는 Heroku보다 훨씬 나았습니다. 마크다운 (markdown) 파일들을 위한 지속성 볼륨 (persistent volume)을 확보할 수 있었고, Heroku보다 빨랐으며, 한 달에 몇 달러로 24/7 운영이 가능했습니다. "일주일 후 중지"되는 문제는 짜증스러웠지만, 매일 URL에 핑 (ping)을 보내는 무료 크론 잡 (cron job)을 사용해 쉽게 해결할 수 있었습니다.
궁금해하실 분들을 위해, 핵심 내용만 남긴 저의 fly.toml 파일입니다:
app = "my-mcp-knowledge-server"
primary_region = "hkg" # 중국에 있는 저와 가장 가까운 지역
...
그리고 저의 Dockerfile (Fly는 Docker를 사용합니다):
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml .
...
이 방식은 한동안 꽤 잘 작동했습니다. Fly에서 거의 두 달 동안 지식 베이스 (knowledge base)를 운영했습니다. 하지만...
Fly의 중국발 트래픽 라우팅 (traffic routing)이... 불안정한 문제를 겪었습니다. 때로는 연결하는 데 2~3초가 걸리기도 하고, 때로는 완전히 타임아웃 (time out)이 발생하기도 했습니다. 저는 중국에 있기 때문에, 이곳에서 더 나은 연결성을 가진 서비스가 정말로 필요했습니다.
그래서 저는 더 가까운 곳을 시도해 보기로 했습니다.
현재 설정: Tencent Cloud Serverless Cloud Function (SCF)
저는 중국에 있기 때문에, 중국 클라우드 제공업체들이 더 낮은 지연 시간 (latency)을 제공합니다. 저는 트래픽이 많지 않기 때문에 (하루에 저 혼자 몇 번 사용하는 정도) 서버리스 (serverless)를 시도해 보기로 했습니다. 저 혼자 쓰는데 굳이 전체 VM (가상 머신) 비용을 지불할 필요가 있을까요?
장점:
- 종량제 (Pay-as-you-go) — 저의 아주 적은 사용량 기준으로 월 약 $0.50 정도입니다. 커피 한 잔 값보다 저렴합니다.
- 중국에 있는 저와 더 가까워서 지연 시간이 매우 낮습니다 (Fly의 300-500ms 대비 50-100ms).
- 자동 확장 (Automatic scaling) — 만약 다른 누군가가 갑자기 사용하기 시작하더라도 자동으로 확장됩니다.
- 무료 티어 (Free tier)에 많은 무료 호출 (invocations)이 포함되어 있습니다 — 기본적으로 거의 무료로 운영할 수 있습니다.
- 마크다운 파일을 위한 지속성 COS (객체 스토리지, object storage)를 지원합니다.
단점:
- 콜드 스타트 (Cold starts)! 몇 분 동안 실행되지 않았다면, 시작하는 데 2~5초가 걸립니다. 그래도 Heroku의 30초 콜드 스타트보다는 낫습니다.
- 서버리스 (Serverless)는 앱이 상태가 없다 (stateless)는 것을 의미합니다. 즉, 데이터를 다른 곳(COS, 데이터베이스)에 저장해야 합니다. 큰 문제는 아니지만, 이를 고려하여 설계해야 합니다.
- 중국 클라우드는 특유의 까다로운 점이 있습니다. 모든 것이 중국어로 되어 있고, 콘솔은 압도적이며, API 게이트웨이 (API Gateway) 설정은 까다롭습니다.
- HTTPS는 자동으로 적용되지만, 커스텀 도메인을 작동시키려면 이것저것 클릭하며 설정해야 합니다.
나의 경험: 7.5/10. 나의 사용 사례(개인 지식 베이스, 하루에 몇 번만 사용하는 용도)에는 완벽합니다. 저렴하고, 지연 시간 (latency)이 좋으며, 콜드 스타트도 관리 가능한 수준입니다. 중국에 있다면 이것을 추천합니다. 중국에 있지 않다면, Fly.io나 다른 제공업체가 아마 더 쉬울 것입니다.
대략적인 구조는 다음과 같습니다:
- **SCF 함수 (SCF Function)**가 Java Spring Boot 앱을 실행합니다 (네, 커스텀 런타임 (custom runtime)을 사용하면 SCF에서 Java가 작동합니다).
- **API 게이트웨이 (API Gateway)**가 HTTP 요청을 처리하고, 저에게 공개 HTTPS 엔드포인트 (endpoint)를 제공합니다.
- **COS 버킷 (COS Bucket)**이 모든 마크다운 파일을 저장합니다. MCP 서버는 검색할 때 COS에서 파일을 읽습니다.
- **클라우드 모니터 (Cloud Monitor)**가 10분마다 엔드포인트에 핑 (ping)을 보내 항상 콜드 상태로 있는 것을 방지합니다.
복잡성이 추가되느냐고요? 네, 약간은 그렇습니다. 하지만 가격과 지연 시간을 고려하면 저에게는 가치가 있습니다.
VPS / 전용 VM (Dedicated VM)은 어떤가요?
물론, 언제든지 일반적인 VPS에 배포할 수도 있습니다. 저는 다른 프로젝트들을 위해 그렇게 해왔습니다. 내용을 나누어 살펴보겠습니다:
장점:
- 완전한 제어권 — 원하는 것은 무엇이든 할 수 있고, 무엇이든 설치할 수 있습니다.
- 콜드 스타트 없음, 수면 없음, 중단 없음 — 항상 실행 중입니다.
- 예측 가능한 가격 — 매달 동일한 금액을 지불합니다.
- Docker를 사용하여 설정하기 쉽습니다.
단점:
- 트래픽이 적은 앱의 경우 서버리스 (serverless)보다 비쌈 — 최소 월 $5-10
- 직접 유지 관리해야 함 — 보안 업데이트, OS 업그레이드, 모니터링 등
- HTTPS를 직접 관리해야 함 (비록 Let's Encrypt 덕분에 지금은 매우 쉬워졌지만)
- 방화벽 규칙 설정, Nginx를 이용한 리버스 프록시 (reverse proxy) 설정 등이 필요함
나의 생각: 여러 개의 MCP 서버를 운영하거나 상당한 트래픽이 예상된다면, 이 방식이 정답입니다. 오직 당신만 사용하는 개인 사이드 프로젝트라면... 과하고 불필요하게 비쌉니다. 하지만 Linux에 익숙하다면 확실히 가장 직관적인 옵션입니다.
MCP 서버를 위한 기본적인 Nginx 설정은 다음과 같습니다:
server {
listen 80;
server_name your-domain.com;
...
Certbot으로 SSL을 추가하면 준비 끝입니다. 그리 복잡한 작업은 아닙니다.
Ngrok 개발 워크플로우 (The Ngrok Development Workflow)
좋습니다, 무언가를 프로덕션 (production) 환경에 배포하기 전에... 테스트를 해야겠죠? 로컬에서 개발할 때, 저는 ngrok를 사용하여 로컬 서버를 인터넷에 노출시켜 다양한 MCP 클라이언트(client)로 테스트할 수 있도록 합니다.
이것은 실제로 게임 체인저 (game-changer)입니다.
장점:
- 단 한 번의 명령:
ngrok http 8080을 입력하면 몇 초 만에 공개 HTTPS URL이 생성됩니다. - 개발 중인 동안 원격 MCP 클라이언트로 테스트하기에 완벽합니다.
- 무료 티어 (Free tier)도 개발용으로는 충분히 잘 작동합니다.
- ngrok를 통과하는 모든 트래픽을 검사할 수 있습니다 — 디버깅 (debugging)에 매우 유용합니다.
단점:
- 무료 티어는 세션 타임아웃 (session timeouts)이 있습니다 — 몇 시간 뒤에 ngrok 터널이 끊깁니다.
- ngrok를 재시작할 때마다 URL이 변경됩니다 — 매번 클라이언트 설정을 업데이트해야 합니다.
- 프로덕션용이 아님 — 생각조차 하지 마세요. Ngrok는 개발용이지, 프로덕션 호스팅용이 아닙니다.
나의 일상적인 워크플로우:
- 로컬의 8080 포트에서 MCP 서버 시작
ngrok http 8080실행- ngrok HTTPS URL을 MCP 클라이언트 설정에 복사
- 모든 기능 테스트
- 제대로 작동하면 프로덕션에 배포
솔직히 말해서, MCP 서버를 구축하고 있고 실제 클라이언트로 테스트해야 한다면, ngrok는 필수적입니다. 너무나 유용하기 때문입니다.
내가 고생하며 배운 뼈아픈 교훈들
자, 이제 아무도 말해주지 않는 내용들을 본격적으로 다뤄보겠습니다. 이것들은 제가 수 시간의 디버깅(debugging) 비용을 치르며 저질렀던 실수들입니다.
1. 서버에 항상 읽기 제한 시간(Read Timeout)을 설정하세요
MCP 클라이언트들은 상당히 참을성이 없습니다. 만약 검색에 10초 이상이 걸린다면, 클라이언트는 연결을 끊어버릴 것입니다. 하지만 더 최악인 게 무엇인지 아십니까? 서버에 읽기 제한 시간(read timeout)이 설정되어 있지 않으면, 유휴 연결(idle connections)이 쌓여 결국 모든 파일 디스크립터(file descriptors)를 점유해 버릴 수 있습니다.
Spring Boot에서는 application.properties에 다음과 같이 설정했습니다:
server.tomcat.connection-timeout=20000
server.tomcat.threads.max=200
연결 제한 시간 20초, 최대 스레드(threads) 200개. 제 사용 사례에는 충분하고도 남는 설정이며, 시스템을 안정적으로 유지해 줍니다.
2. 상태 확인 엔드포인트(Health Check Endpoints)는 당신의 친구입니다
대부분의 클라우드 제공업체는 앱이 살아있는지 확인하기 위해 핑(ping)을 보낼 수 있는 상태 확인(health check) 엔드포인트를 기대합니다. 저는 간단한 것을 추가했습니다:
@RestController
public class HealthController {
...
그게 전부입니다. 이제 클라우드 제공업체는 매 분마다 /health에 핑을 보내 앱을 활성 상태로 유지하고 장애를 감지할 수 있습니다. 정말 값진 작업입니다.
3. CORS 프리플라이트(Preflight) 요청을 잘못 다루면 모든 것이 망가집니다
인증(authentication) 관련 글에서도 언급했지만, 다시 한번 반복할 가치가 있습니다. CORS 프리플라이트(preflight) OPTIONS 요청에는 인증 헤더(authentication headers)가 포함되지 않습니다. 만약 모든 요청(OPTIONS 포함)에 인증을 요구한다면, CORS는 작동하지 않을 것입니다.
CORS 설정이 인증 없이도 OPTIONS를 허용하도록 구성해야 합니다:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
...
네, 공개 MCP 서버라면 모든 오리진(*)을 허용해도 괜찮습니다. 만약 혼자서만 사용한다면 특정 오리진으로 제한할 수도 있겠지만, 솔직히... 개인적인 용도로는 그리 큰 문제가 되지 않습니다.
4. 문제가 발생했을 때 로그(Logs)가 전부입니다
MCP 서버가 작동을 멈추고 클라이언트가 단순히 "연결 실패 (connection failed)"라고만 표시할 때, 가장 먼저 확인해야 할 곳은 로그 (logs)입니다. 로그를 제대로 남기고 있는지 반드시 확인하세요. 대부분의 클라우드 플랫폼에서는 일정 기간 동안 무료 로그 저장 공간을 제공합니다. 이를 적극 활용하세요.
Fly.io에서는 다음과 같이 실행하기만 하면 됩니다:
fly logs -a my-mcp-app
그러면 무슨 일이 일어나고 있는지 확인할 수 있습니다. SCF에서는 콘솔에서 확인할 수 있습니다. 핵심은 중요한 것들 — 들어오는 요청 (incoming requests), 에러 (errors), 느린 쿼리 (slow queries) — 을 로그로 남기는 것입니다. 필요하다고 생각하는 것보다 더 많이 로그를 남기는 것을 두려워하지 마세요. 무언가 고장 났을 때, 저에게 고마워하게 될 것입니다.
5. 단순하게 시작하고, 그 다음에 최적화하세요
저는 처음에 배포 과정을 너무 복잡하게 만들었습니다. 직장에서 사용하는 방식이라서 Kubernetes를 설정하려고 시도했죠. 개인용 MCP 서버를 위해서요? 그건 말도 안 되는 일입니다. 제가 했던 실수를 반복하지 마세요.
작동 가능한 가장 단순한 것부터 시작하세요:
- 단순히 테스트 중이라면 → ngrok
- 프로덕션 (production) 준비가 되었고 사용자도 본인뿐이라면 → Fly.io 또는 이와 유사한 저렴한 플랫폼
- 특정 지역에서 더 나은 지연 시간 (latency)이 필요하다면 → 로컬 클라우드 제공업체 확인
- 여러 서비스를 실행해야 한다면 → Docker Compose를 사용하는 VPS
그렇다면 MCP 서버를 어디에 배포해야 할까요?
솔직히 말해서, 사용 사례 (use case)에 따라 다릅니다. 저의 추천을 말씀드리겠습니다:
| 사용 사례 (Use Case) | 추천 (Recommendation) | 예상 비용 (Expected Cost) |
|---|---|---|
| 로컬 개발 전용 | ngrok | 무료 |
| ... |
제 개인적인 의견으로는, MCP 서버를 구축하는 대부분의 사람들에게 Fly.io가 가장 적절한 지점 (sweet spot)이라고 생각합니다. 쉽고, 저렴하며, 충분히 신뢰할 수 있습니다. (중국에 있는 것과 같은) 특정한 요구 사항이 없다면, 그냥 Fly.io를 선택하세요. 10분 안에 실행할 수 있을 것입니다.
마무리
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기