MCP 서버 개발하기
Python과 TypeScript로 MCP 서버 구축하기
MCP 서버 개발 완벽 가이드
Model Context Protocol(MCP) 서버를 직접 개발하여 AI에 커스텀 기능을 제공하는 방법을 알아봅니다.
MCP 서버란?
MCP 서버는 AI 모델(Claude 등)에게 외부 도구, 리소스, 프롬프트를 제공하는 서비스입니다. AI는 이 서버를 통해 실시간 데이터 접근, 외부 API 호출, 파일 시스템 접근 등을 수행할 수 있습니다.
Python MCP 서버
설치
pip install mcp
기본 서버 구조
from mcp.server import Server
from mcp.types import Tool, TextContent
import mcp.server.stdio
# 서버 인스턴스 생성
server = Server("my-mcp-server")
# 도구 정의
@server.list_tools()
async def list_tools():
return [
Tool(
name="get_weather",
description="지정된 도시의 현재 날씨를 가져옵니다",
inputSchema={
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "도시 이름"
}
},
"required": ["city"]
}
),
Tool(
name="search_database",
description="데이터베이스에서 정보를 검색합니다",
inputSchema={
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "검색 쿼리"
},
"limit": {
"type": "number",
"description": "결과 개수",
"default": 10
}
},
"required": ["query"]
}
)
]
# 도구 실행
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "get_weather":
city = arguments["city"]
# 실제 날씨 API 호출
weather_data = await fetch_weather(city)
return [TextContent(
type="text",
text=f"{city}의 날씨: {weather_data['temp']}°C, {weather_data['condition']}"
)]
elif name == "search_database":
query = arguments["query"]
limit = arguments.get("limit", 10)
results = await search_db(query, limit)
return [TextContent(
type="text",
text=format_results(results)
)]
# 서버 실행
async def main():
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
server.create_initialization_options()
)
if __name__ == "__main__":
import asyncio
asyncio.run(main())
TypeScript MCP 서버
설치
npm install @modelcontextprotocol/sdk
기본 서버 구조
import { Server } from "@modelcontextprotocol/sdk/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types";
const server = new Server(
{ name: "my-mcp-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// 도구 목록
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "calculate",
description: "수학 계산을 수행합니다",
inputSchema: {
type: "object",
properties: {
expression: {
type: "string",
description: "계산할 수식"
}
},
required: ["expression"]
}
}
]
}));
// 도구 실행
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "calculate") {
const result = eval(args.expression);
return {
content: [{ type: "text", text: String(result) }]
};
}
throw new Error(`Unknown tool: ${name}`);
});
// 서버 시작
const transport = new StdioServerTransport();
await server.connect(transport);
리소스 제공
@server.list_resources()
async def list_resources():
return [
Resource(
uri="file:///config/settings.json",
name="설정 파일",
mimeType="application/json"
),
Resource(
uri="db://users",
name="사용자 데이터",
mimeType="application/json"
)
]
@server.read_resource()
async def read_resource(uri: str):
if uri == "file:///config/settings.json":
with open("/config/settings.json") as f:
return f.read()
elif uri == "db://users":
users = await get_all_users()
return json.dumps(users)
프롬프트 템플릿
@server.list_prompts()
async def list_prompts():
return [
Prompt(
name="code_review",
description="코드 리뷰를 수행합니다",
arguments=[
PromptArgument(
name="code",
description="리뷰할 코드",
required=True
),
PromptArgument(
name="language",
description="프로그래밍 언어",
required=False
)
]
)
]
@server.get_prompt()
async def get_prompt(name: str, arguments: dict):
if name == "code_review":
code = arguments["code"]
language = arguments.get("language", "")
return GetPromptResult(
messages=[
PromptMessage(
role="user",
content=TextContent(
type="text",
text=f"다음 {language} 코드를 리뷰해주세요:\n\n{code}"
)
)
]
)
Claude Desktop 연동
claude_desktop_config.json에 서버 등록:
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/path/to/server.py"],
"env": {
"API_KEY": "your-api-key"
}
}
}
}