개발 실전 2026-06-16

MCP Server
처음부터 구축

백엔드·플랫폼 엔지니어가 「AI가 사내 API를 호출하게 해 달라」는 요청을 받았는데 curl 스크립트만 있고 재사용 가능한 통합층이 없다면, 이 글이 대상입니다. Python과 FastMCP로 환경 구성부터 Tools / Resources / Prompts 전 모듈, Function Calling 대비 결정표, ChromaDB 벡터 지식베이스, Mac 격리 개발 5단계까지 따라 할 수 있습니다. 대조표·복붙 가능 코드·흔한 오류 표를 포함해 프로덕션 투입 전 판단 근거를 제공합니다.

2026 FastMCP로 MCP Server를 처음부터 구축하는 AI 도구 호출 아키텍처 실습

01 · 서론: MCP란 무엇인가

2026년 Agent는 코드·다단계 추론에 강하지만 외부 도구 없이는 폐쇄 시스템입니다. Git 최신 PR 상태를 모르고, SELECT * FROM orders WHERE status='pending'을 실행하지 못하며, Slack @멘션도 불가합니다. 기존에는 Host마다 Function Calling을 따로 구현하고 SaaS마다 Claude·GPT·Gemini용 어댑터를 작성해 N×M 통합 비용이 폭발했습니다.

MCP(Model Context Protocol)는 Anthropic이 2024년 11월 오픈소스한 규격으로, 「대규모 모델과 외부 세계를 잇는 USB-C」에 비유됩니다. 규격 준수 Server 하나로 Cursor, Claude Desktop, OpenClaw 등 여러 Host가 로드합니다. MCP가 AI 시대 HTTP가 되는 이유를 읽었다면 본문은 핸즈온판입니다. pip install mcp부터 Docker 상용까지 그대로 따라 할 수 있습니다.

구성: 3대 페인JSON-RPC 생명주기비교표Hello World → Tools → Resources → PromptsHTTP+SSEChromaDBMac 격리 검수.

02 · 개발 3대 페인포인트

한국 스타트업·SI·대기업 IT 팀에서 MCP 도입 전에 가장 자주 듣는 불만은 「Cursor에서는 되는데 Copilot에서는 또 설정해야 한다」는 것입니다. Host가 바뀔 때마다 통합 코드가 fork되고, 보안팀은 OAuth 범위·감사 로그·데이터 분류를 Host마다 다시 검토해야 합니다. MCP는 이런 반복 비용을 구조적으로 줄이도록 설계되었습니다.

1. Host마다 다른 도구 방언. OpenAI tools, Anthropic tool_use, Google Function Declaration——Schema·오류 형식이 제각각입니다. 「주문 조회」를 3 Host에 올리면 래퍼 3벌이 필요합니다. MCP는 JSON-RPC로 등록·설명·호출을 통일해 Write Once, Run Everywhere를 실현합니다.

2. 로컬 자격증명·권한 경계 모호. MCP Server는 파일시스템, 사내 API, OAuth Token에 접근합니다. 메인 Mac에 Server·IDE를 혼재하면 프로덕션 Key가 테스트 cron에 섞입니다. TCC(손쉬운 사용 권한) 승인을 잘못 내리면 되돌리기 어렵습니다. 버릴 수 있는 샌드박스에서 먼저 검수해야 합니다.

3. 디버그 체인이 깁니다. Host → Client → STDIO/HTTP 어디 하나만 잘못돼도 「도구 안 보임」「Connection closed」로 보입니다. stderr가 stdout을 오염시키면 JSON-RPC 파싱이 깨집니다. Inspector·단위 테스트 없이는 추측 디버깅이 됩니다.

03 · 아키텍처와 진화

Function Calling에서 MCP까지 3단계

1단계(2023): Function Calling. GPT-4 도구 호출 등장. JSON으로 함수·인자 반환. Schema가 Prompt/SDK에 묻혀 Host 간 재사용 불가.

2단계(2024 초): Plugins/Actions. ChatGPT Plugins 등이 HTTP를 도구화. 문턱은 낮았으나 Host 사유이고 런타임 동적 발견 불가.

3단계(2024.11~): MCP. 오픈 규격·SDK. Host/Client/Server 분리. 18개월에 10,000+ Server. 2026년 OpenAI·Google·Microsoft 본격 추종.

Client-Server와 3대 역량

