MCP(Model Context Protocol)๋ Anthropic์ด 2024๋ 11์์ ๋ฐํํ ์คํ ํ์ค ํ๋กํ ์ฝ๋ก, AI ์ ํ๋ฆฌ์ผ์ด์ (Claude, ChatGPT ๋ฑ)์ด ์ธ๋ถ ์์คํ (DB, ํ์ผ, API ๋ฑ)๊ณผ ํ์คํ๋ ๋ฐฉ์์ผ๋ก ์ฐ๊ฒฐํ ์ ์๊ฒ ํด์ค๋ค.
USB-C ํฌํธ ๋น์ : USB-C๊ฐ ์ ์๊ธฐ๊ธฐ๋ฅผ ์ฐ๊ฒฐํ๋ ํ์ค์ด๋ฏ, MCP๋ AI ์ฑ์ ์ธ๋ถ ์์คํ ์ ์ฐ๊ฒฐํ๋ ํ์ค์ด๋ค.
MCP Server๋ ์ด ํ๋กํ ์ฝ์์ ์ปจํ ์คํธ๋ฅผ ์ ๊ณตํ๋ ํ๋ก๊ทธ๋จ์ ์๋ฏธํ๋ค. ์ฆ, AI๊ฐ ์ฌ์ฉํ ์ ์๋ ๋๊ตฌ(tool)๋ ๋ฐ์ดํฐ(resource)๋ฅผ ๋ ธ์ถํ๋ ์๋ฒ ํ๋ก๊ทธ๋จ์ด๋ค.
ํด๋น ๊ฐ๋ ์ด ํ์ํ ์ด์
- AI ์ฑ์์ ์ธ๋ถ ๋ฐ์ดํฐ(DB, API ๋ฑ)์ ์ ๊ทผํ๋ ค๋ฉด ๊ฐ๊ฐ ์ปค์คํ ์ปค๋ฅํฐ๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค (NรM ๋ฌธ์ )
- MCP๋ฅผ ์ฌ์ฉํ๋ฉด ํ๋์ ํ์ค ์ธํฐํ์ด์ค๋ก ๋ชจ๋ AI ์ฑ์ด ๋์ผํ ์๋ฒ์ ์ ์ ๊ฐ๋ฅ
- Claude Code, Codex CLI ๋ฑ์์ ๋ด DB์ Todo ๋ฐ์ดํฐ๋ฅผ ์ง์ ์กฐํ/์์ฑํ ์ ์๋ค
AS-IS
sequenceDiagram autonumber participant CC as Claude Code participant API as Custom API participant DB as Database CC->>API: ์ง์ HTTP ํธ์ถ (์ปค์คํ ์ฝ๋ ํ์) API->>DB: SQL ์ฟผ๋ฆฌ DB-->>API: ๊ฒฐ๊ณผ ๋ฐํ API-->>CC: JSON ์๋ต Note over CC,DB: ๊ฐ AI ์ฑ๋ง๋ค ๋ณ๋ ์ฐ๋ ์ฝ๋ ํ์<br/>(NรM ๋ฌธ์ )
TO-BE
sequenceDiagram autonumber participant CC as Claude Code participant MC as MCP Client participant MS as MCP Server participant DB as DB CC->>MC: "Todo ๋ชฉ๋ก ๋ณด์ฌ์ค" MC->>MS: tools/call: getTodos (JSON-RPC) MS->>DB: getTodos (DB) DB-->>MS: Todo[] MS-->>MC: content: [{type: "text", text: "..."}] MC-->>CC: ์์ฐ์ด ์๋ต ์์ฑ Note over CC,DB: ํ์ค ํ๋กํ ์ฝ๋ก ์ด๋ค AI ์ฑ์ด๋ <br/>๋์ผํ MCP Server ์ฌ์ฌ์ฉ
MCP ์ํคํ ์ฒ: 3๊ฐ์ง ์ฐธ์ฌ์
| ์ฐธ์ฌ์ | ์ญํ | ์์ |
|---|---|---|
| MCP Host | AI ์ฑ, MCP Client๋ฅผ ๊ด๋ฆฌ | Claude Code, Claude Desktop, VS Code |
| MCP Client | MCP Server์ 1:1 ์ฐ๊ฒฐ ์ ์ง | Host ๋ด๋ถ์์ ์๋ ์์ฑ๋จ |
| MCP Server | ์ปจํ ์คํธ(Tool, Resource)๋ฅผ ์ ๊ณต | Prisma Todo ์๋ฒ |
graph TB subgraph "MCP Host (Claude Code)" Client1["MCP Client 1"] Client2["MCP Client 2"] end ServerA["MCP Server A<br/>(Todo - Prisma)"] ServerB["MCP Server B<br/>(ํ์ผ์์คํ )"] Client1 ---|"STDIO"| ServerA Client2 ---|"STDIO"| ServerB
MCP์ 2๊ฐ์ง ๋ ์ด์ด
Data Layer (JSON-RPC 2.0)
ํด๋ผ์ด์ธํธ-์๋ฒ ๊ฐ ๋ฉ์์ง ๊ตฌ์กฐ์ ์๋ฏธ๋ฅผ ์ ์ํ๋ค.
- Lifecycle: ์ฐ๊ฒฐ ์ด๊ธฐํ โ ๊ธฐ๋ฅ ํ์(capability negotiation) โ ์ข ๋ฃ
- Server Primitives: Tools, Resources, Prompts
- Client Primitives: Sampling, Elicitation, Logging
Transport Layer
ํต์ ์ฑ๋๊ณผ ์ธ์ฆ์ ๊ด๋ฆฌํ๋ค.
| Transport | ์ค๋ช | MCP ์๋ฒ ์์น | ์ฌ์ฉ ์์ |
|---|---|---|---|
| STDIO | stdin/stdout ์คํธ๋ฆผ | ๊ฐ์ ์ปดํจํฐ (๋ก์ปฌ) | ๋ก์ปฌ ํ๋ก์ธ์ค |
| Streamable HTTP | HTTP POST + SSE | ๋ค๋ฅธ ์ปดํจํฐ (์๊ฒฉ ์๋ฒ) | ์๊ฒฉ ์๋ฒ |
๋ ์ด์ด ์ดํด๋ฅผ ์ํ ๋น์
์ฐ์ฒด๊ตญ ์์คํ ์ ๋น์ :
| ๋ ์ด์ด | ์ญํ | ์ฐ์ฒด๊ตญ ๋น์ | ์ค์ MCP ์์ |
|---|---|---|---|
| Transport Layer | ์ด๋ค ์ด์ก ์๋จ? | ๐ ํ๋ฐฐ์ฐจ vs โ๏ธ ๋นํ๊ธฐ | STDIO vs HTTP |
| Data Layer | ํธ์ง ๋ด์ฉ๊ณผ ํ์ | ๐ ํธ์ง ํฌ๋งท (๋ฐ์ ์, ์์ ์, ๋ณธ๋ฌธ) | JSON-RPC ๋ฉ์์ง (tools/list, tools/call) |
์์:
- Transport Layer: โ์ด ํธ์ง๋ฅผ ํ๋ฐฐ์ฐจ(STDIO)๋ก ๋ณด๋ผ๊น, ๋นํ๊ธฐ(HTTP)๋ก ๋ณด๋ผ๊น?โ
- Data Layer: โํธ์ง์ ์ด๋ค ๋ด์ฉ(
tools/list์์ฒญ)์ ์ด๋ค ํ์(JSON-RPC)์ผ๋ก ์ ์๊น?โ
์ค์ ๋์:
sequenceDiagram autonumber participant Client as MCP Client participant Server as MCP Server Note over Client,Server: Transport Layer: STDIO๋ก ๋ฌผ๋ฆฌ์ ์ ์ก Client->>Server: {"method":"tools/list"} (Data Layer) Note over Server: JSON-RPC ๋ฉ์์ง ํด์ Server-->>Client: {"result":{"tools":[...]}} (Data Layer) Note over Client: ์๋ต ๋ฐ์ดํฐ ์ฒ๋ฆฌ
- Transport Layer: STDIO๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ๋ฌผ๋ฆฌ์ ์ผ๋ก ์ ์ก๋จ
- Data Layer: JSON-RPC ํ์์ ๋ฉ์์ง๊ฐ ์๋ฏธ์ ์ผ๋ก ํด์๋จ
3๋ Server Primitives (ํต์ฌ)
MCP Server๊ฐ ๋ ธ์ถํ ์ ์๋ 3๊ฐ์ง ํต์ฌ ์์:
1. Tools (๋๊ตฌ)
- AI๊ฐ ์คํ ๊ฐ๋ฅํ ํจ์ (e.g.
getTodos,createTodo) tools/list๋ก ๋ฐ๊ฒฌ,tools/call๋ก ์คํ- inputSchema๋ก ํ๋ผ๋ฏธํฐ ํ์ ์ ์ (JSON Schema)
2. Resources (๋ฆฌ์์ค)
- ์ฝ๊ธฐ ์ ์ฉ ๋ฐ์ดํฐ ์ ๊ณต (ํ์ผ ๋ด์ฉ, DB ์คํค๋ง ๋ฑ)
resources/list๋ก ๋ฐ๊ฒฌ,resources/read๋ก ์กฐํ
3. Prompts (ํ๋กฌํํธ)
- ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ํ ํ๋ฆฟ (์์คํ ํ๋กฌํํธ, few-shot ์์)
prompts/list๋ก ๋ฐ๊ฒฌ,prompts/get์ผ๋ก ์กฐํ
TypeScript๋ก MCP Server ๋ง๋๋ ๋ฐฉ๋ฒ
1. ํ๋ก์ ํธ ์ ์
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod@3
npm install -D @types/node typescript2. Tool ๋ฑ๋ก (ํต์ฌ ์ฝ๋ ํจํด)
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: "my-server",
version: "1.0.0",
});
// Tool ๋ฑ๋ก
server.registerTool(
"getTodos",
{
description: "Get all todos from the database",
inputSchema: {}, // ํ๋ผ๋ฏธํฐ ์์
},
async () => {
// Prisma๋ก DB ์กฐํ
const todos = await prisma.todo.findMany();
return {
content: [{ type: "text", text: JSON.stringify(todos) }],
};
}
);
// ์๋ฒ ์์ (STDIO transport)
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main();3. Claude Code์ ๋ฑ๋ก
~/.claude/settings.json:
{
"mcpServers": {
"todo-server": {
"command": "node",
"args": ["/absolute/path/to/build/index.js"]
}
}
}ํ๋กํ ์ฝ ํต์ ํ๋ฆ (์ค์ JSON-RPC ๋ฉ์์ง)
sequenceDiagram autonumber participant Client as MCP Client participant Server as MCP Server Note over Client,Server: 1. ์ด๊ธฐํ (Lifecycle) Client->>Server: initialize {protocolVersion, capabilities} Server-->>Client: {capabilities: {tools: {}}} Client->>Server: notifications/initialized Note over Client,Server: 2. ๋๊ตฌ ๋ฐ๊ฒฌ (Discovery) Client->>Server: tools/list Server-->>Client: {tools: [{name: "getTodos", ...}]} Note over Client,Server: 3. ๋๊ตฌ ์คํ (Execution) Client->>Server: tools/call {name: "getTodos"} Server-->>Client: {content: [{type: "text", text: "[...]"}]}
STDIO Transport
STDIO(Standard Input/Output) Transport๋ ๊ฐ์ ๋จธ์ ์์ ์คํ๋๋ ๋ ํ๋ก์ธ์ค ๊ฐ ํต์ ๋ฐฉ์์ด๋ค.
ํต์ฌ ์๋ฆฌ:
- ๋ถ๋ชจ ํ๋ก์ธ์ค(Claude Code)๊ฐ ์์ ํ๋ก์ธ์ค(MCP Server)๋ฅผ
spawn - ๋ถ๋ชจ โ ์์: stdin์ผ๋ก JSON-RPC ๋ฉ์์ง ์ ์ก
- ์์ โ ๋ถ๋ชจ: stdout์ผ๋ก JSON-RPC ์๋ต ์ ์ก
์ console.log() ๊ธ์ง์ธ๊ฐ:
- stdout์ JSON-RPC ๋ฉ์์ง ์ ์ฉ ์ฑ๋
console.log("hello")๊ฐ stdout์ ์ฐ์ด๋ฉด โ ํด๋ผ์ด์ธํธ๊ฐ"hello"๋ฅผ JSON-RPC๋ก ํ์ฑ ์๋ โ ํ์ฑ ์๋ฌ๋ก ์๋ฒ ํฌ๋์- ๋๋ฒ๊น
๋ก๊ทธ๋ ๋ฐ๋์
console.error()(stderr)๋ก ์ถ๋ ฅ
STDIO vs HTTP ๋น๊ต:
| STDIO | Streamable HTTP | |
|---|---|---|
| ์คํ ์์น | ๋ก์ปฌ (๊ฐ์ ๋จธ์ ) | ์๊ฒฉ ๊ฐ๋ฅ |
| ์ฐ๊ฒฐ ๋ฐฉ์ | ํ๋ก์ธ์ค spawn | HTTP ์์ฒญ |
| ํด๋ผ์ด์ธํธ ์ | 1:1 | 1:N |
| ๋คํธ์ํฌ ์ค๋ฒํค๋ | ์์ | ์์ |