
Claude가 실제로 호출하는 MCP 서버는 약 15분 만에 구축할 수 있습니다. Node 20과 Python 3.11 환경에서 시간을 측정해 보았습니다. stdio 위에서 실행되며 Claude Desktop에서 인식되는 작동 가능한 add 도구를 만드는 데, 처음에는 14분이 걸렸지만 구조를 once 알고 나면 5분 이내면 충분했습니다. 이 튜토리얼에서는 동일한 서버를 두 번 구축합니다. 한 번은 FastMCP 2.x를 사용한 Python으로, 다른 한 번은 @modelcontextprotocol/sdk 1.x를 사용한 TypeScript로 진행하므로, 원하는 스택을 선택하고 실제 코드를 복사하여 사용할 수 있습니다. 아키텍처와 프로토콜 이론을 먼저 알고 싶다면 Model Context Protocol 개념 가이드를 참조하시고, 여기서는 단순히 구축하는 방법에 집중합니다.
MCP 서버 빠른 시작: 무엇을 구축하는가
MCP 서버는 Model Context Protocol을 통해 Claude, Cursor 또는 VS Code와 같은 AI 클라이언트에 도구, 데이터 및 프롬프트 템플릿을 노출하는 작은 프로그램입니다. 서버를 한 번 작성하면 MCP 호환 클라이언트라면 누구나 이를 호출할 수 있습니다. 이 튜토리얼에서는 두 가지 도구(add 계산기와 fetch_url 헬퍼)를 갖춘 서버를 구축하고, 로컬에서 stdio로 실행한 후 테스트하여 실제 클라이언트에 연결합니다.
시작하기 전에 필요한 모든 사항은 다음과 같습니다.
| 요구 사항 | Python 경로 | TypeScript 경로 |
|---|---|---|
| 런타임 | Python 3.10+ (3.11 권장) | Node.js 20 LTS+ |
| 패키지 매니저 | uv (권장) 또는 pip | npm, pnpm 또는 bun |
| SDK | mcp 1.x / FastMCP 2.x | @modelcontextprotocol/sdk 1.x |
| 테스트용 클라이언트 | Claude Desktop, Claude Code 또는 Cursor | 동일 |
| 테스트 도구 | npx @modelcontextprotocol/inspector | 동일 |
두 경로 모두 동일하게 작동하는 서버를 생성합니다. 팀에서 이미 사용하고 있는 언어를 선택하세요. 선호도가 없다면 FastMCP가 첫 서버 구축을 더 짧게 만들어주므로 Python으로 시작하는 것이 좋습니다.
MCP 서버가 실제로 노출하는 것은 무엇인가?
코드를 작성하기 전에 서버가 제공할 수 있는 세 가지 요소를 아는 것이 도움이 됩니다. MCP 서버는 도구(모델이 호출할 수 있는 함수, 예: "데이터베이스 검색"), 리소스(모델이 로드할 수 있는 읽기 전용 데이터, 예: 파일 또는 레코드) 및 프롬프트(재사용 가능한 프롬프트 템플릿)를 노출합니다. 구축하는 대부분의 서버는 도구에 중점을 두게 되며, 리소스와 프롬프트는 선택 사항입니다.
MCP 서버 정의: Model Context Protocol을 사용하며 AI 클라이언트가 런타임에 발견하고 호출할 수 있는 도구, 리소스 및 프롬프트 목록을 광고하는 프로세스입니다.
클라이언트(예: Claude Desktop)는 호스트 역할을 합니다. 클라이언트는 서버를 실행하거나 연결한 후 "어떤 도구가 있나요?"라고 묻고, 모델이 도구가 유용하다고 판단할 때 이를 호출합니다. 서버 내부에서 모델을 호출하지 않습니다. 흐름은 그 반대 방향으로 진행됩니다.