┌─────────────────────────────────────────────────────────────┐
│  Host(Cursor / Claude Desktop / OpenClaw)                  │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │ MCP Client  │  │ MCP Client  │  │ MCP Client  │          │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘          │
└─────────┼────────────────┼────────────────┼─────────────────┘
          │ JSON-RPC       │ JSON-RPC       │ JSON-RPC
          ▼                ▼                ▼
   ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
   │ MCP Server A │ │ MCP Server B │ │ MCP Server C │
   │ Tools        │ │ Resources    │ │ Prompts      │
   └──────────────┘ └──────────────┘ └──────────────┘
  • Tools: 모델이 능동 호출하는 함수(read_file, query_database 등). JSON Schema 입력.
  • Resources: 모델이 수동 읽기하는 컨텍스트(설정, 로그, schema). URI 식별.
  • Prompts: 코드 리뷰 등 다턴 대화 템플릿. Host 원클릭 주입.

JSON-RPC 2.0과 전송

모든 메시지는 JSON-RPC 2.0. initialize, tools/list, tools/call, resources/read, prompts/get 등이 기본입니다.

// 생명주기: initialize → initialized → 업무 → 종료

{ "jsonrpc": "2.0", "id": 1, "method": "initialize",
  "params": { "protocolVersion": "2024-11-05", "clientInfo": { "name": "cursor" } } }

{ "jsonrpc": "2.0", "id": 2, "method": "tools/call",
  "params": { "name": "say_hello", "arguments": { "name": "MacDate" } } }

전송은 STDIO(자식 프로세스, 로컬 개발)와 HTTP+SSE(원격·멀티테넌트). 2026 규격의 Streamable HTTP가 양방향 스트림을 단순화합니다.

04 · MCP vs OpenAI FC vs LangChain

관점OpenAI FCLangChain ToolsMCP
위치단일 Host 내장Python 프레임워크크로스 Host 오픈 규격
발견정적 Schema코드 등록tools/list 동적
Host 공유OpenAI만어댑터 재작성1구현·다Host
Resources/Prompts미지원Retriever 등 모방1급 시민
전송API 내장프로세스 내STDIO/HTTP+SSE/Streamable HTTP
규모(2026 중)사유PyPI 수천10,000+ Server
적합OpenAI 단독 PoC자체 Agent다Host·Enterprise Catalog

수치: MCP 통합층 도입 팀은 통합 비용 38%–55% 절감 보고. 동일 Server를 Cursor·Claude Desktop에 올릴 때 중복 공수 ~70% 감. 공인 스캔 미인증 노출 Server 1,000+——격리 환경 권한 검증 필수.

05 · 개발 환경 구성

Python vs TypeScript

공식 SDK: Python(mcp), TypeScript(@modelcontextprotocol/sdk). Python FastMCP 데코레이터가 간결해 데이터·AI 스크립트에 적합. 본문은 Python 중심, 개념은 TS로 이식 가능.

venv와 디렉터리

mkdir my-mcp-server && cd my-mcp-server
python3 -m venv .venv
source .venv/bin/activate
pip install "mcp[cli]" pydantic httpx chromadb
my-mcp-server/
├── server.py
├── tools/
├── resources/
├── prompts/
├── tests/
└── Dockerfile

MCP Inspector와 Host 설정

npx @modelcontextprotocol/inspector python server.py

Cursor~/.cursor/mcp.json, Claude Desktop은 macOS에서 ~/Library/Application Support/Claude/claude_desktop_config.json에 Server를 등록합니다.

06 · Hello World: 첫 Server

# server.py
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("hello-server")

@mcp.tool()
def say_hello(name: str = "World") -> str:
    """지정 이름에 인사."""
    return f"Hello, {name}! MCP Server is running."

if __name__ == "__main__":
    mcp.run()

Inspector에서 ConnectList Toolssay_hello{"name": "MacDate"}를 넣어 인사가 반환되는지 확인하세요.

Cursor 설정 예

// ~/.cursor/mcp.json
{ "mcpServers": { "hello-server": {
  "command": "/path/to/.venv/bin/python",
  "args": ["/path/to/server.py"]
} } }

07 · Tools: 5가지 구현

Pydantic 입력 검증

from pydantic import BaseModel, Field

class CalcInput(BaseModel):
    expression: str = Field(description="식, 예 2+3*4")

@mcp.tool()
def calculator(input: CalcInput) -> str:
    import re
    if not re.match(r'^[\d\s+\-*/().]+$', input.expression):
        raise ValueError("잘못된 문자")
    return str(eval(input.expression))
