Mini MCP Server Demo¶
从 3348 行的
src/services/mcp/client.ts提炼到 ~300 行的可运行 MCP server。 展示 MCP 协议 + stdio transport + 工具系统 的最小实现。
这是什么?¶
Claude Code 用 MCP (Model Context Protocol) 连接外部工具/资源。真实代码 3348 行,本 demo 用 ~300 行 实现一个能跑的 MCP server + client,让你能:
- 手写一个工具,跑通 MCP 协议
- 理解 JSON-RPC 2.0 在 MCP 里怎么用
- 看 stdio transport 的"newline-delimited JSON"实际是什么
- 给 CC 真接一个自己写的 MCP server
文件结构¶
mini-mcp-server/
├── src/
│ ├── server.ts ← MCP server 核心(~180 行)
│ ├── client.ts ← 测 server 用的 client(~120 行)
│ ├── transport/
│ │ └── stdio.ts ← NDJSON transport(~50 行)
│ └── tools/
│ ├── types.ts ← 工具类型定义
│ └── calculator.ts ← 示例工具(+ - × ÷)
├── package.json
├── tsconfig.json
└── README.md
怎么跑?¶
# 1. 装依赖
npm install
# 2. 编译
npm run build
# 3. 启动 client(自动 spawn server,跑 6 个测试)
npm run client
# 或单独跑 server(从 stdin 读 JSON-RPC)
npm start
# 然后手动输入:
# {"jsonrpc":"2.0","id":1,"method":"tools/list"}
# {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"calculator","arguments":{"operation":"add","a":1,"b":2}}}
真实代码对照表¶
| Demo 文件 | 真实文件 | 行数对比 | 简化了啥 |
|---|---|---|---|
src/server.ts |
src/services/mcp/client.ts |
180 vs 3348 | 去掉 3 种 transport(SSE/HTTP/WS)、auth、batching、cache、telemetry |
src/transport/stdio.ts |
src/services/mcp/StdioServerTransport.ts |
50 vs ~300 | 用 NDJSON 代替 Content-Length header |
src/client.ts |
真实 client 代码(被 CC 内部使用) | 120 vs ~1000 | 不做 reconnect、auth、capability negotiation 完整流程 |
src/tools/calculator.ts |
任何 MCP server 工具 | 50 vs ~200 | 简化 input validation(用 if 代替 zod/ajv) |
协议流程图¶
Client Server
│ │
│── initialize ────────────────────►│
│◄── {serverInfo, capabilities} ────│
│ │
│── notifications/initialized ─────►│
│ │
│── tools/list ────────────────────►│
│◄── {tools: [calculator, ...]} ────│
│ │
│── tools/call(name=calculator, ───►│
│ args={operation:"add",a:1,b:2}) │
│◄── {content:[{text:"1 + 2 = 3"}]} │
│ │
│── shutdown (or stdin close) ─────►│
│ │
核心设计 4 件套¶
1️⃣ JSON-RPC 2.0 消息结构¶
// Request(有 id,期望响应)
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }
// Notification(无 id,不期望响应)
{ "jsonrpc": "2.0", "method": "notifications/initialized" }
// Response
{ "jsonrpc": "2.0", "id": 1, "result": {...} }
// 或
{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32601, "message": "Method not found" } }
真实 MCP 用 Content-Length header(LSP 风格):
本 demo 简化为 NDJSON(每行一个 JSON),更易调试。
2️⃣ stdio transport = readline + stdout.write¶
// 读:process.stdin 按行解析 JSON
const rl = readline.createInterface({ input: process.stdin });
rl.on("line", (line) => {
const msg = JSON.parse(line);
handle(msg);
});
// 写:每条消息一个 JSON + \n
process.stdout.write(JSON.stringify(msg) + "\n");
关键约束: - server 写日志必须用 stderr(CC 也这么做),否则会污染 stdout 协议 - 不要 print debug,否则 client 解析失败
3️⃣ 工具系统 = Map + 验证¶
private tools = new Map<string, Tool>();
registerTool(tool: Tool) {
this.tools.set(tool.definition.name, tool);
}
async handleToolsCall(params) {
const tool = this.tools.get(params.name);
if (!tool) throw new ToolNotFoundError();
return await tool.execute(params.arguments);
}
真实代码:CC 用 zod/ajv 做严格 schema 验证,本 demo 用 TypeScript 类型 + if 简化。
4️⃣ 错误处理 = 标准 JSON-RPC 错误码¶
| Code | 含义 | 何时用 |
|---|---|---|
| -32700 | Parse error | JSON 解析失败 |
| -32600 | Invalid request | 消息格式不对 |
| -32601 | Method not found | 未实现的 method |
| -32602 | Invalid params | 参数缺失或类型错 |
| -32603 | Internal error | server 端异常 |
| -32000 | Tool not found | MCP 自定义 |
| -32001 | Tool exec failed | MCP 自定义 |
测试场景(npm run client 输出)¶
✅ initialize response: {...serverInfo, capabilities...}
✅ sent notifications/initialized
📋 tools/list: [calculator]
🔧 tools/call tests:
- add(1, 2) → 1 + 2 = 3
- subtract(10, 3) → 10 - 3 = 7
- multiply(7, 6) → 7 × 6 = 42
- divide(100, 4) → 100 ÷ 4 = 25
⚠️ error handling:
- divide by zero → isError=true, "Division by zero"
- nonexistent tool → code=-32000, "Tool not found"
进阶练习¶
- 加 SSE transport:除 stdio 外加一个 SSE transport(见 spec §3)
- 加 zod 验证:用 zod 验证
inputSchema,严格报错 - 加 resources:实现
resources/list+resources/read,返回文件内容 - 加 prompts:实现
prompts/list+prompts/get - 加 cancellation:实现
$/cancelRequest(JSON-RPC 取消机制) - 接 Claude Code:在
~/.claude/mcp.json加这个 server 路径,在 CC 里能调 calculator
相关阅读¶
- topics/mcp-protocol-deep-dive.md —— 真实 MCP 协议分析
- topics/deep-dive-mcp-client.md —— 3348 行 client 拆解
- topics/deep-dive-mcp-auth.md —— OAuth + PKCE
- tutorials/build-mcp-server.md —— 手把手教程
- walkthrough/build-an-mcp-server.md —— 练习答案
- MCP 官方协议规范