explain.md•9.17 kB
# MCP Server 開發完整指南
## 什麼是 Model Context Protocol (MCP)?
MCP 是一個開放協議,標準化了 AI 應用程式和大型語言模型如何連接到外部數據源和工具。它讓 AI 能夠:
- 調用外部工具(如計算器、API 調用)
- 讀取資源(文件、數據庫)
- 使用提示模板
## 核心概念
### MCP 架構
```mermaid
graph TB
AI[AI Client<br/>Claude Desktop]
MCP[MCP Protocol<br/>JSON-RPC over stdio]
Server[MCP Server<br/>Your Custom Tools]
AI <--> MCP
MCP <--> Server
subgraph "MCP Server Components"
Tools[Tools<br/>可調用函數]
Resources[Resources<br/>可讀取數據]
Prompts[Prompts<br/>模板]
end
Server --> Tools
Server --> Resources
Server --> Prompts
```
### 通信流程
```mermaid
sequenceDiagram
participant AI as AI Client
participant MCP as MCP Protocol
participant Server as MCP Server
AI->>MCP: 初始化連接
MCP->>Server: initialize request
Server->>MCP: capabilities response
MCP->>AI: 可用工具列表
AI->>MCP: 調用工具 "sum"
MCP->>Server: tool call with parameters
Server->>Server: 執行計算
Server->>MCP: 結果返回
MCP->>AI: 格式化結果
```
## 實作步驟
### 1. 項目初始化
```json
// package.json
{
"name": "basic-math-mcp-server",
"type": "module", // ✅ 使用 ES modules
"dependencies": {
"@modelcontextprotocol/sdk": "^1.12.1",
"zod": "^3.22.0" // ✅ 關鍵依賴
}
}
```
### 2. 基本服務器結構
```typescript
// ✅ 正確的 ES modules 導入方式
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: "basic-math-server",
version: "1.0.0"
}, {
capabilities: {
tools: {} // 聲明支持工具
}
});
```
### 3. 工具定義
```typescript
// ✅ 正確的工具定義
server.tool(
"sum", // 工具名稱
"Add two numbers together", // 描述
{ // 參數 schema (使用 zod)
a: z.number().describe("First number"),
b: z.number().describe("Second number")
},
async ({ a, b }: { a: number; b: number }) => { // 類型註解
const result = a + b;
return {
content: [
{
type: "text",
text: `The sum of ${a} and ${b} is: ${result}`
}
]
};
}
);
```
## 遇到的重要問題與解決
### 問題 1: 參數傳遞失敗 (NaN 結果)
**錯誤現象:**
```
The sum of undefined and undefined is: NaN
```
**原因分析:**
```mermaid
graph LR
A[AI 傳遞參數] --> B{參數 Schema 定義}
B -->|❌ 普通對象| C[參數解析失敗]
B -->|✅ Zod Schema| D[參數正確解析]
C --> E[undefined values]
D --> F[正確的數值]
```
**錯誤代碼:**
```typescript
// ❌ 錯誤:使用普通對象定義參數
{
a: {
type: "number",
description: "First number"
}
}
```
**正確代碼:**
```typescript
// ✅ 正確:使用 zod schema
{
a: z.number().describe("First number"),
b: z.number().describe("Second number")
}
```
### 問題 2: ES Modules vs CommonJS
**更新: 官方推薦使用 ES Modules**
**正確配置:**
```json
// ✅ 使用 ES modules (官方推薦)
{
"type": "module",
"compilerOptions": {
"module": "ESNext"
}
}
```
**正確的導入語法:**
```typescript
// ✅ ES modules 導入
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
```
### 問題 3: TypeScript 嚴格模式類型錯誤
**錯誤:**
```
Binding element 'a' implicitly has an 'any' type
```
**解決:**
```typescript
// ✅ 添加類型註解
async ({ a, b }: { a: number; b: number }) => {
```
## Zod 參數 Schema 詳解
### 為什麼需要 Zod?
```mermaid
graph TD
A[AI 發送 JSON 參數] --> B[MCP Protocol]
B --> C{Schema 驗證}
C -->|Zod Schema| D[類型安全轉換]
C -->|無 Schema| E[參數丟失/類型錯誤]
D --> F[正確的 TypeScript 參數]
E --> G[undefined/NaN 錯誤]
```
### Zod Schema 語法
```typescript
// 基本類型
z.number() // 數字
z.string() // 字符串
z.boolean() // 布爾值
// 添加描述
z.number().describe("這是一個數字參數")
// 可選參數
z.number().optional()
// 默認值
z.number().default(0)
// 數組
z.array(z.number())
// 對象
z.object({
name: z.string(),
age: z.number()
})
```
## 配置 AI 客戶端連接
### Claude Desktop 配置
```json
{
"mcpServers": {
"basic-math-server": {
"command": "node",
"args": ["C:\\path\\to\\your\\project\\build\\index.js"],
"description": "A basic math server providing sum and subtraction operations"
}
}
}
```
### 配置流程
```mermaid
graph LR
A[編寫 MCP Server] --> B[編譯 TypeScript]
B --> C[創建配置文件]
C --> D[添加到 Claude Desktop]
D --> E[重啟 Claude]
E --> F[AI 可調用工具]
```
## 調試和測試
### 本地測試腳本
```javascript
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
// 創建客戶端測試
const transport = new StdioClientTransport({
command: 'node',
args: ['build/index.js']
});
const client = new Client({ name: 'test-client', version: '1.0.0' });
await client.connect(transport);
// 測試工具調用
const result = await client.callTool({
name: 'sum',
arguments: { a: 20.12, b: 123456 }
});
```
## 最佳實踐
### 1. 錯誤處理
```typescript
server.tool("divide",
{ a: z.number(), b: z.number() },
async ({ a, b }) => {
if (b === 0) {
return {
content: [{ type: "text", text: "Error: Division by zero" }],
isError: true
};
}
return {
content: [{ type: "text", text: String(a / b) }]
};
}
);
```
### 2. 參數驗證
```typescript
server.tool("factorial",
{ n: z.number().int().min(0).max(20) }, // 限制範圍
async ({ n }) => {
// 實現階乘
}
);
```
### 3. 異步操作
```typescript
server.tool("fetch-data",
{ url: z.string().url() },
async ({ url }) => {
try {
const response = await fetch(url);
const data = await response.text();
return { content: [{ type: "text", text: data }] };
} catch (error) {
return {
content: [{ type: "text", text: `Error: ${error.message}` }],
isError: true
};
}
}
);
```
## 常見陷阱
1. **忘記使用 zod schema** → 參數無法正確傳遞
2. **模塊系統配置錯誤** → 運行時錯誤
3. **缺少類型註解** → TypeScript 編譯錯誤
4. **路徑配置錯誤** → AI 客戶端無法找到服務器
5. **忘記重新編譯** → 修改未生效
## 擴展方向
### 添加更多工具類型
```mermaid
graph TB
MCP[MCP Server] --> Math[數學工具]
MCP --> File[文件操作]
MCP --> API[API 調用]
MCP --> DB[數據庫查詢]
Math --> Sum[加法]
Math --> Sub[減法]
Math --> Complex[復雜運算]
File --> Read[讀取文件]
File --> Write[寫入文件]
API --> HTTP[HTTP 請求]
API --> Auth[認證]
DB --> Query[查詢]
DB --> Update[更新]
```
### 資源定義
```typescript
// 添加可讀取的資源
server.resource(
"config",
"config://settings",
async (uri) => ({
contents: [{
uri: uri.href,
text: JSON.stringify(settings, null, 2)
}]
})
);
```
## ES Modules 更新說明 (2025年1月)
### 更新摘要
我們已成功將項目從 CommonJS 轉換為 ES Modules,符合官方最佳實踐:
### 主要更改
1. **package.json**
```json
{
"type": "module" // 新增此行
}
```
2. **tsconfig.json**
```json
{
"compilerOptions": {
"module": "ESNext", // 從 CommonJS 改為 ESNext
"allowSyntheticDefaultImports": true // 新增此選項
}
}
```
3. **src/index.ts**
```typescript
// 從 require 改為 import
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
```
4. **test.js**
```javascript
// 測試文件也更新為 ES modules
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
```
### 驗證結果
- ✅ TypeScript 編譯成功
- ✅ 服務器正常啟動
- ✅ 工具調用功能正常
- ✅ 測試腳本運行成功
### 優勢
- 符合現代 JavaScript 標準
- 更好的樹搖 (tree-shaking) 支持
- 與官方 MCP SDK 完全兼容
- 為 Next.js 等現代框架做好準備
通過這個完整的指南,開發者可以理解 MCP Server 的核心概念、實作步驟、常見問題及解決方案,並使用現代的 ES Modules 標準,從而成功創建自己的 MCP 工具。