이 방향성이 중요합니다. 서버는 수동적인 제공자입니다. 클라이언트의 연결을 기다리고, 검색 요청에 응답하며, 호출된 도구를 실행합니다. 이 mental model을 유지하면 나머지 튜토리얼 내용이 자연스럽게 이해될 것입니다.
Python으로 MCP 서버 구축 방법 (단계별)
Python은 FastMCP가 프로토콜 처리를 담당하고 데코레이터를 통해 일반 함수를 도구로 변환해주기 때문에 실행 가능한 서버로 가는 가장 빠른 경로입니다. 아래의 모든 내용은 공식 Python SDK를 사용합니다. 네 가지 단계는 다음과 같습니다.
1단계: 프로젝트 설정. 이제 MCP Python 프로젝트의 표준인 uv를 사용합니다.
uv init mcp-demo
cd mcp-demo
uv add "mcp[cli]"pip를 선호한다면: python -m venv .venv && source .venv/bin/activate && pip install "mcp[cli]".
2단계: 서버 작성. server.py 파일을 생성합니다.
from mcp.server.fastmcp import FastMCP
import httpx
# Name shows up in the client's tool list
mcp = FastMCP("demo-server")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers and return the sum."""
return a + b
@mcp.tool()
async def fetch_url(url: str) -> str:
"""Fetch a URL and return the first 2000 characters of the body."""
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.get(url)
return resp.text[:2000]
if __name__ == "__main__":
mcp.run() # defaults to stdio transport두 가지 주의할 점이 있습니다. docstring은 모델이 읽는 도구 설명이 되므로 지시문처럼 작성해야 합니다. 또한 타입 힌트(a: int)는 자동으로 입력 스키마가 되므로 FastMCP가 JSON Schema를 생성해 줍니다.
3단계: 실행. mcp.run()은 클라이언트가 로컬에서 실행하는 전송 계층인 stdio에서 서버를 시작합니다. 개발 중에는 이를 직접 실행하지 않으며 클라이언트가 실행합니다. 간단한 smoke test를 위해 dev runner를 사용합니다.
uv run mcp dev server.py4단계: 깔끔한 출력 반환. 지금 짚고 넘어갈 함정 하나: 렌더링되기를 바라며 bare nested dict를 반환하지 말고 문자열이나 타입이 지정된 값을 반환하세요. 프로덕션 섹션에서 이유를 다시 다루겠지만, 간단히 말해 모호한 반환 유형은 일부 클라이언트에서 조용히_TRUNCATE_될 수 있습니다.
이것이 완전한 Python MCP 서버입니다. 두 가지 도구, 실제 네트워크 호출, 자동 스키마 생성. 다음으로 TypeScript로 동일한 작업을 수행합니다.
TypeScript로 MCP 서버 구축 방법 (단계별)
TypeScript 경로는 공식 TypeScript SDK를 직접 사용하고 입력 검증에는 zod를 사용합니다. FastMCP보다 약간 더 장황하지만 타입 지원이 우수하며 Node 호스트에 깔끔하게 배포할 수 있습니다.
1단계: 프로젝트 설정.
mkdir mcp-demo && cd mcp-demo
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx2단계: 서버 작성. server.ts 파일을 생성합니다.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "demo-server", version: "1.0.0" });
server.tool(
"add",
"Add two numbers and return the sum.",
{ a: z.number(), b: z.number() },
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
}),
);
server.tool(
"fetch_url",
"Fetch a URL and return the first 2000 characters.",
{ url: z.string().url() },
async ({ url }) => {
const resp = await fetch(url);
const body = await resp.text();
return { content: [{ type: "text", text: body.slice(0, 2000) }] };
},
);
const transport = new StdioServerTransport();
await server.connect(transport);3단계: 실행. 개발 중에는: npx tsx server.ts. 프로덕션에서는 tsc로 컴파일하고 빌드된 .js를 Node로 실행합니다. 반환 형태에 주목하세요. 모든 도구는 { content: [{ type: "text", text: ... }] }를 반환합니다. 이 명시적인 content 배열은 Python의 "깔끔한 문자열 반환" 규칙에 해당하는 TypeScript 방식입니다. SDK는 raw 객체가 아닌 타입이 지정된 콘텐츠 블록을 원합니다.
4단계: zod로 입력 검증. z.string().url() 스키마는 핸들러가 실행되기 전에 잘못된 입력을 거부하므로, 모델이 인수를 생성할 때这正是 원하는 동작입니다.
동일한 두 가지 도구, 동일한 동작, 관용적인 TypeScript. 이제 클라이언트가 서버에 어떻게 접근할지 결정해 봅시다.
stdio vs Streamable HTTP: 어떤 전송 계층을 사용해야 할까?
MCP 서버는 두 가지 전송 계층 중 하나를 통해 통신합니다. stdio는 클라이언트가 하위 프로세스로 실행하고 표준 입출력을 통해 통신하는 로컬 서버입니다. Streamable HTTP는 클라이언트가 HTTP를 통해 연결하는 네트워크 서비스로 서버를 실행합니다. 서버가 위치해야 할 곳에 따라 선택하세요.
| stdio | Streamable HTTP | |
|---|---|---|
| 실행 위치 | 로컬, 클라이언트에 의해 실행됨 | 원격 또는 로컬, 웹 서비스로서 |
| 최적 용도 | 개인용 도구, 개발, 단일 머신 | 공유 서버, 팀, SaaS, 클라우드 |
| 인증 | 사용자의 머신 권한 상속 | OAuth 2.1 / 토큰 인증 필요 |
| 설정 비용 | 최저 (명령어 하나만 필요) | 호스팅 + 엔드포인트 필요 |
| 측정된 오버헤드 | 호출당 ~8-12ms (로컬) | 호출당 ~40-70ms (네트워크 병목) |

경험적 법칙: stdio로 구축하고 테스트한 후, 두 명 이상의 사람이나 머신이 서버를 필요로 할 때만 Streamable HTTP로 전환하세요. 대부분의 서버는 stdio를 벗어나지 않아도 됩니다. 위의 mcp.run() 및 StdioServerTransport() 호출은 이미 stdio이므로 개발 준비는 완료되었습니다.
Inspector로 MCP 서버 테스트하는 방법
Claude에 서버를 연결하기 전에 MCP Inspector를 사용하여 격리된 상태에서 테스트하세요. 이는 브라우저 UI로 서버에 연결하여 도구를 목록화하고 수동으로 호출할 수 있게 해줍니다. 서버를 대상으로 실행합니다.
# Python
npx @modelcontextprotocol/inspector uv run server.py
# TypeScript
npx @modelcontextprotocol/inspector npx tsx server.tsInspector는 로컬 페이지를 열어 add 및 fetch_url 도구를 확인하고, 테스트 호출을 실행하며, raw 응답을 읽을 수 있게 해줍니다. 이는 MCP 개발에서 가장 좋은 습관입니다. 도구의 스키마가 잘못되었거나 반환 값이 틀린 경우, Claude 내부의 침묵하는 실패를 바라보는 대신 여기서 몇 초 만에 확인할 수 있습니다. 우리는 이 방식으로 클라이언트를 통한 전체 디버깅 왕복 시간을 절약할 수 있었던 잘못된 입력 스키마를 발견했습니다. 항상 먼저 Inspector에서 테스트하세요.
MCP 서버를 Claude Desktop, Claude Code 및 Cursor에 연결하는 방법
Inspector에서 문제가 없으면 실제 클라이언트를 서버에 연결합니다. 각 클라이언트는 stdio를 통해 서버를 실행하는 방법을 알려주는 구성 파일을 읽습니다.
Claude Desktop. claude_desktop_config.json을 편집합니다 (macOS 기준: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"demo-server": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/mcp-demo", "run", "server.py"]
}
}
}Claude Desktop을 재시작하면 커넥터 아이콘 아래에 도구들이 나타납니다.
Claude Code. 프로젝트에서 다음 명령어로 서버를 추가합니다: claude mcp add demo-server -- uv run server.py. Claude Code는 이를 프로젝트 구성에 저장하고 실행 시 로드합니다. Claude Code를 스크립팅하기 위해 훅(hooks)도 사용한다면, Claude Code 훅 가이드가 custom MCP 도구와 잘 어울립니다.
Cursor. 프로젝트 루트의 .cursor/mcp.json에 동일한 mcpServers 블록을 추가합니다. 형태는 Claude Desktop과 일치합니다. Claude Code 내부에서 실행되는 MCP 서버의 실제 사례로는 Higgsfield를 Claude Code에 연결한 방법을 참조하세요.
모든 구성에서 절대 경로를 사용하세요. 상대 경로는 서버 실행 실패의 가장 흔한 원인입니다.
프로덕션으로 MCP 서버 배포하기 (인증 및 호스팅)
서버를 공유해야 할 때는 stdio에서 Streamable HTTP로 전환하고 세 가지를 추가해야 합니다: 인증, 오류 처리 및 호스트.
- 인증. 원격 MCP 서버는 MCP authorization spec에 따라 OAuth 2.1을 사용해야 합니다. 내부 도구의 경우 HTTP 엔드포인트에서 bearer-token 검사가 실용적인 최소 조건입니다. SQL을 실행하거나 내부 API를 호출하는 도구는 살아있는 공격 표면이므로, 인증되지 않은 공개 도구 서버는 절대 배포하지 마세요.
- 오류 처리. 도구 본문을 try/except (또는 try/catch)로 감싸고 throw하는 대신 타입이 지정된 오류 메시지를 반환하세요. 모델은 "쿼리가 실패했으며 이유는 다음과 같습니다"라는 메시지를 끊어진 연결보다 훨씬 잘 처리합니다.
- 호스팅. 장기 실행 Node 또는 Python 프로세스를 실행할 수 있는 모든 플랫폼이 적합합니다: 소형 VPS, Fly.io, Railway 또는 자체 인프라의 컨테이너. 첫 번째 도구 호출에 지연 시간을 추가하므로 프로세스를 warm 상태로 유지하세요.
- 동시성 및 비용. 도구가 하류에서 LLM 또는 유료 API를 호출하는 경우 앞에 게이트웨이를 배치하세요. LLM 게이트웨이 도구 요약 자료는 속도 제한 및 폴백을 다루며, 컨텍스트 엔지니어링 도구는 도구 출력이 모델의 컨텍스트 창을 과도하게 채우는 것을 방지하는 데 도움이 됩니다.
Python의 경우 실행 호출을 mcp.run(transport="streamable-http")로 변경하고, TypeScript의 경우 StdioServerTransport를 SDK의 StreamableHTTPServerTransport로 교체하세요. 도구 정의는 전혀 변경되지 않습니다. 이것이 전송 계층 추상화의 목적입니다.
프로덕션에서 MCP 서버를 배포하며 배운 점
Techsy에서 내부용으로 MCP 서버를 구축했으며, 실제 트래픽이 발생했을 때만 드러나는 몇 가지 교훈이 있습니다. 우리가 측정한 내용과 문제를 겪었던 부분을 소개합니다.
우리가 처음 배포한 서버는 Python mcp 1.x SDK 기반 FastMCP 2.x로 구축된 읽기 전용 Postgres 쿼리 도구였으며, 나중에 비교를 위해 @modelcontextprotocol/sdk 1.x로 다시 작성되었습니다. 2026년 스택(Node 20, Python 3.11)에서 로컬 stdio 도구 호출은 호출당 약 8~12ms의 전송 오버헤드를 추가했습니다. 동일한 서버를 VPS의 Streamable HTTP로 이동하자 호출당 비용이 40~70ms로 증가했으며, 이는 거의 전적으로 프로토콜 비용이 아닌 네트워크 왕복 시간 때문이었습니다. FastMCP의 콜드 스타트는 프로세스 기준 약 300ms였으며, 이것이 우리가 프로덕션 프로세스를 warm 상태로 유지하는 이유입니다.
약 2시간의 비용을 치르게 한 함정: Inspector에서는 정상적으로 렌더링되었던 raw Python dict를 반환하는 도구가 Claude Desktop 내부에서는 truncated 되어 반환되었습니다. 반환 값을 타입이 지정된 텍스트 문자열로 감싸자 즉시 해결되었습니다. 이것이 이 튜토리얼이 중첩 객체 대신 везде 문자열과 content 텍스트 블록을 반환하는 이유입니다. 즉시 효과를 본 또 다른 습관은 클라이언트 구성을 건드리기 전에 모든 서버를 npx @modelcontextprotocol/inspector로 실행하는 것이었는데, 이로 인해 TypeScript 재작성 과정에서 Cursor에서 조용히 실패했을 잘못된 입력 스키마를 표면화할 수 있었습니다.
| 사용한 항목 | 버전 |
|---|---|
Python mcp SDK | 1.x |
| FastMCP | 2.x |
@modelcontextprotocol/sdk (TS) | 1.x |
| Node.js | 20 LTS |
| Inspector | @modelcontextprotocol/inspector (최신) |
어떤 도구를 서버로 구축할지 고민 중이라면, 2026년 최고의 MCP 서버 목록이 좋은 아이디어 뱅크가 될 것입니다.
Techsy의 MCP 개발 접근 방식
Techsy에서는 클라이언트용으로 배포하는 AI 에이전트 시스템의 일부로 MCP 서버를 구축하며, 타입이 지정된 도구 계층을 통해 에이전트를 내부 데이터베이스, CRM 및 API에 연결합니다. 우리의 접근 방식은 좁게 시작하는 것(stdio上で 잘 테스트된 도구 하나), Inspector에서 검증한 후, 두 명 이상의 에이전트가 필요할 때만 인증된 HTTP 서비스로 승격시키는 것입니다. 에이전트 로직이 복잡해질 때는 custom 서버를 Claude Agent SDK와 결합합니다.
솔직한 버전은 다음과 같습니다: 대부분의 팀은 첫 서버를 과잉 구축합니다. 첫날부터 HTTP, OAuth 및 십여 개의 도구가 필요한 경우는 거의 없습니다. MCP 통합에 대한 제2의 의견이 필요하다면 무료 상담을 신청하세요. 그것이 단일 도구 stdio 작업인지, 아니면 실제로 인프라가 필요한 것인지 알려드리겠습니다.
자주 묻는 질문
MCP 서버를 Python으로 구축해야 할까요, 아니면 TypeScript로 구축해야 할까요?
팀에서 이미 배포하고 있는 언어를 사용하세요. FastMCP를 사용한 Python은 데코레이터가 함수를 도구로 변환해주기 때문에 첫 실행 서버로 가는 가장 짧은 경로입니다. 공식 SDK를 사용한 TypeScript는 약간 더 장황하지만 우수한 타입 지원을 제공하며 Node 호스트에 깔끔하게 배포됩니다. 둘 다 클라이언트에게 동일하게 작동하는 서버를 생성합니다.
MCP 서버를 구축하기 위해 FastMCP와 같은 프레임워크가 필요할까요?
필수는 아니지만 도움이 됩니다. FastMCP는 공식 Python mcp SDK에 포함되어 있으며 대부분의 프로토콜 보일러플레이트를 제거합니다. 세밀한 제어를 위해 하위 수준 Server API를 사용할 수 있지만, 거의 모든 서버에는 FastMCP(Python) 또는 McpServer(TypeScript)가 적합한 도구이며 코드 양이 훨씬 적습니다.
작동하지 않는 MCP 서버는 어떻게 디버깅하나요?
먼저 MCP Inspector를 통해 실행하세요: npx @modelcontextprotocol/inspector 뒤에 실행 명령어를 붙입니다. Inspector는 도구를 목록화하고 직접 호출할 수 있게 해주므로, 클라이언트를 탓하기 전에 서버가 작동하는지 확인할 수 있습니다. Inspector는 정상인데 클라이언트가 작동하지 않으면, 구성에서 절대 경로를 사용했는지 확인하고 클라이언트를 재시작했는지 점검하세요.
FastMCP는 MCP의 공식 일부인가요?
네. FastMCP는 고급 서버 인터페이스로서 공식 Model Context Protocol Python SDK에 번들로 제공됩니다. 사용하는 @mcp.tool() 데코레이터는 서드파티 추가 기능이 아닌 Python 서버를 구축하는 권장 방식입니다.
로컬 MCP 서버와 원격 MCP 서버의 차이점은 무엇인가요?
로컬 서버는 하위 프로세스로 클라이언트에 의해 실행되어 머신에서 stdio를 통해 작동하며, 개인용 도구 및 개발에 최적입니다. 원격 서버는 Streamable HTTP를 통해 웹 서비스로 실행되며 여러 클라이언트가 접근할 수 있어 OAuth 2.1 인증이 필요합니다. 로컬부터 구축하고 공유가 필요할 때만 원격으로 전환하세요.
어떤 언어로 MCP 서버를 구축할 수 있나요?
Model Context Protocol은 Python, TypeScript, Java, Kotlin 및 C#용 공식 SDK를 제공하며, 다른 언어에도 커뮤니티 SDK가 있습니다. MCP는 와이어 프로토콜이므로 stdio 또는 HTTP를 통해 JSON-RPC를 읽고 쓸 수 있는 모든 언어로 서버를 구현할 수 있지만, 공식 SDK를 사용하면 그러한 작업을 절약할 수 있습니다.
MCP 서버는 ChatGPT 및 Gemini와도 작동하나요, 아니면 Claude만 가능한가요?
MCP는 ChatGPT, Gemini, Cursor 및 VS Code Copilot을 포함한 에이전틱 AI 생태계 전반에서 채택된 오픈 표준입니다. 구축한 단일 서버는 호환되는 모든 클라이언트에서 작동합니다. 모델마다 별도의 통합을 작성할 필요가 없다는 것이 바로 이 프로토콜의 존재 이유입니다.
작동하는 MCP 서버를 구축하는 데 얼마나 걸리나요?
런타임이 설치되면 stdio上で 실행되는 한두 개의 도구를 갖춘 첫 서버는 약 15분이 소요됩니다. Node 20에서 초보자의 경우 14분, 반복 구축의 경우 5분 미만으로 측정되었습니다. 실제 시간이 소요되는 것은 서버 자체가 아니라 인증, HTTP 전송 계층 및 프로덕션 호스팅 추가 부분입니다.
저자 소개
Mert Batur Gurbuz는 Techsy.io의 공동 창업자로, 팀은 B2B 클라이언트를 위한 AI 에이전트, 자동화 시스템 및 음성/SDR 파이프라인을 배포합니다. 그는 버밍엄 대학교에서 공부하며 Techsy 팀이 프로덕션에서 실제로 사용하는 LLM 툴링 스택에 대해 글을 씁니다. LinkedIn에서 연결하세요.
Mert Batur Gurbuz, 공동 창업자, Techsy.io, 버밍엄 대학교