모델 컨텍스트 프로토콜(MCP)은 AI 어시스턴트가 외부 도구 및 데이터 소스와 상호 작용하는 방식을 혁신합니다. MCP를 AI 애플리케이션을 위한 범용 USB-C 포트라고 생각해보세요. 상상할 수 있는 거의 모든 데이터 소스, API 또는 도구에 Claude Code를 연결할 수 있는 표준화된 방법을 제공합니다. 이 종합 가이드는 처음부터 자신만의 MCP 서버를 구축하는 과정을 안내하며, Claude Code가 내장 기능을 훨씬 뛰어넘는 맞춤형 기능에 액세스할 수 있도록 지원합니다.
데이터베이스, API, 파일 시스템을 통합하거나 완전히 맞춤형 도구를 생성하려는 경우, MCP는 무한한 확장성을 위한 기반을 제공합니다. 이 튜토리얼을 마치면 작동하는 MCP 서버를 갖게 되며 모든 사용 사례에 맞게 확장하는 방법을 이해하게 될 것입니다.
최대 생산성으로 개발팀이 함께 작업할 수 있는 통합 올인원 플랫폼을 원하시나요?
Apidog는 귀하의 모든 요구 사항을 충족하며, 훨씬 저렴한 가격으로 Postman을 대체합니다!
We’re thrilled to share that MCP support is coming soon to Apidog! 🚀
— Apidog (@ApidogHQ) March 19, 2025
Apidog MCP Server lets you feed API docs directly to Agentic AI, supercharging your vibe coding experience! Whether you're using Cursor, Cline, or Windsurf - it'll make your dev process faster and smoother.… pic.twitter.com/ew8U38mU0K
MCP 서버란 무엇이며 왜 모두가 이야기하는가
MCP가 다른 점
MCP(Model Context Protocol)는 Anthropic이 개발한 개방형 프로토콜로, AI 모델이 표준화된 인터페이스를 통해 외부 서버와 통신할 수 있도록 합니다. 특정 엔드포인트를 하드코딩하는 전통적인 API 통합과 달리, MCP는 AI 어시스턴트가 외부 도구를 동적으로 발견하고 이해하며 활용할 수 있는 구조화된 방법을 제공합니다.
MCP의 독창성은 발견 가능성에 있습니다. Claude Code가 MCP 서버에 연결하면 사용 가능한 도구, 사용 방법 및 허용되는 매개변수를 자동으로 학습합니다. 이는 Claude Code 자체를 업데이트하지 않고도 새로운 기능을 추가할 수 있음을 의미합니다.
MCP 아키텍처 심층 분석
이 프로토콜은 명확하게 정의된 역할을 가진 클라이언트-서버 아키텍처를 따릅니다.
- MCP 호스트: Claude Code, Claude Desktop 또는 MCP 서비스를 사용하는 기타 AI 어시스턴트와 같은 애플리케이션
- MCP 클라이언트: 서버와 1:1 연결을 유지하고 통신을 처리하는 프로토콜 클라이언트
- MCP 서버: 표준화된 프로토콜을 통해 특정 기능을 노출하는 경량 프로그램
- 전송 계층: 통신 방법 (로컬 서버는 stdio, 원격 서버는 SSE)
통신 흐름 설명
Claude Code가 외부 도구를 사용해야 할 때 발생하는 상황은 다음과 같습니다.
- 발견 단계: Claude Code가 서버에 사용 가능한 도구를 쿼리합니다.
- 스키마 유효성 검사: 서버가 도구 정의 및 입력 스키마로 응답합니다.
- 도구 선택: Claude Code가 사용자 요청에 따라 적절한 도구를 선택합니다.
- 실행 단계: Claude Code가 유효성이 검증된 매개변수로 도구 호출을 보냅니다.
- 결과 처리: 서버가 요청을 처리하고 구조화된 결과를 반환합니다.
이 흐름은 모든 MCP 통합에서 타입 안전성, 적절한 오류 처리 및 일관된 동작을 보장합니다.
사전 요구 사항 및 환경 설정
시스템 요구 사항 분석
MCP 서버를 구축하기 전에 개발 환경을 이해하고 올바른 도구를 선택해야 합니다. MCP 서버는 여러 언어로 구축할 수 있지만, Python과 TypeScript는 광범위한 도구 지원으로 가장 일반적으로 지원됩니다.
Python 개발용:
- Python 3.8 이상 - 최신 async/await 지원 및 타입 주석에 필요
- pip 패키지 관리자 - 종속성 관리를 위해
- 가상 환경 도구 - 종속성을 격리하기 위해
venv
또는conda
사용
TypeScript/JavaScript 개발용:
- Node.js v20 이상 - 최신 ECMAScript 기능 및 안정성에 필요
- npm 또는 yarn - 패키지 관리를 위해
- TypeScript 컴파일러 - 더 나은 타입 안전성을 위해 TypeScript를 사용하는 경우
핵심 종속성:
- Claude Code CLI: MCP 서버 관리를 위한 기본 인터페이스
- JSON-RPC 2.0 지식: 기본 통신 프로토콜 이해
- 기본 서버 아키텍처 개념: 요청/응답 주기 및 오류 처리
단계별 환경 준비
1. Claude Code CLI 설치
Claude Code CLI는 MCP 서버를 관리하기 위한 기본 도구입니다. 어떤 디렉토리에서도 액세스할 수 있도록 전역으로 설치하세요.
# Install Claude Code globally
npm install -g @anthropic-ai/claude-code
전역 설치가 중요한 이유: 전역 설치는 claude
명령이 시스템 전체에서 사용 가능하도록 보장하여, 다른 디렉토리에서 MCP 서버를 등록할 때 경로 관련 문제를 방지합니다.
2. 설치 확인
Claude Code가 제대로 설치되고 액세스 가능한지 확인하세요.
# Verify installation and check version
claude --version
# Check available commands
claude --help
3. 중요: 첫 실행 권한 설정
이 단계는 절대적으로 필수적이며 종종 간과됩니다.
# Run initial setup with permissions bypass
claude --dangerously-skip-permissions
이 명령이 하는 일:
- Claude Code의 구성 디렉토리 초기화
- MCP 통신을 위한 보안 권한 설정
- 필요한 인증 토큰 생성
- MCP 레지스트리 데이터베이스 설정
필요한 이유: 이 단계 없이는 MCP 서버가 Claude Code와 보안 연결을 설정할 수 없어 인증 실패 및 연결 시간 초과가 발생합니다.
보안 고려 사항: --dangerously-skip-permissions
플래그는 개발 환경에서는 안전하지만 일반적인 보안 프롬프트를 우회합니다. 프로덕션 환경에서는 각 권한 요청을 신중하게 검토하세요.
중요 구성: MCP 스코프 이해
구성 스코프가 중요한 이유
MCP 서버를 구축할 때 가장 흔한 함정 중 하나는 부적절한 구성 스코프 관리입니다. 스코프를 이해하는 것은 MCP 서버가 Claude Code에서 사용 가능한 위치와 시기를 결정하기 때문에 매우 중요합니다. 많은 개발자가 스코프 잘못된 구성으로 인해 "서버를 찾을 수 없습니다" 오류를 디버깅하는 데 몇 시간을 소비합니다.
Claude Code는 보안을 유지하면서 유연성을 제공하도록 설계된 계층적 구성 시스템을 사용합니다. 각 스코프는 특정 목적을 가지며 다른 사용 사례를 가집니다.
구성 스코프 계층 구조 설명
1. 프로젝트 스코프 (.mcp.json
) - 최고 우선순위
위치: 프로젝트 루트 디렉토리의 .mcp.json
파일
목적: 특정 프로젝트에서 작업할 때만 사용 가능한 프로젝트별 MCP 서버
사용 사례: 프로젝트별 데이터베이스 연결, 프로젝트별 린터 또는 사용자 지정 빌드 도구
프로젝트 스코프가 적절한 경우:
- 전역적이지 않은 프로젝트별 도구가 있는 경우
- 팀으로 작업하며 버전 제어를 통해 MCP 구성을 공유하려는 경우
- 다른 프로젝트에 대해 동일한 도구의 다른 버전이 필요한 경우
2. 사용자 스코프 (--scope user
) - 전역 구성
위치: 사용자 홈 디렉토리 구성
목적: 모든 프로젝트 및 디렉토리에서 전역적으로 사용 가능한 MCP 서버
사용 사례: 날씨 API, 계산기 도구 또는 시스템 유틸리티와 같은 범용 도구
사용자 스코프가 일반적으로 선호되는 이유:
- 시스템의 어떤 디렉토리에서도 작동
- 프로젝트 디렉토리 변경에 영향을 받지 않음
- 어디서든 사용하고 싶은 유틸리티 서버에 이상적
3. 로컬 스코프 (기본값) - 디렉토리별
위치: 현재 작업 디렉토리 컨텍스트
목적: 빠르고 임시적인 MCP 서버 설정
제한 사항: 해당 특정 디렉토리에서 Claude Code를 실행할 때만 작동
흔한 구성 실수
❌ 잘못된 접근 방식 (로컬 스코프 - 기능 제한):
claude mcp add my-server python3 /path/to/server.py
문제: 이 서버는 등록한 정확한 디렉토리에 있을 때만 작동합니다.
✅ 올바른 접근 방식 (사용자 스코프 - 전역 액세스):
claude mcp add --scope user my-server python3 /path/to/server.py
이점: 이 서버는 시스템의 어떤 디렉토리에서도 작동합니다.
전략적 디렉토리 계획
권장 디렉토리 구조
장기적인 유지 관리를 위해 잘 구성된 디렉토리 구조를 만드세요.
# Create permanent storage location
mkdir -p ~/.claude-mcp-servers/
# Organize by functionality
mkdir -p ~/.claude-mcp-servers/apis/
mkdir -p ~/.claude-mcp-servers/utilities/
mkdir -p ~/.claude-mcp-servers/development/
체계적인 구조의 이점
유지 관리성: 나중에 서버를 쉽게 찾고 업데이트할 수 있습니다.
보안: 다른 유형의 도구 간 명확한 분리
백업: 하나의 디렉토리를 백업하여 모든 MCP 서버를 쉽게 백업
공유: 팀 구성원과 서버 구성을 쉽게 공유
스코프 문제 해결 가이드
스코프 문제 진단
MCP 서버가 나타나지 않으면 다음 진단 순서를 따르세요.
- 현재 스코프 구성 확인:
claude mcp list
- 충돌하는 프로젝트 스코프가 있는 디렉토리에 있지 않은지 확인:
ls .mcp.json
- 다른 디렉토리에서 테스트:
cd ~ && claude mcp list
cd /tmp && claude mcp list
스코프 문제 해결
문제: 서버가 한 디렉토리에서만 작동
해결책: 로컬 구성 제거 및 사용자 스코프로 다시 추가
# Remove problematic local configuration
claude mcp remove my-server
# Re-add with global user scope
claude mcp add --scope user my-server python3 /path/to/server.py
첫 번째 MCP 서버 구축
개발 프로세스 이해
MCP 서버를 구축하는 것은 MCP 프로토콜과 사용 사례의 특정 요구 사항을 모두 이해하는 것을 포함합니다. 기본 사항을 이해하기 위해 기본적인 "Hello World" 서버부터 시작한 다음, 그 기반 위에 구축할 것입니다.
개발 프로세스는 다음 단계를 따릅니다.
- 서버 구조 설정: 기본 파일 구조 및 진입점 생성
- 프로토콜 구현: 필요한 MCP 메서드 구현
- 도구 정의: 서버가 제공하는 도구 정의
- 등록 및 테스트: Claude Code에 서버 추가 및 기능 확인
- 개선 및 프로덕션: 실제 기능 및 오류 처리 추가
단계 1: 프로젝트 기반 및 구조
개발 환경 생성
먼저 MCP 서버를 위한 적절한 개발 환경을 설정하세요.
# Navigate to your MCP servers directory
cd ~/.claude-mcp-servers/
# Create a new server project
mkdir my-first-server
cd my-first-server
# Initialize the project structure
touch server.py
touch requirements.txt
touch .env
이 구조가 중요한 이유
체계적인 개발: 각 서버를 자체 디렉토리에 유지하면 충돌을 방지하고 유지 관리가 쉬워집니다.
종속성 격리: 각 서버는 다른 서버에 영향을 주지 않고 자체 요구 사항을 가질 수 있습니다.
구성 관리: 환경 파일은 값을 하드코딩하지 않고 보안 구성을 허용합니다.
MCP 서버 요구 사항 이해
모든 MCP 서버는 세 가지 핵심 JSON-RPC 메서드를 구현해야 합니다.
initialize
: 연결을 설정하고 서버 기능을 선언합니다.tools/list
: 사용 가능한 도구와 해당 스키마를 반환합니다.tools/call
: 제공된 매개변수로 특정 도구를 실행합니다.
단계 2: 핵심 서버 프레임워크 구현
기본 MCP 서버 템플릿을 사용하여 server.py
라는 파일을 생성하세요.
#!/usr/bin/env python3
"""
Custom MCP Server for Claude Code Integration
"""
import json
import sys
import os
from typing import Dict, Any, Optional
# Ensure unbuffered output for proper MCP communication
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)
sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 1)
def send_response(response: Dict[str, Any]):
"""Send a JSON-RPC response to Claude Code"""
print(json.dumps(response), flush=True)
def handle_initialize(request_id: Any) -> Dict[str, Any]:
"""Handle MCP initialization handshake"""
return {
"jsonrpc": "2.0",
"id": request_id,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {}
},
"serverInfo": {
"name": "my-custom-server",
"version": "1.0.0"
}
}
}
def handle_tools_list(request_id: Any) -> Dict[str, Any]:
"""List available tools for Claude Code"""
tools = [
{
"name": "hello_world",
"description": "A simple demonstration tool",
"inputSchema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name to greet"
}
},
"required": ["name"]
}
}
]
return {
"jsonrpc": "2.0",
"id": request_id,
"result": {
"tools": tools
}
}
def handle_tool_call(request_id: Any, params: Dict[str, Any]) -> Dict[str, Any]:
"""Execute tool calls from Claude Code"""
tool_name = params.get("name")
arguments = params.get("arguments", {})
try:
if tool_name == "hello_world":
name = arguments.get("name", "World")
result = f"Hello, {name}! Your MCP server is working perfectly."
else:
raise ValueError(f"Unknown tool: {tool_name}")
return {
"jsonrpc": "2.0",
"id": request_id,
"result": {
"content": [
{
"type": "text",
"text": result
}
]
}
}
except Exception as e:
return {
"jsonrpc": "2.0",
"id": request_id,
"error": {
"code": -32603,
"message": str(e)
}
}
def main():
"""Main server loop handling JSON-RPC communication"""
while True:
try:
line = sys.stdin.readline()
if not line:
break
request = json.loads(line.strip())
method = request.get("method")
request_id = request.get("id")
params = request.get("params", {})
if method == "initialize":
response = handle_initialize(request_id)
elif method == "tools/list":
response = handle_tools_list(request_id)
elif method == "tools/call":
response = handle_tool_call(request_id, params)
else:
response = {
"jsonrpc": "2.0",
"id": request_id,
"error": {
"code": -32601,
"message": f"Method not found: {method}"
}
}
send_response(response)
except json.JSONDecodeError:
continue
except EOFError:
break
except Exception as e:
if 'request_id' in locals():
send_response({
"jsonrpc": "2.0",
"id": request_id,
"error": {
"code": -32603,
"message": f"Internal error: {str(e)}"
}
})
if __name__ == "__main__":
main()
코드 아키텍처 설명
입출력 설정: 처음 몇 줄은 버퍼링되지 않은 I/O를 구성하는데, 이는 MCP 통신에 중요합니다. 버퍼링된 출력은 프로토콜을 깨뜨리는 메시지 전달 지연을 유발할 수 있습니다.
JSON-RPC 처리: 메인 루프는 stdin에서 JSON-RPC 요청을 읽고 stdout에 응답을 씁니다. 이는 로컬 서버 통신을 위한 MCP 사양을 따릅니다.
오류 처리 전략: 코드는 여러 계층의 오류 처리를 구현합니다.
- JSON 구문 분석 오류 (잘못된 형식의 요청)
- 메서드를 찾을 수 없음 오류 (지원되지 않는 작업)
- 도구 실행 오류 (런타임 실패)
프로토콜 준수: 각 응답에는 적절한 상관 관계를 위한 필수 필드 jsonrpc: "2.0"
및 요청 ID가 포함됩니다.
단계 3: 서버 준비 및 테스트
서버 실행 가능하게 만들기
# Make the server executable
chmod +x server.py
실행 권한이 중요한 이유: MCP 서버는 Claude Code에 의해 서브 프로세스로 시작됩니다. 실행 권한이 없으면 모호한 권한 오류로 인해 시작이 실패합니다.
수동 프로토콜 테스트
Claude Code에 등록하기 전에 서버의 프로토콜 구현을 테스트하세요.
# Test the initialize handshake
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | python3 server.py
예상 결과: 프로토콜 버전 및 기능이 포함된 JSON 응답이 표시되어야 합니다. 오류 메시지가 표시되거나 출력이 없으면 Python 설치 및 스크립트 구문을 확인하세요.
유효성 검사 단계
계속 진행하기 전에 다음 유효성 검사를 수행하세요.
- 구문 확인:
python3 -m py_compile server.py
- 가져오기 테스트:
python3 -c "import json, sys, os"
- 실행 테스트: 수동 프로토콜 테스트가 작동하는지 확인
단계 4: Claude Code에 등록
서버 추가
적절한 스코프와 절대 경로를 사용하여 서버를 등록하세요.
# Register with global user scope for universal access
claude mcp add --scope user my-first-server python3 ~/.claude-mcp-servers/my-first-server/server.py
중요 세부 정보:
- "파일을 찾을 수 없음" 오류를 방지하기 위해 절대 경로 사용
- 쉽게 식별할 수 있도록 설명적인 서버 이름 선택
- 개발 서버에는 항상
--scope user
사용
확인 및 문제 해결
# Verify registration
claude mcp list
# Check for any connection issues
claude mcp get my-first-server
일반적인 등록 문제:
- 서버가 목록에 없음: 파일 경로 및 권한 확인
- 연결 실패: Python 설치 및 스크립트 구문 확인
- 스코프 문제: 충돌하는
.mcp.json
이 있는 디렉토리에 있지 않은지 확인
고급 예제: 날씨 API 통합
Hello World를 넘어
기본 MCP 서버 구조를 이해했으니 이제 실제 통합 패턴을 보여주는 보다 실용적인 서버를 구축해 보겠습니다. 이 날씨 API 서버는 다음을 가르쳐 줄 것입니다.
- 적절한 오류 처리를 통한 외부 API 통합
- 보안 구성을 위한 환경 변수 관리
- 입력 유효성 검사 및 매개변수 처리
- 최적의 Claude Code 통합을 위한 응답 형식 지정
- 프로덕션 준비 오류 처리 패턴
API 통합 계획
코드를 작성하기 전에 다음 통합 측면을 고려하십시오.
API 선택: 단순성과 무료 계층을 위해 OpenWeatherMap API를 사용합니다.
데이터 흐름: 사용자 요청 → 매개변수 유효성 검사 → API 호출 → 응답 형식 지정 → Claude 응답
오류 시나리오: 네트워크 오류, 잘못된 API 키, 잘못된 형식의 응답, 속도 제한
보안: 환경 변수에 저장된 API 키, 입력 정리
구현 전략
모든 오류 처리를 포함하여 이 서버를 점진적으로 구축해 보겠습니다.
#!/usr/bin/env python3
import json
import sys
import os
import requests
from typing import Dict, Any
# Configuration - use environment variables for security
WEATHER_API_KEY = os.environ.get("OPENWEATHER_API_KEY", "your-api-key-here")
def get_weather(city: str) -> str:
"""Fetch current weather data for a specified city"""
try:
url = "<http://api.openweathermap.org/data/2.5/weather>"
params = {
"q": city,
"appid": WEATHER_API_KEY,
"units": "metric"
}
response = requests.get(url, params=params, timeout=10)
data = response.json()
if response.status_code == 200:
temp = data["main"]["temp"]
desc = data["weather"][0]["description"]
humidity = data["main"]["humidity"]
return f"Weather in {city}: {temp}°C, {desc.title()}, Humidity: {humidity}%"
else:
return f"Error fetching weather: {data.get('message', 'Unknown error')}"
except requests.RequestException as e:
return f"Network error: {str(e)}"
except Exception as e:
return f"Error processing weather data: {str(e)}"
def handle_tools_list(request_id: Any) -> Dict[str, Any]:
"""Enhanced tools list with weather functionality"""
tools = [
{
"name": "get_weather",
"description": "Get current weather conditions for any city worldwide",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City name (e.g., 'London', 'Tokyo', 'New York')"
}
},
"required": ["city"]
}
}
]
return {
"jsonrpc": "2.0",
"id": request_id,
"result": {
"tools": tools
}
}
def handle_tool_call(request_id: Any, params: Dict[str, Any]) -> Dict[str, Any]:
"""Enhanced tool execution with weather functionality"""
tool_name = params.get("name")
arguments = params.get("arguments", {})
try:
if tool_name == "get_weather":
city = arguments.get("city")
if not city:
raise ValueError("City name is required")
result = get_weather(city)
else:
raise ValueError(f"Unknown tool: {tool_name}")
return {
"jsonrpc": "2.0",
"id": request_id,
"result": {
"content": [
{
"type": "text",
"text": result
}
]
}
}
except Exception as e:
return {
"jsonrpc": "2.0",
"id": request_id,
"error": {
"code": -32603,
"message": str(e)
}
}
# Include the same main() function and other handlers from the basic example
고급 기능 설명
환경 변수 보안: API 키는 환경 변수에서 로드되며 절대 하드코딩되지 않습니다. 이는 버전 제어에서 실수로 노출되는 것을 방지합니다.
강력한 오류 처리: get_weather()
함수는 여러 오류 시나리오를 처리합니다.
- 네트워크 시간 초과 및 연결 실패
- 잘못된 API 응답 및 속도 제한
- 잘못된 형식의 JSON 데이터
- 누락되거나 잘못된 API 키
향상된 도구 스키마: 날씨 도구 스키마에는 자세한 설명과 예제가 포함되어 있어 Claude Code가 도구를 효과적으로 사용하는 방법을 이해하는 데 도움이 됩니다.
단계 5: 전문적인 종속성 및 구성 관리
적절한 요구 사항 파일 생성
requests>=2.28.0
python-dotenv>=1.0.0
버전 고정 전략: 최소 버전 요구 사항(>=
)을 사용하면 보안 업데이트를 허용하면서 호환성을 보장합니다. 프로덕션 서버의 경우 정확한 버전 고정을 고려하십시오.
보안 환경 구성
구성 관리를 위해 .env
파일을 생성합니다.
# Weather API configuration
OPENWEATHER_API_KEY=your_actual_api_key_here
# Server configuration
MCP_LOG_LEVEL=INFO
MCP_DEBUG=false
# Optional: Rate limiting
MCP_MAX_REQUESTS_PER_MINUTE=60
보안 모범 사례:
- 절대
.env
파일을 버전 제어에 커밋하지 마십시오. - 강력하고 고유한 API 키를 사용하십시오.
- 악용을 방지하기 위해 속도 제한을 구현하십시오.
- 프로덕션 사용을 위해 API 키 순환을 고려하십시오.
종속성 설치 및 격리
# Create virtual environment for isolation
python3 -m venv mcp-env
source mcp-env/bin/activate # On Windows: mcp-env\\\\Scripts\\\\activate
# Install dependencies
pip install -r requirements.txt
# Verify installation
python3 -c "import requests; print('Dependencies installed successfully')"
가상 환경이 중요한 이유: 격리는 다른 MCP 서버와 시스템 Python 설치 간의 종속성 충돌을 방지합니다.
MCP 서버 테스트 및 디버깅
포괄적인 테스트 전략
MCP 서버를 테스트하려면 프로토콜 준수와 기능적 정확성 모두를 다루어야 하므로 다층적인 접근 방식이 필요합니다. 체계적인 테스트 전략은 문제가 프로덕션에 도달하는 것을 방지하고 디버깅을 훨씬 쉽게 만듭니다.
MCP 서버를 위한 테스트 피라미드
- 단위 테스트: 개별 함수 테스트
- 프로토콜 테스트: JSON-RPC 준수 확인
- 통합 테스트: Claude Code 상호 작용 테스트
- 종단 간 테스트: 전체 워크플로우 유효성 검사
계층 1: 수동 프로토콜 테스트
핵심 MCP 메서드 테스트
통합 전에 서버가 MCP 프로토콜을 올바르게 구현하는지 확인하십시오.
# Test initialization handshake
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | python3 server.py
예상 응답 구조:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {"tools": {}},
"serverInfo": {"name": "your-server", "version": "1.0.0"}
}
}
도구 발견 테스트
# Test tools list endpoint
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | python3 server.py
유효성 검사 체크리스트:
- 응답에
tools
배열 포함 - 각 도구에
name
,description
,inputSchema
포함 - 스키마가 JSON Schema 사양 준수
- 모든 필수 필드가 스키마에 표시됨
도구 실행 테스트
# Test actual tool functionality
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_weather","arguments":{"city":"London"}}}' | python3 server.py
확인할 사항:
- 도구가 오류 없이 실행
- 응답에
content
배열 포함 - 콘텐츠에 적절한
type
및 데이터 필드 포함 - 오류 응답에 적절한 오류 코드 포함
계층 2: 자동화된 테스트 프레임워크
테스트 스크립트 생성
자동화된 테스트를 위해 test_server.py
파일을 생성하십시오.
#!/usr/bin/env python3
import json
import subprocess
import sys
def test_mcp_method(method, params=None):
"""Test a specific MCP method"""
request = {
"jsonrpc": "2.0",
"id": 1,
"method": method,
"params": params or {}
}
try:
result = subprocess.run(
[sys.executable, "server.py"],
input=json.dumps(request),
capture_output=True,
text=True,
timeout=10
)
return json.loads(result.stdout.strip())
except Exception as e:
return {"error": str(e)}
# Test suite
tests = [
("initialize", None),
("tools/list", None),
("tools/call", {"name": "hello_world", "arguments": {"name": "Test"}})
]
for method, params in tests:
response = test_mcp_method(method, params)
print(f"Testing {method}: {'✓ PASS' if 'result' in response else '✗ FAIL'}")
계층 3: Claude Code와의 통합 테스트
서버 등록 및 확인
# Register your server
claude mcp add --scope user test-server python3 /full/path/to/server.py
# Verify registration
claude mcp list | grep test-server
# Check server health
claude mcp get test-server
실시간 통합 테스트
# Start Claude Code in test mode
claude
# In Claude Code, test tool discovery
/mcp
# Test tool execution
mcp__test-server__hello_world name:"Integration Test"
도구 이름 지정 패턴: Claude Code는 이름 충돌을 피하기 위해 도구 이름 앞에 mcp__<server-name>__<tool-name>
을 붙입니다.
고급 디버깅 기술
디버그 로깅 활성화
서버에 포괄적인 로깅을 추가하십시오.
import logging
import sys
# Configure logging to stderr (won't interfere with JSON-RPC)
logging.basicConfig(
level=logging.DEBUG,
stream=sys.stderr,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def handle_tool_call(request_id, params):
logger.debug(f"Received tool call: {params}")
# ... your tool logic
logger.debug(f"Tool execution completed successfully")
MCP 서버 로그 분석
Claude Code는 각 MCP 서버에 대한 로그를 유지 관리합니다.
# View recent logs (macOS)
tail -f ~/Library/Logs/Claude/mcp-server-*.log
# View recent logs (Linux)
tail -f ~/.config/claude/logs/mcp-server-*.log
# Search for errors
grep -i error ~/Library/Logs/Claude/mcp-server-*.log
일반적인 디버깅 패턴
문제: 서버는 시작하지만 도구가 나타나지 않음
진단: tools/list
응답 형식 확인
해결책: JSON 스키마 준수 유효성 검사
문제: 도구 호출이 조용히 실패함
진단: tools/call
의 오류 처리 확인
해결책: 포괄적인 예외 처리 추가
문제: 서버 연결 끊김
진단: 버퍼링되지 않은 I/O 및 적절한 예외 처리 확인
해결책: sys.stdout
구성 및 메인 루프 오류 처리 확인
성능 및 안정성 테스트
서버 부하 테스트
# Test multiple rapid requests
for i in {1..10}; do
echo '{"jsonrpc":"2.0","id":'$i',"method":"tools/list","params":{}}' | python3 server.py &
done
wait
메모리 및 리소스 모니터링
# Monitor server resource usage
python3 -m memory_profiler server.py
# Check for memory leaks during extended operation
python3 -m tracemalloc server.py
일반적인 문제 해결
프로토콜 수준 문제
- 잘못된 JSON 응답:
json.loads()
를 사용하여 출력 유효성 검사 - 필수 필드 누락: MCP 사양 준수 확인
- 잘못된 오류 코드: 표준 JSON-RPC 오류 코드 사용
통합 문제
- 서버가 나타나지 않음: 파일 권한 및 Python 경로 확인
- 도구에 액세스할 수 없음: 스코프 구성 및 등록 확인
- 인증 실패: 적절한 MCP 초기화 보장
모범 사례 및 보안 고려 사항
프로덕션 준비 오류 처리
강력한 유효성 검사 구현
MCP 서버의 오류 처리는 포괄적이어야 합니다. 실패는 Claude Code와의 전체 통신 체인을 끊을 수 있기 때문입니다. 여러 수준에서 유효성 검사를 구현하십시오.
def validate_arguments(arguments: Dict[str, Any], required: List[str]):
"""Validate required arguments are present"""
missing = [field for field in required if field not in arguments]
if missing:
raise ValueError(f"Missing required fields: {', '.join(missing)}")
def handle_tool_call(request_id: Any, params: Dict[str, Any]) -> Dict[str, Any]:
"""Tool execution with proper validation"""
try:
tool_name = params.get("name")
arguments = params.get("arguments", {})
# Validate before processing
if tool_name == "get_weather":
validate_arguments(arguments, ["city"])
# Process tool logic here
except ValueError as ve:
return create_error_response(request_id, -32602, str(ve))
except Exception as e:
return create_error_response(request_id, -32603, f"Internal error: {str(e)}")
오류 응답 표준
JSON-RPC 2.0 오류 코드 규칙을 따르십시오.
- 32700: 구문 분석 오류 (잘못된 JSON)
- 32600: 잘못된 요청 (잘못된 형식의 요청 객체)
- 32601: 메서드를 찾을 수 없음 (지원되지 않는 MCP 메서드)
- 32602: 잘못된 매개변수 (도구에 대한 잘못된 매개변수)
- 32603: 내부 오류 (서버 측 실행 실패)
포괄적인 보안 프레임워크
1. 비밀 관리
민감한 정보를 절대 하드코딩하지 마십시오. 구성에 계층적 접근 방식을 사용하십시오.
import os
from pathlib import Path
def load_config():
"""Load configuration with fallback hierarchy"""
# 1. Environment variables (highest priority)
api_key = os.environ.get("API_KEY")
# 2. Local .env file
if not api_key:
env_path = Path(".env")
if env_path.exists():
# Load from .env file
pass
# 3. System keyring (production)
if not api_key:
try:
import keyring
api_key = keyring.get_password("mcp-server", "api_key")
except ImportError:
pass
if not api_key:
raise ValueError("API key not found in any configuration source")
return {"api_key": api_key}
2. 입력 정리 및 유효성 검사
주입 공격을 방지하기 위해 엄격한 입력 유효성 검사를 구현하십시오.
import re
from typing import Any, Dict
def sanitize_string_input(value: str, max_length: int = 100) -> str:
"""Sanitize string inputs"""
if not isinstance(value, str):
raise ValueError("Expected string input")
# Remove potentially dangerous characters
sanitized = re.sub(r'[<>"\\\\']', '', value)
# Limit length to prevent DoS
if len(sanitized) > max_length:
raise ValueError(f"Input too long (max {max_length} characters)")
return sanitized.strip()
def validate_city_name(city: str) -> str:
"""Validate city name input"""
sanitized = sanitize_string_input(city, 50)
# Allow only letters, spaces, and common punctuation
if not re.match(r'^[a-zA-Z\\\\s\\\\-\\\\.]+$', sanitized):
raise ValueError("Invalid city name format")
return sanitized
3. 속도 제한 및 리소스 보호
악용을 방지하기 위해 속도 제한을 구현하십시오.
import time
from collections import defaultdict
from threading import Lock
class RateLimiter:
def __init__(self, max_requests: int = 60, window_seconds: int = 60):
self.max_requests = max_requests
self.window_seconds = window_seconds
self.requests = defaultdict(list)
self.lock = Lock()
def allow_request(self, client_id: str = "default") -> bool:
"""Check if request is allowed under rate limit"""
now = time.time()
with self.lock:
# Clean old requests
self.requests[client_id] = [
req_time for req_time in self.requests[client_id]
if now - req_time < self.window_seconds
]
# Check limit
if len(self.requests[client_id]) >= self.max_requests:
return False
# Record this request
self.requests[client_id].append(now)
return True
# Global rate limiter instance
rate_limiter = RateLimiter()
고급 로깅 및 모니터링
구조화된 로깅 구현
더 나은 디버깅 및 모니터링을 위해 구조화된 로깅을 사용하십시오.
import logging
import json
import sys
from datetime import datetime
class MCPFormatter(logging.Formatter):
"""Custom formatter for MCP server logs"""
def format(self, record):
log_entry = {
"timestamp": datetime.utcnow().isoformat(),
"level": record.levelname,
"message": record.getMessage(),
"module": record.module,
"function": record.funcName,
}
# Add extra context if available
if hasattr(record, 'tool_name'):
log_entry["tool_name"] = record.tool_name
if hasattr(record, 'request_id'):
log_entry["request_id"] = record.request_id
return json.dumps(log_entry)
# Configure structured logging
logger = logging.getLogger(__name__)
handler = logging.StreamHandler(sys.stderr)
handler.setFormatter(MCPFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)
성능 모니터링
서버 성능 지표를 추적하십시오.
import time
import statistics
from collections import deque
class PerformanceMonitor:
def __init__(self, max_samples: int = 1000):
self.response_times = deque(maxlen=max_samples)
self.error_count = 0
self.request_count = 0
def record_request(self, duration: float, success: bool):
"""Record request metrics"""
self.request_count += 1
self.response_times.append(duration)
if not success:
self.error_count += 1
def get_stats(self) -> Dict[str, Any]:
"""Get current performance statistics"""
if not self.response_times:
return {"no_data": True}
return {
"total_requests": self.request_count,
"error_rate": self.error_count / self.request_count,
"avg_response_time": statistics.mean(self.response_times),
"p95_response_time": statistics.quantiles(self.response_times, n=20)[18],
"p99_response_time": statistics.quantiles(self.response_times, n=100)[98]
}
# Global performance monitor
perf_monitor = PerformanceMonitor()
배포 및 유지 관리 전략
버전 관리
MCP 서버에 대한 적절한 버전 관리를 구현하십시오.
__version__ = "1.2.3"
__mcp_version__ = "2024-11-05"
def get_server_info():
"""Return server information for MCP initialize"""
return {
"name": "my-production-server",
"version": __version__,
"mcp_protocol_version": __mcp_version__,
"capabilities": ["tools", "resources"], # Declare what you support
}
상태 확인 구현
모니터링을 위한 상태 확인 기능을 추가하십시오.
def handle_health_check(request_id: Any) -> Dict[str, Any]:
"""Health check endpoint for monitoring"""
try:
# Test core functionality
test_db_connection() # Example health check
test_external_apis() # Example health check
return {
"jsonrpc": "2.0",
"id": request_id,
"result": {
"status": "healthy",
"timestamp": datetime.utcnow().isoformat(),
"version": __version__,
"uptime_seconds": time.time() - start_time,
"performance": perf_monitor.get_stats()
}
}
except Exception as e:
return {
"jsonrpc": "2.0",
"id": request_id,
"result": {
"status": "unhealthy",
"error": str(e),
"timestamp": datetime.utcnow().isoformat()
}
}
정상 종료 처리
서버 종료 시 적절한 정리를 구현하십시오.
import signal
import sys
class MCPServer:
def __init__(self):
self.running = True
self.active_requests = set()
# Register signal handlers
signal.signal(signal.SIGINT, self.shutdown_handler)
signal.signal(signal.SIGTERM, self.shutdown_handler)
def shutdown_handler(self, signum, frame):
"""Handle graceful shutdown"""
logger.info(f"Received signal {signum}, initiating graceful shutdown")
self.running = False
# Wait for active requests to complete
timeout = 30 # seconds
start_time = time.time()
while self.active_requests and (time.time() - start_time) < timeout:
time.sleep(0.1)
logger.info("Shutdown complete")
sys.exit(0)
실제 사용 사례 및 고급 애플리케이션
엔터프라이즈 통합 패턴
MCP 서버는 Claude Code가 기존 비즈니스 시스템과 통합해야 하는 엔터프라이즈 환경에서 뛰어납니다. 입증된 통합 패턴은 다음과 같습니다.
데이터베이스 통합 서버
- 고객 데이터 조회: CRM 시스템에서 고객 정보 쿼리
- 재고 관리: 실시간 재고 수준 확인 및 업데이트
- 분석 대시보드: 비즈니스 인텔리전스 시스템에서 보고서 생성
- 감사 추적 생성: 규정 준수를 위한 AI 지원 결정 로깅
개발 워크플로우 자동화
- CI/CD 파이프라인 통합: 빌드, 배포 및 테스트 트리거
- 코드 품질 분석: SonarQube, ESLint 또는 사용자 지정 린터와 통합
- 문서 생성: 코드 주석에서 API 문서 자동 생성
- 이슈 추적: Jira/GitHub 이슈 생성, 업데이트 및 쿼리
시스템 모니터링 및 운영
- 인프라 모니터링: Prometheus, Grafana 또는 사용자 지정 메트릭 쿼리
- 로그 분석: 애플리케이션 로그 검색 및 분석
- 성능 최적화: 병목 현상 식별 및 개선 제안
- 보안 스캔: 취약점 스캐너 및 보안 도구와 통합
고급 아키텍처 패턴
다중 서버 오케스트레이션
복잡한 워크플로우의 경우 서로 협력하는 MCP 서버를 설계하십시오.
# Server coordination pattern
def coordinate_workflow(workflow_id: str, steps: List[Dict]) -> Dict:
"""Coordinate multi-step workflow across servers"""
results = {}
for step in steps:
server_name = step["server"]
tool_name = step["tool"]
params = step["params"]
# Call other MCP server through Claude Code
result = call_mcp_tool(server_name, tool_name, params)
results[step["id"]] = result
# Handle dependencies between steps
if step.get("depends_on"):
inject_dependencies(params, results, step["depends_on"])
return {"workflow_id": workflow_id, "results": results}
캐싱 및 성능 최적화
자주 요청되는 데이터에 대한 지능형 캐싱을 구현하십시오.
import hashlib
import pickle
from datetime import datetime, timedelta
class IntelligentCache:
def __init__(self, default_ttl: int = 3600):
self.cache = {}
self.default_ttl = default_ttl
def get_cache_key(self, tool_name: str, params: Dict) -> str:
"""Generate consistent cache key"""
key_data = f"{tool_name}:{json.dumps(params, sort_keys=True)}"
return hashlib.md5(key_data.encode()).hexdigest()
def get(self, tool_name: str, params: Dict) -> Optional[Any]:
"""Get cached result if valid"""
key = self.get_cache_key(tool_name, params)
if key in self.cache:
data, expiry = self.cache[key]
if datetime.now() < expiry:
return data
else:
del self.cache[key]
return None
def set(self, tool_name: str, params: Dict, result: Any, ttl: Optional[int] = None):
"""Cache result with TTL"""
key = self.get_cache_key(tool_name, params)
expiry = datetime.now() + timedelta(seconds=ttl or self.default_ttl)
self.cache[key] = (result, expiry)
프로덕션 배포 전략
컨테이너화된 배포
일관된 배포를 위해 MCP 서버를 Docker 컨테이너로 패키징하십시오.
FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \\\\
curl \\\\
&& rm -rf /var/lib/apt/lists/*
# Copy and install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY server.py .
COPY config/ ./config/
# Create non-root user
RUN useradd -m -s /bin/bash mcpuser
USER mcpuser
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\\\
CMD python3 -c "import requests; requests.get('<http://localhost:8080/health>')"
CMD ["python3", "server.py"]
Kubernetes 배포
확장성 및 안정성을 위해 Kubernetes에 MCP 서버를 배포하십시오.
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-weather-server
spec:
replicas: 3
selector:
matchLabels:
app: mcp-weather-server
template:
metadata:
labels:
app: mcp-weather-server
spec:
containers:
- name: mcp-server
image: your-registry/mcp-weather-server:latest
ports:
- containerPort: 8080
env:
- name: OPENWEATHER_API_KEY
valueFrom:
secretKeyRef:
name: mcp-secrets
key: openweather-api-key
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
확장 및 성능 고려 사항
수평 확장 패턴
수평 확장을 지원하도록 MCP 서버를 설계하십시오.
- 무상태 설계: 서버를 무상태로 유지하여 쉬운 복제 가능
- 로드 밸런싱: 여러 서버 인스턴스에 요청 분산
- 데이터베이스 풀링: 데이터베이스 지원 서버에 연결 풀링 사용
- 캐싱 전략: 공유 캐싱을 위해 Redis 또는 Memcached 구현
성능 최적화 기술
import asyncio
import aiohttp
from concurrent.futures import ThreadPoolExecutor
class HighPerformanceMCPServer:
def __init__(self):
self.executor = ThreadPoolExecutor(max_workers=10)
self.session = None
async def async_tool_call(self, tool_name: str, params: Dict) -> Dict:
"""Handle tool calls asynchronously"""
if not self.session:
self.session = aiohttp.ClientSession()
# Use async operations for I/O bound tasks
if tool_name == "web_search":
return await self.async_web_search(params)
elif tool_name == "database_query":
return await self.async_database_query(params)
else:
# Use thread pool for CPU-bound tasks
loop = asyncio.get_event_loop()
return await loop.run_in_executor(
self.executor,
self.sync_tool_call,
tool_name,
params
)
결론 및 다음 단계
MCP 개발 마스터하기
Claude Code를 위한 MCP 서버 구축은 AI 애플리케이션 개발의 패러다임 전환을 나타냅니다. 하드코딩된 연결이 필요한 전통적인 API 통합과 달리, MCP는 AI 어시스턴트를 진정으로 확장 가능하게 만드는 동적이고 발견 가능한 인터페이스를 제공합니다.
이 종합 가이드를 통해 다음을 학습했습니다.
기초 기술:
- MCP 프로토콜 기본 사항 및 아키텍처 패턴
- 안정적인 배포를 위한 중요한 구성 스코프 관리
- 기본부터 고급까지 단계별 서버 구현
프로덕션 준비:
- 포괄적인 오류 처리 및 유효성 검사 전략
- 비밀 관리 및 입력 정리를 포함한 보안 프레임워크
- 성능 모니터링 및 최적화 기술
고급 기능:
- 다중 서버 오케스트레이션 및 워크플로우 조정
- 캐싱 전략 및 수평 확장 패턴
- 엔터프라이즈 통합 및 배포 방법론
전략적 개발 접근 방식
단계 1: 기반 구축 (1-2주차)
프로토콜을 이해하기 위해 간단하고 단일 목적의 서버부터 시작하십시오.
- 파일 시스템 유틸리티 (파일 목록, 읽기, 쓰기)
- 기본 API 통합 (날씨, 뉴스, 계산기)
- 시스템 정보 도구 (디스크 공간, 프로세스 모니터링)
단계 2: 통합 확장 (3-4주차)
기존 시스템과 통합하는 더 복잡한 서버를 구축하십시오.
- 애플리케이션을 위한 데이터베이스 쿼리 인터페이스
- 개발 도구 통합 (git, CI/CD, 테스트 프레임워크)
- 통신 도구 (이메일, Slack, 알림 시스템)
단계 3: 엔터프라이즈 배포 (2개월차 이상)
완전한 운영 지원을 통해 프로덕션 준비 서버를 배포하십시오.
- 상태 확인을 포함한 컨테이너화된 배포
- 모니터링 및 알림 통합
- 보안 강화 및 규정 준수 기능
- 다중 팀 협업 및 서버 공유
장기적인 성공 전략
커뮤니티 참여
- 오픈 소스 기여: MCP 커뮤니티와 서버 공유
- 다른 사람에게 배우기: 모범 사례를 위해 기존 서버 구현 연구
- 최신 정보 유지: MCP 프로토콜 발전 및 새로운 기능 추적
지속적인 개선
- 성능 모니터링: 서버 메트릭 추적 및 병목 현상 최적화
- 피드백 수집: 사용자 피드백 수집 및 기능 반복
- 보안 업데이트: 종속성 및 보안 관행 정기 업데이트
혁신 기회
- AI 모델 통합: Claude Code를 전문 AI 모델에 연결
- 산업별 도구: 도메인 전문 지식을 위한 서버 구축
- 워크플로우 자동화: 복잡한 비즈니스 프로세스를 자동화하는 서버 생성
MCP 개발의 미래
모델 컨텍스트 프로토콜은 AI 통합 애플리케이션의 새로운 생태계를 위한 기반을 나타냅니다. MCP 서버를 구축할 때 Claude Code를 위한 도구를 만드는 것뿐만 아니라 MCP 호환 AI 어시스턴트의 확장되는 생태계에서 작동할 재사용 가능한 구성 요소를 구축하는 것입니다.
MCP 개발에 대한 투자는 다음을 통해 이점을 얻습니다.
- 프로토콜 표준화: 다른 AI 플랫폼에서 도구 작동
- 커뮤니티 활용: 공유 라이브러리 및 모범 사례 활용
- 향후 호환성: 새로운 AI 어시스턴트가 서버를 즉시 사용 가능
중요 성공 알림
MCP 개발 여정을 시작할 때 다음 필수 원칙을 기억하십시오.
- 구성 스코프 숙달: 프로젝트 수준 제한이 특별히 필요하지 않는 한 개발 서버에는 항상
--scope user
를 사용하십시오. - 보안 우선: 절대 비밀을 하드코딩하지 말고, 항상 입력 유효성을 검사하고, 속도 제한을 구현하십시오.
- 오류 처리 완전성: 모든 실패 모드를 예상하고 정상적으로 처리하십시오.
- 철저한 테스트: 프로토콜 준수, 기능 및 통합을 테스트하십시오.
- 문서 품질: 팀 협업 및 유지 관리를 위해 서버를 문서화하십시오.
도움 및 리소스 얻기
어려움에 직면했을 때:
- 공식 MCP 문서: 최신 프로토콜 사양 참조
- 커뮤니티 포럼: 문제 해결을 위해 다른 MCP 개발자와 교류
- GitHub 저장소: 오픈 소스 MCP 서버 구현 연구
- Claude Code 로그: 연결 및 실행 문제 디버깅을 위해 서버 로그 사용
오늘부터 구축을 시작하고 빠르게 반복하며 모델 컨텍스트 프로토콜을 통해 AI 기능을 확장하는 개발자 커뮤니티에 참여하십시오. 사용자 지정 MCP 서버는 우리가 상상하기 시작한 AI 지원 워크플로우를 위한 새로운 가능성을 열어줄 것입니다.
기억하십시오: 모든 복잡한 통합은 간단한 "Hello World" 서버로 시작되었습니다. 기본부터 시작하여 기본 사항을 마스터하고 작업 방식을 변화시킬 AI 통합 도구를 점진적으로 구축하십시오.
최대 생산성으로 개발팀이 함께 작업할 수 있는 통합 올인원 플랫폼을 원하시나요?
Apidog는 귀하의 모든 요구 사항을 충족하며, 훨씬 저렴한 가격으로 Postman을 대체합니다!