MCP 프로토콜
MCP (Model Context Protocol)는 AI 모델과 외부 시스템 간의 표준화된 통신 프로토콜입니다. JSON-RPC 2.0 기반으로 도구 호출, 리소스 접근, 프롬프트 템플릿을 정의합니다. 프로토콜을 이해하면 커스텀 MCP 서버를 효과적으로 개발할 수 있습니다.
text
# MCP 프로토콜 기본 구조
## 1. 초기화 (Initialize)
Client → Server: {"jsonrpc": "2.0", "method": "initialize", ...}
Server → Client: {"capabilities": {...}, "serverInfo": {...}}
## 2. 도구 목록 요청
Client → Server: {"method": "tools/list"}
Server → Client: {"tools": [{name, description, inputSchema}, ...]}
## 3. 도구 실행
Client → Server: {"method": "tools/call", "params": {name, arguments}}
Server → Client: {"content": [...], "isError": false}
## 4. 리소스 접근
Client → Server: {"method": "resources/read", "params": {uri}}
Server → Client: {"contents": [...]}json
// 도구 정의 스키마 (JSON Schema)
{
"name": "query_database",
"description": "Execute SQL query",
"inputSchema": {
"type": "object",
"properties": {
"sql": {
"type": "string",
"description": "SQL query to execute"
},
"params": {
"type": "array",
"description": "Query parameters"
}
},
"required": ["sql"]
}
}- 표준 프로토콜 - JSON-RPC 2.0 기반
- 타입 안전 - JSON Schema 검증
- 양방향 통신 - 요청/응답 패턴
- 확장 가능 - 커스텀 메서드 정의
서버 구조 설계
커스텀 MCP 서버를 만들려면 프로젝트 구조를 올바르게 설계해야 합니다. TypeScript나 Python으로 구현할 수 있으며, 각 언어별 SDK가 제공됩니다.
bash
# TypeScript MCP 서버 구조
my-mcp-server/
├── package.json
├── tsconfig.json
├── src/
│ ├── index.ts # 서버 엔트리포인트
│ ├── tools/ # 도구 구현
│ │ ├── query.ts
│ │ └── analyze.ts
│ ├── resources/ # 리소스 구현
│ │ └── database.ts
│ └── types.ts # 타입 정의
├── tests/
│ └── tools.test.ts
└── README.md
# 초기 설정
npm init -y
npm install @modelcontextprotocol/sdk
npm install -D typescript @types/nodetypescript
// src/index.ts - MCP 서버 기본 구조
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
const server = new Server(
{ name: 'my-custom-server', version: '1.0.0' },
{ capabilities: { tools: {} } }
);
// 도구 목록 제공
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'query_data',
description: 'Query the database',
inputSchema: {
type: 'object',
properties: {
sql: { type: 'string' }
},
required: ['sql']
}
}
]
}));
// 도구 실행
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === 'query_data') {
const result = await executeQuery(request.params.arguments.sql);
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
}
throw new Error('Unknown tool');
});
// 서버 시작
const transport = new StdioServerTransport();
await server.connect(transport);- SDK 제공 - TypeScript/Python SDK
- 모듈화 - 도구별 분리 구현
- 타입 안전 - TypeScript 타입 시스템
- 테스트 가능 - 단위 테스트 지원
도구 구현
MCP 도구는 Claude가 호출할 수 있는 함수입니다. 입력 검증, 비즈니스 로직 실행, 결과 반환의 3단계로 구성됩니다.
typescript
// 도구 구현 예제: 데이터베이스 쿼리
import { z } from 'zod';
// 1. 입력 스키마 정의
const QuerySchema = z.object({
sql: z.string(),
params: z.array(z.any()).optional()
});
// 2. 도구 함수 구현
async function queryDatabase(args: unknown) {
// 입력 검증
const { sql, params } = QuerySchema.parse(args);
// 비즈니스 로직
try {
const result = await db.query(sql, params);
// 성공 응답
return {
content: [{
type: 'text',
text: JSON.stringify(result, null, 2)
}],
isError: false
};
} catch (error) {
// 에러 응답
return {
content: [{
type: 'text',
text: `Error: ${error.message}`
}],
isError: true
};
}
}
// 3. 서버에 등록
server.setRequestHandler(CallToolRequestSchema, async (request) => {
switch (request.params.name) {
case 'query_database':
return await queryDatabase(request.params.arguments);
default:
throw new Error(`Unknown tool: ${request.params.name}`);
}
});- 입력 검증 - Zod 스키마로 타입 체크
- 에러 처리 - 명확한 에러 메시지
- 비동기 지원 - async/await 패턴
- 구조화된 응답 - 일관된 응답 형식
리소스 구현
MCP 리소스는 읽기 가능한 데이터 소스입니다. 파일, 데이터베이스 레코드, API 응답 등을 리소스로 노출할 수 있습니다.
typescript
// 리소스 구현 예제
import { ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
// 1. 리소스 목록 제공
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [
{
uri: 'mydb://tables',
name: 'Database Tables',
mimeType: 'application/json',
description: 'List of all database tables'
},
{
uri: 'mydb://schema/{table}',
name: 'Table Schema',
mimeType: 'application/json',
description: 'Schema for a specific table'
}
]
}));
// 2. 리소스 읽기 구현
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const uri = request.params.uri;
if (uri === 'mydb://tables') {
const tables = await db.query('SHOW TABLES');
return {
contents: [{
uri: uri,
mimeType: 'application/json',
text: JSON.stringify(tables, null, 2)
}]
};
}
if (uri.startsWith('mydb://schema/')) {
const tableName = uri.split('/').pop();
const schema = await db.query(`DESCRIBE ${tableName}`);
return {
contents: [{
uri: uri,
mimeType: 'application/json',
text: JSON.stringify(schema, null, 2)
}]
};
}
throw new Error('Resource not found');
});- URI 기반 - 표준 리소스 식별
- MIME 타입 - 콘텐츠 타입 지정
- 동적 생성 - 실시간 데이터 제공
- 템플릿 지원 - URI 패턴 매칭
테스트와 디버깅
MCP 서버는 일반 Node.js 애플리케이션처럼 테스트하고 디버깅할 수 있습니다. 단위 테스트로 도구 로직을 검증하고, 통합 테스트로 전체 흐름을 확인하세요.
typescript
// 단위 테스트 예제 (Jest)
import { queryDatabase } from '../src/tools/query';
describe('queryDatabase', () => {
it('should execute valid SQL', async () => {
const result = await queryDatabase({
sql: 'SELECT * FROM users LIMIT 1'
});
expect(result.isError).toBe(false);
expect(result.content[0].type).toBe('text');
});
it('should handle invalid SQL', async () => {
const result = await queryDatabase({
sql: 'INVALID SQL'
});
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('Error');
});
});
// MCP Inspector로 테스트
# MCP Inspector 실행
npx @modelcontextprotocol/inspector node dist/index.js
# 브라우저에서 http://localhost:5173 접속
# 도구 목록 확인, 도구 실행 테스트json
# 디버깅 팁
# 1. 로그 추가
console.error('[MCP Server] Tool called:', toolName);
# 2. VS Code 디버그 설정 (.vscode/launch.json)
{
"type": "node",
"request": "launch",
"name": "Debug MCP Server",
"program": "${workspaceFolder}/dist/index.js",
"console": "integratedTerminal"
}
# 3. Claude Code에서 디버그 모드 실행
CLAUDE_LOG_LEVEL=debug claude- 단위 테스트 - Jest/Vitest로 도구 검증
- MCP Inspector - GUI로 서버 테스트
- 디버깅 - VS Code 디버거 지원
- 로그 추적 - 상세 실행 로그
배포 및 공유
완성된 MCP 서버를 npm에 배포하거나 GitHub에 공유할 수 있습니다. 다른 개발자들이 쉽게 설치하고 사용할 수 있도록 문서와 예제를 제공하세요.
bash
# npm 배포 준비
## 1. package.json 설정
{
"name": "@yourorg/mcp-server-custom",
"version": "1.0.0",
"description": "Custom MCP server for ...",
"bin": {
"mcp-server-custom": "./dist/index.js"
},
"files": ["dist"],
"keywords": ["mcp", "claude", "server"],
"repository": "github:yourorg/mcp-server-custom"
}
## 2. 빌드
npm run build
## 3. npm 배포
npm publish --access public
## 4. 사용자 설치
npm install -g @yourorg/mcp-server-custommarkdown
# README.md 필수 내용
# MCP Server Custom
Custom MCP server for database operations.
## Installation
```bash
npm install -g @yourorg/mcp-server-custom
```
## Configuration
```json
{
"mcpServers": {
"custom": {
"command": "mcp-server-custom",
"args": ["postgresql://localhost/mydb"],
"env": {
"DB_PASSWORD": "${DB_PASSWORD}"
}
}
}
}
```
## Tools
- `query`: Execute SQL queries
- `analyze`: Analyze query performance
## Resources
- `db://tables`: List all tables
- `db://schema/{table}`: Get table schema- npm 배포 - 전역 패키지로 배포
- 버전 관리 - 시맨틱 버저닝
- 문서화 - 명확한 설치 가이드
- 예제 제공 - 실제 사용 사례
MCP 서버 디렉토리: 공식 MCP 서버 디렉토리에 등록하면 더 많은 사용자가 발견하고 사용할 수 있습니다. github.com/modelcontextprotocol/servers