MCP 서버 만드는 법은 2026년 현재 30분이면 끝난다. Python 3.10 이상에서 pip install "mcp[cli]" 한 줄로 SDK를 설치하고, FastMCP 클래스에 도구 함수를 데코레이터로 붙인 다음, mcp.run(transport="streamable-http")로 실행하면 그 자리에서 Claude·ChatGPT·Cursor·VS Code가 호출할 수 있는 MCP 서버가 된다. 이 글은 그 30분을 단계별로 쪼개서, 환경 준비부터 Docker 배포까지 실제 명령어와 코드로 보여준다.
독자는 Python을 쓸 줄 알지만 MCP 서버는 만들어본 적 없는 한국 개발자를 가정한다. 사내 API·RAG 파이프라인·캘린더·이슈 트래커를 LLM에 연결해야 하는데 매번 함수 호출용 어댑터를 새로 짜기 지친 사람이 정확한 타깃이다. 따라 하면 자원을 표준 프로토콜 한 벌로 노출할 수 있다.
2026년 6월 기준 표준 경로는 두 갈래다. 공식 mcp SDK(1.27.2)와 독립판 fastmcp(3.4.2). 둘 중 무엇을 골라야 하는지도 이 글에서 다룬다. 기준일: 2026-06-10.
목차
- 공식 mcp vs fastmcp 한눈 비교표
- 1단계: 환경 준비 (uv)
- 2단계: 30줄짜리 최소 서버
- 3단계: Tool · Resource · Prompt
- 4단계: 전송 방식 선택
- 5단계: Docker 배포
- 6단계: Claude Desktop·Cursor 연결
- FAQ 4가지 + 결론
공식 mcp vs fastmcp — 어떤 걸 깔아야 할까
설치 한 줄 차이지만 향후 유지보수가 달라진다. 두 패키지 비교는 다음과 같다.
| 항목 | 공식 mcp SDK | fastmcp 독립판 |
|---|---|---|
| PyPI 패키지 | mcp | fastmcp |
| 최신 버전 (기준일 2026-06-10) | 1.27.2 (2026-05-29) | 3.4.2 (2026-06-06) |
| 유지 주체 | Anthropic / MCP 공식 | jlowin + 커뮤니티 |
| Python 요구 | 3.10 이상 | 3.10 이상 |
| FastMCP 클래스 import | from mcp.server.fastmcp import FastMCP | from fastmcp import FastMCP |
| 전송 지원 | stdio · SSE · Streamable HTTP | stdio · SSE · Streamable HTTP · WebSocket 실험 |
| 업데이트 주기 | 스펙 동기화 위주 | 주 1~2회, 신기능 빠름 |
| 권장 용도 | 안정·장기 운영 | 최신 기능·실험 |
이 글의 예제는 공식 SDK 기준이며, fastmcp로 바꾸려면 import 한 줄만 교체하면 된다. 사내 운영 서버라면 공식, 신기능을 빠르게 추적해야 한다면 독립판이다.
1단계: 환경 준비 — uv로 5분이면 끝
2026년 기준 Python 의존성 관리는 uv가 사실상 표준이다. pip 대비 10배 이상 빠르고, 가상환경과 패키지 설치를 한 명령으로 묶는다.
# uv 설치 (macOS / Linux)
curl -LsSf https://astral.sh/uv/install.sh | sh
# 프로젝트 생성
mkdir mcp-demo && cd mcp-demo
uv init --python 3.12
uv add "mcp[cli]"
# 서버 파일 생성
touch server.py
mcp[cli]는 SDK 본체와 mcp dev, mcp install CLI를 함께 설치한다. CLI가 있어야 Claude Desktop에 한 줄로 등록할 수 있다. uv가 막혀 있다면 pip install "mcp[cli]"로 대체해도 동일하다.
2단계: 30줄짜리 최소 서버
아래 코드 하나로 Claude Desktop·Cursor·VS Code Copilot Chat이 호출할 수 있는 완전한 MCP 서버가 만들어진다.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("kez9-demo")
@mcp.tool()
def add(a: int, b: int) -> int:
"""두 정수를 더해 결과를 돌려준다."""
return a + b
@mcp.resource("greeting://{name}")
def greet(name: str) -> str:
"""사용자 이름을 받아 인사말을 만든다."""
return f"안녕하세요, {name}님."
@mcp.prompt()
def code_review(diff: str) -> str:
"""코드 리뷰 프롬프트 템플릿."""
return f"다음 diff를 한국어로 리뷰해 주세요.\n\n{diff}"
if __name__ == "__main__":
mcp.run(transport="streamable-http")
실행은 uv run server.py 한 줄이다. 기본 포트 8000. 도구의 docstring은 LLM이 그대로 사용 설명서로 읽기 때문에 정확하고 짧게 쓴다.
3단계: 세 가지 빌딩 블록 — Tool · Resource · Prompt
MCP 서버는 클라이언트에 세 종류의 능력을 노출한다.
- Tool (
@mcp.tool()) — 부작용 있는 동작. DB 쓰기, 메일 전송, 외부 API 호출. LLM이 능동적으로 호출한다. - Resource (
@mcp.resource("uri://template")) — 읽기 전용 데이터. 파일·문서·설정값. URI 템플릿의 변수가 자동으로 함수 인자가 된다. - Prompt (
@mcp.prompt()) — 재사용 프롬프트 템플릿. 사용자가 슬래시 커맨드로 고르는 사전 정의 문구. 코드 리뷰·요약·번역에 유용하다.
Tool과 Resource 경계가 헷갈리면 원칙은 단순하다. 같은 인자로 호출해 결과가 같고 부작용 없으면 Resource, 한 번이라도 상태를 바꾸면 Tool이다.
4단계: 전송 방식 — stdio·SSE·Streamable HTTP
MCP는 동일 메시지 스키마를 세 전송 위에서 돌린다. 선택 기준은 배포 환경이다.
| 전송 | 적합 환경 | 장점 | 한계 |
|---|---|---|---|
| stdio | 로컬 데스크톱 클라이언트 (Claude Desktop, Cursor) | 인증 불필요, 가장 단순 | 원격 호스팅 불가 |
| SSE | 레거시 원격 서버 | HTTP 기반, 방화벽 친화 | 스펙상 단계적 폐기 중 |
| Streamable HTTP | 2026년 신규 원격 서버 권장 | 단방향·양방향 모두 지원, 인증 표준화 | SDK 1.6 이상 필요 |
신규 서버는 무조건 Streamable HTTP다. SSE는 공식 문서가 “superseded”로 표기하기 시작했다. 로컬 개인용은 stdio가 가장 마찰이 적다. mcp.run(transport="stdio")로 바꾸기만 하면 된다.
5단계: Docker로 배포
로컬 동작이 확인되면 컨테이너로 묶는다. Dockerfile은 한 장이면 충분하다.
FROM python:3.12-slim
WORKDIR /app
RUN pip install --no-cache-dir "mcp[cli]==1.27.2"
COPY server.py .
EXPOSE 8000
CMD ["python", "server.py"]
빌드·실행:
docker build -t kez9-mcp:0.1 .
docker run -p 8000:8000 kez9-mcp:0.1
리버스 프록시(Caddy·Traefik·Nginx) 뒤에 TLS와 Authorization: Bearer ... 토큰 인증을 붙이면 사외에서도 호출된다. Fly.io·Railway·Cloud Run 모두 추가 설정 없이 동작한다.
6단계: 클라이언트 연결
로컬 stdio 서버는 한 줄이다.
mcp install server.py
이 명령은 Claude Desktop 설정 파일에 항목을 자동으로 추가한다. 원격 Streamable HTTP 서버라면 클라이언트 설정 JSON에 { "url": "https://your.host/mcp" } 형태로 등록한다.
FAQ
Q1. Python 외 언어로도 MCP 서버를 만들 수 있나요?
네. 2026년 6월 현재 TypeScript·Go·Rust·C#·Java·Kotlin·Swift SDK가 공식으로 유지된다. 사내 언어를 그대로 따라가는 것이 정답이지만, 기능 추가가 가장 빠른 쪽은 Python과 TypeScript다.
Q2. 인증·권한 분리는 어떻게 하나요?
Streamable HTTP는 OAuth 2.1 Bearer Token을 표준 지원한다. 도구 단위 권한 분리는 각 함수에서 토큰을 검사해 거부하는 방식이 일반적이다. 정교한 제어는 fastmcp 3.x 미들웨어 훅이 깔끔하다.
Q3. Function Calling과 무엇이 다른가요?
Function Calling은 한 벤더에 묶인 호출 규약이고, MCP는 클라이언트·서버 간 표준 프로토콜이다. 같은 서버 코드를 Claude·ChatGPT·Cursor·VS Code가 동시에 호출할 수 있다는 점이 결정적인 차이다.
Q4. 한국어 docstring을 써도 LLM이 잘 호출하나요?
네, 잘 호출한다. 다만 도구가 많아질수록 한국어와 영어를 섞지 말고 한 언어로 통일하는 것이 호출 정확도에 유리하다. 사내 사용자가 모두 한국어라면 docstring도 한국어로 통일한다.
결론 — 누가 무엇을 골라야 하는가
Python을 쓸 줄 안다면 30분 안에 첫 MCP 서버를 띄울 수 있고, 같은 코드가 Claude·ChatGPT·Cursor·VS Code에서 동시에 동작한다. 상황별 권장 경로는 다음과 같다.
- 개인 개발자 — 공식
mcpSDK + stdio + Claude Desktop. 인증·배포 부담이 없다. - 사내 백엔드 엔지니어 — 공식
mcpSDK + Streamable HTTP + Docker + Caddy. 안정성 최우선. - ML 플랫폼 팀 —
fastmcp3.x + Streamable HTTP + 미들웨어 인증. 신기능 추적이 빠르다. - RAG 담당 데이터 엔지니어 — Resource 중심 설계. 검색 결과는 Tool, 정적 문서는 Resource로 분리한다.
다음 단계로는 도구 호출 로그 수집과 권한 분리, 여러 MCP 서버를 한 게이트웨이 뒤에 묶는 라우팅을 살펴볼 수 있다.