도구용도핵심
calculator안전 사칙연산정규식 화이트리스트
read_file워크스페이스 읽기경로 정규화·루트 제한
http_getHTTP 프록시httpx 비동기·타임아웃
query_db읽기 전용 SQL파라미터화 쿼리
current_time타임존 시각zoneinfo + ISO 8601
from pathlib import Path

WORKSPACE = Path("/safe/workspace").resolve()

@mcp.tool()
def read_file(path: str) -> str:
    target = (WORKSPACE / path).resolve()
    if not str(target).startswith(str(WORKSPACE)):
        raise ValueError("경로 이탈")
    return target.read_text(encoding="utf-8")
@mcp.tool()
async def http_get(url: str) -> str:
    import httpx
    async with httpx.AsyncClient(timeout=5.0) as c:
        resp = await c.get(url)
        return resp.text[:8000]

오류는 모델이 설명할 수 있는 읽기 쉬운 문자열로 반환하세요(파라미터 검증 실패 제외).

08 · Resources: 읽기 전용 컨텍스트

Tool은 부작용 있는 능동 동작. Resource는 설정·schema 등 읽기 전용 컨텍스트. 대화 시작 시 Host가 선행 로드하면 Token을 절약합니다.

@mcp.resource("config://app/settings")
def get_settings() -> str:
    import json
    return json.dumps({"env": "production"})

@mcp.resource("schema://db/{table_name}")
def get_table_schema(table_name: str) -> str:
    return f"CREATE TABLE {table_name} (...);"

09 · Prompts: 재사용 템플릿

Prompts는 Host가 원클릭으로 다턴 구조를 주입합니다. Cursor Agent Skill이 「언제 무엇을」 orchestrate한다면, MCP Prompt는 대화 골격을 제공합니다.

@mcp.prompt()
def code_review_prompt(language: str = "Python") -> str:
    return f"""당신은 {language} 시니어 리뷰어입니다.
1. 보안 2. 성능 3. 가독성 4. 테스트 제안
각 항목에 줄 번호와 수정안을 한국어로 출력."""

10 · HTTP 전송과 보안

관점STDIOHTTP+SSEStreamable HTTP
배치로컬 자식 프로세스원격 서버단일 엔드포인트 양방향
공유Host별 독립다중 Client 공유동일
인증실행자 책임Bearer/mTLS/OAuth동일
용도데스크톱 Host사내 SaaS 게이트웨이신규 배포 권장
mcp run server.py --transport streamable-http --port 8080

공인 노출 시 Bearer Token 또는 OAuth 2.1 필수. 도메인 화이트리스트·경로 샌드박스·SQL 읽기 전용을 도구층에서 적용. tools/call 인자를 감사 로그에 기록하세요.

11 · 디버깅·테스트·오류

MacDate가 지원하는 팀에서는 MCP Inspector를 「Postman for AI tools」처럼 씁니다. Host를 거치지 않고 Server만 단독 검증하면, 문제가 Server 쪽인지 Host 설정 쪽인지 5분 안에 갈릴 때가 많습니다. CI에는 pytest로 핵심 Tool의 happy path와 injection 거부 케이스를 넣어 두세요.

  1. Connect: initialize 성공 확인.
  2. List: Schema 기대치 대조.
  3. Call Tool: 수동 파라미터로 응답 확인.
  4. Export Log: JSON-RPC transcript 팀 공유.
  5. pytest: CI에 tools/call 포함.
def test_calculator_basic():
    result = calculator(CalcInput(expression="2+3*4"))
    assert result == "14"
증상원인조치
도구 미표시경로 오류·venv 미사용mcp.json 절대경로·Inspector 선행
Connection closed시작 크래시단독 python server.py
타임아웃동기 블로킹 IOasync + timeout
HTTP 401Token 만료Authorization 헤더
Schema 실패Pydantic 불일치tools/list inputSchema

12 · 프로덕션 배포

PoC는 Railway·Render로 빠르게 올리고, 사내 Catalog에 편입할 Server는 Cloud Run 또는 VPC 내부 mTLS 게이트웨이 뒤에 두는 패턴이 2026년 한국 팀에서 흔합니다. 컨테이너 이미지는 slim 베이스 + 멀티스테이지 빌드로 cold start를 줄이고, HEALTHCHECKinitialize 응답을 주기적으로 확인하세요.

FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir .
EXPOSE 8080
CMD ["mcp", "run", "server.py", "--transport", "streamable-http", "--port", "8080"]
  • Railway / Render: MVP·PoC 종량제.
  • Cloud Run: SSE 장연결에 비교적 유리.
  • VPS: mTLS 사내망, 모니터링 자체 구축.

