🔌 為什麼要自己寫 MCP Server?
MCP 讓 AI 以統一方式連接工具。社群已有數百個現成 Server,但當你需要連接自己公司的內部系統——你得自己寫。
💡 一句話理解 寫 MCP Server = 幫 AI 裝一個「插頭」,讓它能存取你的資料和工具。
什麼場景需要自己寫
| 場景 | 現成 MCP Server | 需要自己寫 |
|---|---|---|
| 連接 GitHub | ✅ 有 | |
| 連接 Notion | ✅ 有 | |
| 連接公司內部 ERP | ✅ 自己系統 | |
| 連接自建資料庫 | ⚠️ 通用的有 | ✅ 需客製查詢 |
| 公司 API 做成 AI 工具 | ✅ 自己 API |
🏗️ MCP Server 架構
Claude Desktop / Cursor / AI Agent(MCP Host)
↕ JSON-RPC over stdio / SSE
你的 MCP Server
↕
你的工具 / 資料
(資料庫、API、檔案系統⋯)
MCP Server 提供三種能力
| 能力 | 說明 | 範例 |
|---|---|---|
| Tools | AI 可以呼叫的功能 | 搜尋商品、建立訂單 |
| Resources | AI 可以讀取的資料 | 資料庫內容、設定檔 |
| Prompts | 預設的提示模板 | 「分析報表」模板 |
🚀 TypeScript 實作
安裝
npm init -y
npm install @modelcontextprotocol/sdk zod
最小 MCP Server
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// 建立 Server
const server = new McpServer({
name: "my-company-tools",
version: "1.0.0",
});
// 定義工具:查詢公司產品
server.tool(
"search_products",
"搜尋公司產品目錄,回傳符合條件的商品",
{
keyword: z.string().describe("搜尋關鍵字"),
category: z.enum(["electronics", "clothing", "food"])
.optional()
.describe("商品類別"),
max_price: z.number().optional().describe("最高價格(台幣)"),
},
async ({ keyword, category, max_price }) => {
// 你的實際搜尋邏輯(呼叫內部 API 或查資料庫)
const results = await searchProductsFromDB(keyword, category, max_price);
return {
content: [{
type: "text",
text: JSON.stringify(results, null, 2),
}],
};
}
);
// 定義工具:建立訂單
server.tool(
"create_order",
"建立新訂單",
{
product_id: z.string().describe("商品 ID"),
quantity: z.number().min(1).describe("數量"),
customer_name: z.string().describe("客戶名稱"),
},
async ({ product_id, quantity, customer_name }) => {
const order = await createOrderInDB(product_id, quantity, customer_name);
return {
content: [{
type: "text",
text: `訂單建立成功!訂單編號:${order.id}`,
}],
};
}
);
// 定義資源:公司政策文件
server.resource(
"company://policies/return",
"退貨政策",
"text/plain",
async () => ({
contents: [{
uri: "company://policies/return",
text: "退貨政策:購買後 7 天內可無條件退貨...",
}],
})
);
// 啟動
const transport = new StdioServerTransport();
await server.connect(transport);
🐍 Python 實作
安裝
pip install mcp
最小 MCP Server
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import json
server = Server("my-company-tools")
# 定義工具列表
@server.list_tools()
async def list_tools():
return [
Tool(
name="search_products",
description="搜尋公司產品目錄",
inputSchema={
"type": "object",
"properties": {
"keyword": {
"type": "string",
"description": "搜尋關鍵字"
},
"max_price": {
"type": "number",
"description": "最高價格(台幣)"
}
},
"required": ["keyword"]
}
),
Tool(
name="get_order_status",
description="查詢訂單狀態",
inputSchema={
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "訂單編號"
}
},
"required": ["order_id"]
}
)
]
# 處理工具呼叫
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "search_products":
results = search_products_from_db(
arguments["keyword"],
arguments.get("max_price")
)
return [TextContent(
type="text",
text=json.dumps(results, ensure_ascii=False)
)]
elif name == "get_order_status":
status = get_order_from_db(arguments["order_id"])
return [TextContent(
type="text",
text=f"訂單 {arguments['order_id']} 狀態:{status}"
)]
# 啟動
async def main():
async with stdio_server() as (read, write):
await server.run(read, write, server.create_initialization_options())
import asyncio
asyncio.run(main())
⚙️ 在 Claude Desktop 中使用
寫好 MCP Server 後,在 Claude Desktop 設定檔中註冊:
macOS
// ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"my-company-tools": {
"command": "node",
"args": ["/path/to/your/server/index.js"]
}
}
}
Windows
// %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"my-company-tools": {
"command": "node",
"args": ["C:\\path\\to\\your\\server\\index.js"]
}
}
}
在 Cursor 中使用
// .cursor/mcp.json(專案根目錄)
{
"mcpServers": {
"my-company-tools": {
"command": "node",
"args": ["./mcp-server/index.js"]
}
}
}
🧪 測試你的 MCP Server
用 MCP Inspector
npx @modelcontextprotocol/inspector node ./index.js
Inspector 提供一個 Web UI,讓你可以:
- 查看所有 Tools 和 Resources
- 手動呼叫工具並查看回應
- 偵錯 JSON-RPC 通訊
📋 MCP Server 開發 Checklist
- ✅ Tool 的 description 要清楚——AI 靠此決定要不要用
- ✅ Parameter 的 description 要精確——AI 靠此填入參數
- ✅ 用
enum約束可列舉的參數值 - ✅ 有錯誤處理——Tool 失敗時回傳有意義的錯誤訊息
- ✅ 敏感操作加確認——刪除、修改等操作要小心
- ✅ 用 Inspector 測試過所有工具
- ✅ 在 Claude Desktop 或 Cursor 中實際測試
❓ FAQ
MCP Server 和普通 API 有什麼不同?
MCP Server 透過標準化的 JSON-RPC 協議和 AI 溝通,不需要 AI 知道你的 API 格式。你定義工具的 schema 和描述,AI 自動知道怎麼使用。而且一個 MCP Server 可以被所有支援 MCP 的 AI 使用——不用為每個 AI 各寫一次。
MCP Server 要部署到哪裡?
目前主流是本地 stdio 方式(MCP Host 直接啟動你的 Server 程序)。也支援 SSE(HTTP),可以部署到遠端伺服器。本地方式最簡單,適合個人和開發階段;SSE 方式適合團隊共用。
哪些 AI 支援 MCP?
Claude Desktop(原生最完整)、Cursor(AI IDE)、Windsurf、以及越來越多的 Agent 框架。OpenAI 和 Google 尚未正式支援但在評估中。