**Model Context Protocol (MCP)**은 Anthropic이 만든 오픈 표준으로, AI 모델이 외부 도구, 데이터 소스, 서비스와 어떻게 통신하는지를 정의합니다. 이것을 "AI의 USB-C"라고 생각하세요 - 표준화된 인터페이스를 통해 어떤 AI 에이전트든 어떤 도구와든 통신할 수 있게 해주는 범용 커넥터입니다.
출시 이후 MCP는 월간 SDK 다운로드 9,700만 회를 돌파했으며, 모든 주요 AI 제공업체가 채택했습니다: Anthropic, OpenAI, Google, Microsoft, Amazon. 이 가이드에서는 MCP로 구축하기 위해 알아야 할 모든 것을 살펴봅니다.
MCP가 존재하는 이유
MCP 이전에는 모든 AI 애플리케이션이 사용하려는 각 도구에 대해 커스텀 통합을 구축해야 했습니다. AI가 파일을 읽게 하고 싶나요? 커스텀 코드를 작성하세요. 데이터베이스를 쿼리하나요? 더 많은 커스텀 코드. Slack에 게시하나요? 또 다른 통합.
이것은 N×M 문제를 만들었습니다: N개의 AI 애플리케이션이 각각 M개의 커스텀 통합을 필요로 하여 중복 노력과 파편화된 에코시스템으로 이어졌습니다.
MCP는 어떤 AI 클라이언트든 어떤 MCP 서버와든 통신할 수 있는 단일 프로토콜로 이를 해결합니다:
핵심 개념
MCP에는 세 가지 기본 프리미티브가 있습니다:
1. 도구 (Tools)
도구는 AI가 호출할 수 있는 함수입니다. "파일 생성", "데이터베이스 쿼리", "메시지 전송"과 같은 작업을 나타냅니다. 각 도구에는 이름, 설명, 매개변수에 대한 JSON Schema가 있습니다.
{ name: "create_issue", description: "Create a new GitHub issue", inputSchema: { type: "object", properties: { title: { type: "string", description: "Issue title" }, body: { type: "string", description: "Issue body" }, repo: { type: "string", description: "Repository name" } }, required: ["title", "repo"] } }
2. 리소스 (Resources)
리소스는 AI가 읽을 수 있는 데이터입니다. 파일, 데이터베이스 레코드, API 응답 또는 기타 데이터 소스를 나타냅니다. 리소스는 URI로 식별됩니다.
{ uri: "file:///Users/dev/project/README.md", name: "Project README", mimeType: "text/markdown" }
3. 프롬프트 (Prompts)
프롬프트는 상호작용을 구조화하는 데 도움이 되는 재사용 가능한 템플릿입니다. 동적 매개변수를 포함할 수 있으며 일반적인 워크플로우를 표준화하는 데 유용합니다.
{ name: "code_review", description: "Review code changes for quality and security", arguments: [ { name: "diff", description: "The code diff to review", required: true } ] }
아키텍처
MCP는 클라이언트-서버 아키텍처를 따릅니다:
- 호스트: AI 애플리케이션 (Claude Desktop, Cursor, 커스텀 앱)
- 클라이언트: MCP 서버와 1:1 연결을 유지
- 서버: 클라이언트에 도구, 리소스, 프롬프트를 노출
- 전송: stdio(로컬) 또는 Server-Sent Events(원격)을 통한 JSON-RPC 2.0으로 통신
MCP 서버 구축
JSON 파일에 저장된 할 일 목록과 상호작용하는 실용적인 MCP 서버를 구축해 봅시다.
설정
mkdir mcp-todo-server && cd mcp-todo-server npm init -y npm install @modelcontextprotocol/sdk zod
서버 구현
// src/index.ts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import fs from "fs"; const TODO_FILE = "./todos.json"; function readTodos(): { id: number; text: string; done: boolean }[] { if (!fs.existsSync(TODO_FILE)) return []; return JSON.parse(fs.readFileSync(TODO_FILE, "utf-8")); } function writeTodos(todos: { id: number; text: string; done: boolean }[]) { fs.writeFileSync(TODO_FILE, JSON.stringify(todos, null, 2)); } const server = new McpServer({ name: "todo-server", version: "1.0.0", }); // Tool: Add a todo server.tool( "add_todo", "Add a new todo item", { text: z.string().describe("The todo text") }, async ({ text }) => { const todos = readTodos(); const newTodo = { id: Date.now(), text, done: false }; todos.push(newTodo); writeTodos(todos); return { content: [{ type: "text", text: `Added: "${text}"` }] }; } ); // Tool: List todos server.tool( "list_todos", "List all todo items", {}, async () => { const todos = readTodos(); const list = todos .map((t) => `${t.done ? "✅" : "⬜"} [${t.id}] ${t.text}`) .join("\n"); return { content: [{ type: "text", text: list || "No todos yet." }] }; } ); // Tool: Complete a todo server.tool( "complete_todo", "Mark a todo as completed", { id: z.number().describe("The todo ID to complete") }, async ({ id }) => { const todos = readTodos(); const todo = todos.find((t) => t.id === id); if (!todo) return { content: [{ type: "text", text: "Todo not found." }] }; todo.done = true; writeTodos(todos); return { content: [{ type: "text", text: `Completed: "${todo.text}"` }] }; } ); // Resource: Current todos as a readable resource server.resource( "todos://list", "Current todo list", async () => ({ contents: [{ uri: "todos://list", mimeType: "application/json", text: JSON.stringify(readTodos(), null, 2), }], }) ); // Start the server const transport = new StdioServerTransport(); await server.connect(transport);
설정
이 서버를 Claude Desktop에서 사용하려면 설정에 추가하세요:
{ "mcpServers": { "todo": { "command": "npx", "args": ["tsx", "/path/to/mcp-todo-server/src/index.ts"] } } }
MCP 클라이언트 구축
어떤 MCP 서버에든 연결하는 커스텀 클라이언트도 구축할 수 있습니다:
import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; const transport = new StdioClientTransport({ command: "npx", args: ["tsx", "./src/index.ts"], }); const client = new Client({ name: "my-client", version: "1.0.0" }); await client.connect(transport); // List available tools const { tools } = await client.listTools(); console.log("Available tools:", tools.map((t) => t.name)); // Call a tool const result = await client.callTool({ name: "add_todo", arguments: { text: "Write MCP blog post" }, }); console.log(result);
인기 MCP 서버
MCP 에코시스템은 빠르게 성장했습니다. 가장 인기 있는 서버들을 소개합니다:
| 서버 | 설명 | 사용 사례 |
|---|---|---|
| GitHub | Issue, PR 생성, 저장소 관리 | 개발 워크플로우 |
| Slack | 메시지 전송, 채널 관리 | 팀 커뮤니케이션 |
| PostgreSQL | 데이터베이스 쿼리 및 관리 | 데이터 접근 |
| Filesystem | 파일 읽기, 쓰기, 검색 | 로컬 개발 |
| Puppeteer | 브라우저 자동화 및 스크래핑 | 웹 테스트 |
| Sentry | 오류 모니터링 및 디버깅 | 프로덕션 지원 |
| Supabase | 데이터베이스, 인증, 스토리지 | 백엔드 운영 |
MCP vs A2A (Agent-to-Agent)
MCP가 에이전트-도구 통신을 처리하는 반면, Google의 A2A (Agent-to-Agent) 프로토콜은 에이전트-에이전트 통신을 처리합니다. 이 둘은 상호보완적입니다:
- MCP: AI 에이전트가 도구를 사용하는 방법 (수직 통합)
- A2A: AI 에이전트들이 서로 협업하는 방법 (수평 통합)
모범 사례
- 서버를 집중적으로 유지하세요: 도메인당 하나의 서버 (GitHub 서버, Slack 서버 등). 모놀리식 서버를 구축하지 마세요.
- Zod로 입력을 검증하세요: 항상 적절한 스키마로 도구 입력을 검증하세요.
- 오류를 우아하게 처리하세요: 스택 트레이스가 아닌 의미 있는 오류 메시지를 반환하세요.
- 읽기 전용 데이터에는 리소스를 사용하세요: AI가 데이터만 읽으면 되는 경우, 도구가 아닌 리소스로 노출하세요.
- 적절한 설명을 추가하세요: 좋은 도구 및 매개변수 설명은 AI가 각 도구를 언제, 어떻게 사용할지 이해하는 데 도움이 됩니다.
- MCP Inspector로 테스트하세요:
npx @modelcontextprotocol/inspector를 사용하여 서버를 대화형으로 테스트하세요.
시작하기
# Create a new MCP server from template npx @modelcontextprotocol/create-server my-server # Test with the MCP Inspector npx @modelcontextprotocol/inspector npx tsx ./src/index.ts
결론
MCP는 2026년 AI 도구 사용의 사실상 표준이 되었습니다. 커스텀 AI 에이전트를 구축하든, Claude Code를 확장하든, 기존 플랫폼을 위한 통합을 만들든, MCP를 이해하는 것은 필수적입니다. 이 프로토콜은 하루 오후면 배울 수 있을 만큼 간단하지만 프로덕션 수준의 AI 워크플로우를 구축할 만큼 강력합니다.
다음 단계: