지금까지 만든 MCP 서버는 다 로컬이에요. 내 맥북 꺼지면 팀원은 못 써요. 로컬 MCP는 나만 쓸 수 있고 내 맥북이 꺼지면 그대로 끝나버리는 구조인데, 서버에 올려서 운영하는 MCP는 팀원 A, B, C가 전부 같은 서버에 연결해서 쓸 수 있어요. 토큰도 한 곳에서 관리할 수 있고 내 맥북 상태와 상관없이 24시간 돌아간다는 게 가장 큰 차이예요.
1단계 — MCP 서버를 HTTP로 변환
기존 stdio 방식 MCP를 HTTP 서버로 바꿔요. 원래 로컬 방식은 stdio_server를 통해 표준 입출력으로만 통신하기 때문에 같은 머신 안에서만 동작해요.
# 로컬에서만 동작
async with stdio_server() as (read, write):
await app.run(read, write, ...)
이 방식은 프로세스가 같은 머신에 떠 있어야만 동작하기 때문에 팀 단위 배포에는 쓸 수 없어요. 이걸 HTTP로 바꾸려면 SSE(Server-Sent Events) 전송 방식을 쓰는 Starlette 기반 서버로 다시 짜야 해요.
# server.py
from mcp.server import Server
from mcp.server.sse import SseServerTransport
from starlette.applications import Starlette
from starlette.routing import Route, Mount
from starlette.responses import JSONResponse
import uvicorn
import os
app = Server("team-mcp")
# 툴 정의 (기존과 동일)
@app.list_tools()
async def list_tools():
return [...]
@app.call_tool()
async def call_tool(name, arguments):
...
# HTTP + SSE 서버로 변환
sse = SseServerTransport("/messages")
async def handle_sse(request):
# 인증 체크
api_key = request.headers.get("X-API-Key")
if api_key != os.environ["MCP_API_KEY"]:
return JSONResponse({"error": "Unauthorized"}, status_code=401)
async with sse.connect_sse(
request.scope, request.receive, request._send
) as streams:
await app.run(streams[0], streams[1], app.create_initialization_options())
starlette_app = Starlette(
routes=[
Route("/sse", endpoint=handle_sse),
Mount("/messages", app=sse.handle_post_message),
Route("/health", endpoint=lambda r: JSONResponse({"status": "ok"}))
]
)
if __name__ == "__main__":
uvicorn.run(starlette_app, host="0.0.0.0", port=8000)
list_tools와 call_tool 함수는 기존 stdio 버전 그대로 가져오면 되고, 새로 추가된 부분은 SSE 연결과 API 키 인증, 헬스체크 엔드포인트예요. 특히 handle_sse 안에서 X-API-Key 헤더를 검증하는 부분이 핵심인데, 이게 없으면 URL만 아는 누구나 서버에 접근할 수 있게 돼요.
2단계 — Docker로 컨테이너화
서버 코드가 준비됐으면 이제 어디서든 똑같이 띄울 수 있도록 컨테이너로 묶어야 해요. Dockerfile은 Python 슬림 이미지 위에 의존성을 설치하고 코드를 복사하는 단순한 구조예요.
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "server.py"]
requirements.txt에는 서버 실행에 필요한 패키지를 정리해두면 돼요.
# requirements.txt
mcp
uvicorn
starlette
asyncpg
httpx
python-dotenv
이렇게 두 파일만 준비되면 로컬에서 바로 빌드하고 테스트할 수 있어요.
# 로컬 테스트
docker build -t team-mcp .
docker run -p 8000:8000 \
--env-file .env \
team-mcp
# 헬스 체크
curl http://localhost:8000/health
# {"status": "ok"}
헬스 체크 응답으로 {"status": "ok"}가 떨어지면 컨테이너가 정상적으로 떠 있다는 뜻이고, 이 상태에서 바로 배포 단계로 넘어가면 돼요.
3단계 — Railway 배포 (제일 간단)
Railway는 GitHub 연동하면 자동 배포돼요. 설정 거의 없어요. CLI로 직접 배포하고 싶다면 아래처럼 설치하고 로그인한 다음 init과 up만 실행하면 끝이에요.
# Railway CLI 설치
npm install -g @railway/cli
# 로그인
railway login
# 프로젝트 생성 및 배포
railway init
railway up
명령어 네 줄이면 배포가 끝나는데, 이렇게 배포한 다음에는 Railway 대시보드에서 환경변수를 따로 설정해줘야 해요. DB 접속 정보나 외부 서비스 토큰처럼 민감한 값들을 여기에 넣어두면 코드에는 전혀 노출되지 않아요.
CLAUDE_DATABASE_URL = postgresql://claude_readonly:...
GITHUB_TOKEN = ghp_...
SLACK_BOT_TOKEN = xoxb-...
MCP_API_KEY = team-secret-key-here ← 팀 공유용 키
이 중에서 MCP_API_KEY만 팀원들에게 공유하면 되고, 나머지 값들은 서버에만 남아 있어요. 배포가 끝나면 https://team-mcp-production.up.railway.app 형태의 URL이 발급되는데, 이 주소가 곧 팀원들이 연결할 엔드포인트가 돼요.
4단계 — 팀원 Claude Code 연결
팀원들은 발급받은 URL과 API 키만 있으면 바로 연결할 수 있어요. claude mcp add 명령어로 등록하는 방법이 가장 간단해요.
claude mcp add team-mcp \
--transport http \
--header "X-API-Key: team-secret-key-here" \
https://team-mcp-production.up.railway.app/sse
매번 같은 명령어를 치기 번거롭다면 프로젝트 안에 설정 파일로 넣어두는 방법도 있어요. .claude/mcp.json에 아래처럼 작성해두면 프로젝트를 열 때마다 자동으로 연결돼요.
{
"mcpServers": {
"team-mcp": {
"type": "http",
"url": "https://team-mcp-production.up.railway.app/sse",
"headers": {
"X-API-Key": "${MCP_API_KEY}"
}
}
}
}
팀원은 .env에 MCP_API_KEY만 넣으면 돼요. DB 비밀번호, GitHub 토큰 같은 민감한 정보는 서버에만 있고 팀원한테 공유 안 해도 돼요.
로컬 vs 서버 배포 비교
항목 로컬 MCP 서버 배포 MCP
| 설정 | 개인 .env | 서버 환경변수 |
| 팀 공유 | 각자 토큰 발급 | MCP_API_KEY만 공유 |
| 가용성 | 내 맥북 켜져 있을 때만 | 24/7 |
| 비용 | 무료 | Railway 약 $5/월 |
| 관리 | 개인 관리 | 중앙 관리 |
소규모 팀(3인 이하)이면 로컬로 충분해요. 5인 이상이면 서버 배포가 편해요.
마무리
결국 MCP 서버를 로컬에 둘지 서버로 올릴지는 팀 규모와 가용성 요구사항에 따라 갈리는 선택이에요. 인원이 적고 가볍게 쓰는 단계라면 로컬 stdio 방식으로도 충분히 버틸 수 있지만, 팀이 커지면서 누군가의 맥북 상태에 의존하는 구조는 금방 한계에 부딫혀요. HTTP로 전환하고 Docker로 묶어서 Railway 같은 플랫폼에 올려두면 토큰 관리와 가용성 문제를 한 번에 해결할 수 있고, 팀원은 API 키 하나만 받아서 바로 연결하면 돼요. 보안 측면에서는 X-API-Key 인증과 민감 정보의 서버 측 보관이 핵심이니, 배포 전에 이 부분만큼은 꼭 한 번 더 점검해보는 게 좋아요.
'MCP' 카테고리의 다른 글
| MCP Server Cards — AI용 robots.txt, 서버 능력을 자동으로 알리는 법 (0) | 2026.04.14 |
|---|---|
| Tool Poisoning Attack — 악성 MCP 서버가 Claude를 해킹하는 법 (0) | 2026.04.14 |
| MCP 서버 보안 설정 완전 가이드 — 인증, 권한 제한, 위험 차단 (0) | 2026.04.14 |
| 여러 MCP 조합하기 — DB + Slack + GitHub 연동으로 자동화 파이프라인 만들기 (0) | 2026.04.14 |
| GitHub MCP 연동 실전 가이드 — 이슈 분석부터 PR 생성까지 자동화 (1) | 2026.04.14 |