serverInfo.version SemVer. Prometheus 등으로 tools/call P99 기록. 카나리로 신구 Server 병행 후 전환.

13 · 지식베이스: ChromaDB

기업 Agent에서 가장 흔한 MCP 용도는 벡터 지식베이스입니다. Confluence·Notion·PDF 매뉴얼을 청크 단위로 embedding하면, 모델이 「사내 VPN 설정 방법」 같은 질문에 hallucination 없이 답할 확률이 올라갑니다. 인덱싱 Tool과 검색 Tool을 분리하면 권한 모델을 단순화할 수 있습니다.

RAG 파이프라인에서는 문서 전처리(헤더 제거, 표 Markdown화) 품질이 embedding 모델 선택만큼 중요합니다. 한국어 문서는 sentence-transformers 다국어 모델 또는 OpenAI embedding을 A/B 테스트해 MRR@5를 기록해 두세요.

import chromadb
client = chromadb.PersistentClient(path="./chroma_data")
collection = client.get_or_create_collection("docs")

@mcp.tool()
def index_document(doc_id: str, text: str) -> str:
    collection.upsert(ids=[doc_id], documents=[text])
    return f"indexed: {doc_id}"

@mcp.tool()
def search_knowledge(query: str, top_k: int = 5) -> str:
    results = collection.query(query_texts=[query], n_results=top_k)
    return "\n---\n".join(results["documents"][0] or [])

Embedding: OpenAI text-embedding-3-small(1536차원) 또는 로컬 sentence-transformers. ChromaDB 기본 all-MiniLM-L6-v2(384차원). 512 token 청크 일반적. 10만 페이지 인덱스 시 디스크 2–4 GB·메모리 8 GB 목표. 프로덕션 Qdrant 클러스터, PoC ChromaDB 단일 노드.

14 · 생태계와 학습 로드맵

  • @modelcontextprotocol/server-filesystem — 파일 Resource
  • @modelcontextprotocol/server-postgres — 읽기 SQL
  • @modelcontextprotocol/server-slack — Slack
  • @modelcontextprotocol/server-github — Issue/PR
  • mcp-server-fetch — HTTP 수집

2026 트렌드: Streamable HTTP 기본화. OAuth 2.1 디바이스 플로. Enterprise Catalog·Server 서명. MCP·A2A 공존.

  1. MCP 프로토콜 해설로 3계층 이해.
  2. Hello World → Tools 5종 Inspector 검수.
  3. Cursor 연결로 실무 시나리오.
  4. ChromaDB Server 검색 정확도 비교.
  5. Railway + Bearer로 HTTP 배포.
  6. 격리 Mac Catalog 리허설 → ADR → 상용.

15 · 마무리: 격리 Mac에서 익힌 뒤 상용

WSL·Linux 컨테이너에서도 MCP Server 개발은 가능하지만, 메인 Mac에 OAuth·프로덕션 API Key·다중 Host 설정을 혼재하면 백그라운드 cron의 tools/call이 사내 API를 치는 사고가 납니다. 공인 1,000+ 미인증 Server——프로덕션 자격증명 오염 전 격리 환경에서 화이트리스트 후보를 검증하는 것이 건전한 엔지니어링입니다.

MCP는 Write Once를 실현하지만 개발 경험도 macOS 네이티브가 유리합니다. Cursor/Claude Desktop 설정 경로, STDIO 자식 프로세스, Keychain은 Apple 생태계와 일체입니다. 감사 가능한 「다 Server × 다 Host」 실측이 필요하면 독립 macOS 임대 노드에서 1–3일 리허설 후 Enterprise Catalog로 가는 편이 일상 Mac에 Server를 쌓는 것보다 안전하고, 맨 컨테이너보다 Host 동작에 가깝습니다.

Mac 격리 MCP 개발 5단계

  1. 격리 macOS 임대: Mac mini M4부터. SSH. Apple ID/OAuth 메인과 분리. M 시리즈 요금.
  2. 개발 환경: Python 3.12, Node(Inspector), Cursor. 독립 venv.
  3. 다중 Server 병행: Hello World, Tools 5종, ChromaDB. Inspector tools/list 스냅샷.
  4. Host 연동: STDIO 등록, 고정 태스크로 지연·권한 초과 기록.
  5. ADR·해제: Server 화이트리스트·OAuth 스코프 ADR. 테스트 Key 폐기·임대 종료.