MCP Server 처음부터 개발하기: AI 도구 호출 완벽 가이드
대규모 언어 모델이 아무리 똑똑해도 데이터베이스 조회, API 호출, 파일 읽기·쓰기는 직접 할 수 없습니다. AI 도구 호출 능력이 Agent가 현실 세계에 닿을 수 있는지를 결정합니다. MCP(Model Context Protocol) 는 Anthropic이 오픈소스로 공개한 표준 프로토콜로, Claude·Cursor 등 클라이언트가 여러분이 작성한 Server를 통일된 방식으로 발견하고 호출할 수 있게 합니다. 본문은 Python 또는 TypeScript 기초를 갖춘 백엔드/AI 개발자를 대상으로, 프로토콜 원리, 환경 구축, Tools/Resources/Prompts 3대 기능, 원격 HTTP 배포, 디버깅·테스트부터 프로덕션 배포까지 전 과정을 처음부터 안내합니다.
읽고 나면 다음 세 가지에 답할 수 있습니다. ① MCP와 Function Calling, LangChain Tools의 본질적 차이 ② 공식 SDK로 도구, 리소스, 프롬프트 템플릿을 등록하는 방법 ③ 개인 지식 베이스를 프로덕션급 MCP Server로 캡슐화하고 Cursor에서 「지난주 MCP 관련 메모가 뭐였지?」라고 직접 질문하는 방법.
01 MCP란? 프로토콜 원리, 통신 메커니즘과 방안 비교
도구 호출 능력은 3세대 진화를 거쳤습니다. Function Calling(벤더 전용 포맷) → Plugins(플랫폼 종속) → MCP(개방 프로토콜 표준). Anthropic이 MCP를 설계한 핵심 동기는 JSON-RPC 규격으로 「AI 클라이언트가 외부 능력을 어떻게 발견·기술·호출하는가」를 통일하고, N개 모델 × M개 도구의 맞춤 통합 악몽을 끝내는 것입니다.
- 페인 포인트: 모델은 외부 도구와 실시간 데이터 접근 능력이 부족해 DB 조회, API 호출, 파일 조작을 할 수 없습니다.
- 시나리오: Claude/GPT가 데이터베이스를 조회하고 REST API를 호출하며 로컬 Markdown을 읽고 쓰게 하고 싶다면, 그것이 바로 MCP Server가 노출해야 할 능력입니다.
- 가치 약속: 본문을 읽으면 프로덕션급 MCP Server를 독립적으로 개발·배포할 수 있습니다.
아키텍처상 MCP Client(Claude Desktop, Cursor 등)와 MCP Server(여러분이 개발하는 부분)가 JSON-RPC로 양방향 통신하고, Server가 외부 시스템과 연결합니다.
- Tools: AI가 호출할 수 있는 함수(검색, 계산, DB 쿼리)
- Resources: AI가 읽을 수 있는 리소스(파일, URL, 데이터 스트림)
- Prompts: 매개변수 주입을 지원하는 사전 정의 프롬프트 템플릿
통신은 JSON-RPC 2.0 기반이며, 전송 방식은 두 가지입니다. stdio(로컬 자식 프로세스, 지연 매우 낮음)와 HTTP + SSE / Streamable HTTP(원격 서비스, 다중 클라이언트 지원). 수명 주기는 초기화 핸드셰이크 → 기능 협상 → 요청/응답 → 종료입니다.
| 비교 축 | MCP | OpenAI Function Calling | LangChain Tools |
|---|---|---|---|
| 표준화 수준 | 개방 프로토콜 표준 | 벤더 전용 | 프레임워크 종속 |
| 전송 방식 | stdio / HTTP | HTTP | HTTP |
| 크로스 모델 지원 | 예 | 아니오 | 일부 |
| 리소스 / 프롬프트 | 네이티브 지원 | 미지원 | 미지원 |
| 생태계 | 급성장(10,000+ Server) | 성숙 | 성숙 |
관련 글: MCP가 AI 시대 HTTP 프로토콜이 되는 이유. 공식 규격은 modelcontextprotocol.io를 참고하세요.
02 개발 환경 준비: 언어 선택, 의존성 설치와 프로젝트 구조
Python(초보자 권장): 공식 SDK mcp, FastMCP 데코레이터로 간결하게 시작할 수 있습니다. TypeScript(프론트엔드/풀스택 권장): 공식 SDK @modelcontextprotocol/sdk. 본문은 Python을 중심으로, TypeScript는 대조 설명합니다.
# Python 환경
python -m venv .venv
source .venv/bin/activate
pip install mcp
# TypeScript 환경(대조)
npm init -y
npm install @modelcontextprotocol/sdk
권장 프로젝트 구조:
my-mcp-server/
├── server.py # 메인 서비스 진입점
├── tools/
│ ├── __init__.py
│ ├── calculator.py
│ └── web_search.py
├── resources/
│ └── file_reader.py
├── prompts/
│ └── templates.py
├── tests/
│ └── test_tools.py
├── pyproject.toml
└── README.md
디버깅 도구 3종:
- MCP Inspector: 공식 디버그 UI, Tools/Resources/Prompts 시각화 테스트
- Claude Desktop:
claude_desktop_config.json편집으로 로컬 연동 - Cursor MCP 설정: Settings → MCP → stdio 명령줄 시작 항목 추가
03 Hello World: 가장 간단한 MCP Server와 Cursor 연결
FastMCP로 10줄 코드만으로 첫 Server를 실행할 수 있습니다.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-first-server")
@mcp.tool()
def say_hello(name: str) -> str:
"""지정한 사람에게 인사한다"""
return f"Hello, {name}! 이것이 첫 MCP 도구입니다."
if __name__ == "__main__":
mcp.run()
실행과 검증:
python server.py
# 또는 MCP Inspector로 디버깅
npx @modelcontextprotocol/inspector python server.py
Cursor 연결 6단계:
- Python 경로 확인: 가상 환경에서
which python으로 절대 경로를 기록합니다. - Cursor MCP 설정 열기: Settings → Features → MCP Servers.
- stdio Server 추가: command에 Python 경로, args에
server.py절대 경로. - Cursor 재시작: MCP 설정을 반영합니다.
- 도구 목록 확인: Agent 모드에서
say_hello가 표시되는지 확인합니다. - 호출 트리거: 대화에서 AI에게 「say_hello로 JEXCLOUD에 인사해」라고 요청해 올바른 응답을 확인합니다.
Claude Desktop도 동일합니다. ~/Library/Application Support/Claude/claude_desktop_config.json을 편집해 mcpServers 노드에 동일 설정을 등록합니다.
04 Tools 개발: 매개변수 타입, 5대 실전 도구와 비동기 모드
도구의 기본 계약: 함수 시그니처가 곧 문서입니다. 매개변수 타입, 반환 타입, docstring이 MCP에 의해 JSON Schema로 변환되어 AI가 이해합니다. 이름은 snake_case, 오류는 예외를 그대로 던지기보다 구조화된 정보를 우선 반환합니다.
복잡한 매개변수는 Pydantic으로 모델링합니다.
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
query: str = Field(description="검색 키워드")
max_results: int = Field(default=5, description="최대 반환 결과 수")
language: str = Field(default="ko", description="결과 언어")
@mcp.tool()
def web_search(input: SearchInput) -> list[dict]:
"""웹 검색을 실행하고 관련 결과 목록을 반환한다"""
...
5대 실용 도구를 연습 목록으로 권장합니다.
- 계산기: 수학 표현식 안전 평가(
ast.literal_eval로 인젝션 방지) - 파일 읽기·쓰기: 화이트리스트 디렉터리 내 read/write로 제한
- HTTP 요청: GET/POST 캡슐화, 타임아웃·재시도 통일
- 데이터베이스 쿼리: 읽기 전용 SQL + 매개변수화로 인젝션 방지
- 시간 도구: 현재 시각, 시간대 변환, ISO 8601 포맷
IO 집약형 도구는 비동기로 처리합니다.
import httpx
@mcp.tool()
async def fetch_url(url: str) -> str:
"""지정 URL의 콘텐츠를 가져온다"""
async with httpx.AsyncClient() as client:
response = await client.get(url, timeout=30.0)
return response.text
오류 처리 모범 사례: 타임아웃 설정, 권한 검증(경로 화이트리스트/API Key), {"error": "...", "code": "..."} 구조체 반환으로 AI 자기 수정을 돕습니다.
05 Resources: URI 주소 지정, 정적·동적 리소스, 파일 시스템 실전
Resource와 Tool의 차이: Resource는 데이터 제공자(읽기 전용), Tool은 동작 실행자(쓰기 가능, 부작용 있음). 주소 지정은 URI 스킴: file://, http://, custom://.
# 정적 리소스
@mcp.resource("config://app-settings")
def get_app_settings() -> str:
return json.dumps({"version": "1.0", "env": "production"})
# 동적 리소스(매개변수 포함)
@mcp.resource("user://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
user = db.query_user(user_id)
return json.dumps(user)
리소스 타입 범위:
- 텍스트:
text/plain,application/json - 바이너리: 이미지, PDF(Base64 또는 blob URI)
- 스트리밍: 실시간 로그, 시세 푸시(리소스 구독)
파일 시스템 리소스 서버 실전: 디렉터리 나열 → 경로로 파일 읽기 → 선택적으로 watchfiles로 변경 감지 및 리소스 업데이트 알림 푸시.
06 Prompts: 재사용 가능한 프롬프트 템플릿과 다턴 대화 시나리오
MCP Prompt는 사전 정의된 프롬프트 조각으로, AI 클라이언트가 직접 재사용할 수 있으며 동적 매개변수 주입을 지원해 팀 프롬프트의 일관성과 유지보수성을 높입니다.
from mcp.types import PromptMessage, TextContent
@mcp.prompt()
def code_review_prompt(language: str, code: str) -> list[PromptMessage]:
"""코드 리뷰 프롬프트 템플릿"""
return [
PromptMessage(
role="user",
content=TextContent(
type="text",
text=f"다음 {language} 코드를 리뷰해 주세요..."
)
)
]
다턴 대화 템플릿은 user와 assistant 역할을 혼합할 수 있습니다. 전형적 시나리오: 면접 시뮬레이션(assistant가 먼저 질문, user가 답변), 코드 디버깅 어시스턴트(assistant가 트러블슈팅 단계를 안내).
07 HTTP 전송 모드: 원격 MCP Server와 보안 강화
| 특성 | stdio | HTTP + SSE |
|---|---|---|
| 배포 방식 | 로컬 프로세스 | 원격 서버 |
| 지연 | 매우 낮음 | 네트워크 의존 |
| 다중 클라이언트 | 미지원 | 지원 |
| 적용 시나리오 | 로컬 도구 | SaaS / 팀 공유 |
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("remote-server", transport="streamable-http")
if __name__ == "__main__":
mcp.run(host="0.0.0.0", port=8000)
프로덕션 환경에는 다음을 추가합니다. Bearer Token 인증, API Key 미들웨어, CORS 화이트리스트, 요청 빈도 제한(slowapi 등). 원격 Server는 팀 공유 DB 쿼리, 내부 API 게이트웨이 등에 적합합니다.
08 디버깅과 테스트: MCP Inspector, 단위 테스트와 흔한 오류
MCP Inspector 워크플로: Inspector 시작 → stdio 명령 연결 → UI에서 tools/call 테스트 → JSON-RPC 요청/응답 로그 확인 → 타임아웃·권한 거부 시나리오 시뮬레이션.
import pytest
from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client
@pytest.mark.asyncio
async def test_calculator_tool():
server_params = StdioServerParameters(command="python", args=["server.py"])
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("calculate", {"expression": "2 + 2"})
assert result.content[0].text == "4"
| 오류 | 원인 | 해결책 |
|---|---|---|
| 도구가 AI에 표시되지 않음 | 설정 경로 오류 | config.json의 command/args 절대 경로 확인 |
| JSON 직렬화 실패 | 반환 타입 미지원 | 문자열 또는 dict로 변환 |
| 타임아웃 연결 끊김 | 도구 실행이 느림 | 비동기화 + 타임아웃 제어 |
| 권한 거부 | 파일 경로 제한 | 접근 허용 디렉터리 화이트리스트 설정 |
09 프로덕션 배포: Docker, 클라우드 서비스와 가시성
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "server.py"]
배포 선택:
- Railway / Render: 원클릭 배포, 개인 프로젝트에 적합
- AWS Lambda / Google Cloud Run: Serverless, 호출당 과금
- 자체 VPS: Nginx 리버스 프록시 + TLS, Bearer Token과 함께
가시성 3종: 구조화된 요청 로그, Prometheus 도구 호출 지표, Sentry 오류 알림. /health 헬스 체크 노출. 버전 관리 시 MCP 프로토콜 버전을 선언하고, 도구 업그레이드는 하위 호환을 유지하며, 기능 협상으로 클라이언트 크래시를 방지합니다.
- MCP Python SDK: github.com/modelcontextprotocol/python-sdk
- MCP TypeScript SDK: github.com/modelcontextprotocol/typescript-sdk
- MCP Inspector: github.com/modelcontextprotocol/inspector
10 실전 프로젝트: 개인 지식 베이스 MCP Server 구축
요구사항: AI가 로컬 Markdown 메모 검색, 시맨틱 검색, 메모 생성·업데이트를 할 수 있게 합니다.
기술 선택:
- 벡터 DB: ChromaDB 또는 Qdrant(로컬 경량)
- 임베딩 모델:
text-embedding-3-small(OpenAI) 또는 로컬nomic-embed-text - 파일 감시:
watchfiles로 인덱스 증분 재구축
핵심 모듈:
index_notes도구: 메모 디렉터리 스캔, 청크 분할 후 벡터 DB에 기록semantic_search도구: query → top-k 관련 조각write_note도구: Markdown 파일 생성/추가notes://{path}리소스: URI로 단일 메모 전문 읽기
데모 효과: Cursor에서 「지난주 MCP 관련해서 뭐 기록했지?」라고 질문 → AI가 semantic_search 호출 → 관련 조각 반환 후 종합 답변. 이것이 사적 지식을 Agent 워크플로에 연결하는 최단 경로입니다.
11 MCP 생태계 전망, 학습 경로와 프로덕션 호스트 선택
추천 커뮤니티 Server:
mcp-server-filesystem: 파일 시스템 조작mcp-server-github: GitHub 저장소 조작mcp-server-brave-search: 웹 검색mcp-server-postgres: 데이터베이스 쿼리mcp-server-slack: Slack 메시지
2026 생태계 트렌드: Cursor, Claude Desktop, VS Code, OpenAI, Google Gemini가 이미 MCP를 네이티브 또는 계획으로 지원합니다. MCP Marketplace가 Server 배포를 가속합니다. 엔터프라이즈 보안 표준(OAuth 2.1, 감사 로그)이 로드맵에 포함됩니다.
다음 학습 경로: MCP 프로토콜 규격 정독 → 첫 공개 Server 배포 → MCP + Agent 오케스트레이션 탐색 → 오픈소스 생태계 PR 기여.
- 프로토콜 버전: 2024-11-05 최초 출시, 2025년부터 Streamable HTTP가 순수 SSE를 대체해 원격 전송 권장 방식
- 생태계 규모: 2026년 기준 커뮤니티 MCP Server 10,000개 초과
- SDK 유지: Anthropic 오픈소스 + Linux Foundation AAIF 거버넌스, Python/TypeScript 공식 SDK 주간 업데이트
MCP는 AI 도구화의 표준 프로토콜입니다. Server 개발을 마스터하면 임의 LLM이 여러분의 비즈니스 시스템을 호출하게 하는 능력을 갖게 됩니다. MCP로 어떤 도구를 캡슐화할 계획인가요? 댓글로 시나리오를 공유해 주세요.
프로덕션급 MCP Server의 숨은 비용은 호스트 안정성에 있습니다. 노트북 덮개를 닫으면 STDIO 자식 프로세스가 즉시 종료되고, 가정용 대역폭 변동이 HTTP 장시간 연결을 끊으며, 공유 VPS에는 macOS 샌드박스와 TCC 권한이 없습니다. 7×24 지식 베이스 인덱싱, 원격 HTTP MCP, Cursor Agent CI 연동이 필요하다면 JEXCLOUD 멀티 리전 베어메탈 Mac이 전용 Apple Silicon, 고정 공인 IP, 120초 배포, 월 단위 탄력 임대를 제공합니다. 「로컬로 버티기 + 잦은 재연결」보다 프로덕션 Agent 워크플로에 더 적합합니다. 노드와 가격은 JEXCLOUD 요금 페이지, 배포 문의는 고객센터를 참고하세요.