從 0 開發
MCP Server
若你是全端工程師或 Agent 平台負責人,常被要求「讓 AI 能查內部 API、讀專案檔案」,卻只有零散的 curl 腳本而沒有可重用的整合層,本文正是為你而寫。你將用 Python 與 FastMCP 從環境建置一路做到 Tools / Resources / Prompts 全模組實作、MCP 對照 Function Calling 決策表、ChromaDB 向量知識庫實戰,以及五步 Mac 隔離開發驗收清單。全文含對照表、可跟做的程式片段與常見錯誤排查流程。
📋 本文目錄
01 · 引言:AI 缺工具,MCP 補缺口
2026 年的 Agent 已能寫程式、做多步推理,但沒有外部工具仍是封閉系統:它讀不到你 Git 倉庫最新的 PR 狀態,無法代你執行 SELECT * FROM orders WHERE status='pending',也不能在 Slack 裡 @同事。傳統做法是每家模型宿主各自實作 Function Calling,每個 SaaS 又要為 Claude、GPT、Gemini 寫一套轉接器——整合成本隨 N×M 線性爆炸。
MCP(Model Context Protocol) 由 Anthropic 於 2024 年 11 月開源,定位是「大模型與外部世界的 USB-C 接頭」:你實作一個符合規範的 Server,Cursor、Claude Desktop、OpenClaw 等 Host 都能載入,無須重複寫膠水程式。若你已讀過站內 MCP 為何成為 AI 時代的 HTTP 協定,本文是它的動手版——從 pip install mcp 到 Docker 上線,全程可跟做。
文章結構:三大開發痛點 → MCP 架構與 JSON-RPC 生命週期 → 對照 OpenAI FC / LangChain 決策表 → Hello World → Tools → Resources → Prompts 遞進實作 → HTTP+SSE 部署 → ChromaDB 知識庫實戰 → Mac 隔離開發驗收。
02 · 三大開發痛點
1. 每家宿主一套工具方言。 OpenAI 的 tools 陣列、Anthropic 的 tool_use 區塊、Google 的 Function Declaration——Schema 欄位名、錯誤回傳格式各不相同。把同一個「查訂單」能力接到三個宿主,往往要寫三份包裝層。MCP 把工具註冊、能力描述、呼叫語意統一到 JSON-RPC,Write Once, Run Everywhere。
2. 本地憑證與權限邊界模糊。 MCP Server 常需讀檔案系統、調內網 API、持有 OAuth Token。在主力筆電混裝十幾個 Server 與多款 IDE,一次誤設就可能把正式環境 Key 寫進測試 cron。需要可丟棄的沙箱環境先驗收再上線。
3. 除錯鏈路長、錯誤難定位。 從 Host 發起到 Server 執行,中間經過 Client 轉發、STDIO 管道或 HTTP 長連線——任何一環設定錯誤都表現為「工具不可用」或「Connection closed」。沒有 Inspector 與單元測試,排查往往靠猜。
03 · 什麼是 MCP:架構與演進
從 Function Calling 到 MCP 的三段演進
第一階段(2023):Function Calling。 OpenAI 在 GPT-4 中引入工具呼叫,模型輸出 JSON 指定函式名與參數,由應用層執行。問題是 Schema 嵌在 Prompt 或閉源 SDK,無法跨宿主重用。
第二階段(2024 初):Plugins / Actions。 ChatGPT Plugins、GPT Actions 把 HTTP 端點包裝成工具,降低了接入門檻,但仍是宿主私有生態,且依賴 OpenAPI 靜態描述,Agent 無法在執行時動態發現新 Server。
第三階段(2024 11 月至今):MCP。 Anthropic 發布開放規範與參考 SDK,Host / Client / Server 三層解耦,10,000+ 社群 Server 在 18 個月內湧現,OpenAI、Google、Microsoft 於 2026 年全線跟進。
Client-Server 架構與三大能力
┌─────────────────────────────────────────────────────────────┐
│ Host(Cursor / Claude Desktop / OpenClaw) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ MCP Client │ │ MCP Client │ │ MCP Client │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
└─────────┼────────────────┼────────────────┼─────────────────┘
│ JSON-RPC │ JSON-RPC │ JSON-RPC
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ MCP Server A │ │ MCP Server B │ │ MCP Server C │
│ Tools │ │ Resources │ │ Prompts │
│ Resources │ │ Tools │ │ Tools │
└──────────────┘ └──────────────┘ └──────────────┘
- Tools(工具):模型可主動呼叫的函式,如
read_file、query_database、send_http_request。帶 JSON Schema 輸入描述,回傳結構化或文字結果。 - Resources(資源):模型可被動讀取的上下文,如設定檔、日誌片段、資料庫 schema 快照。透過 URI 識別(
file:///project/README.md),由 Client 按需拉取。 - Prompts(提示範本):預置的多輪對話範本,如「程式碼審查」「SQL 生成」,Host 可一鍵注入,減少重複 Prompt 工程。
JSON-RPC 2.0 與傳輸層
所有 MCP 訊息統一為 JSON-RPC 2.0。常見方法包括 initialize、tools/list、tools/call、resources/list、resources/read、prompts/list、prompts/get。
// 連線生命週期:initialize → initialized → 業務呼叫 → 關閉// 1. Client 發起握手{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "cursor", "version": "1.0" } } }// 2. Server 回應能力集{ "jsonrpc": "2.0", "id": 1, "result": { "protocolVersion": "2024-11-05", "capabilities": { "tools": {} }, "serverInfo": { "name": "my-server", "version": "0.1.0" } } }// 3. 呼叫工具{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "say_hello", "arguments": { "name": "MacDate" } } }
傳輸層兩種主流模式:STDIO(Host 以子程序拉起 Server,stdin/stdout 傳 JSON-RPC,適合本地開發)與 HTTP + SSE(遠端 Server、多租戶閘道,Client 透過 SSE 收 Server 推送)。2026 年規範還引入了 Streamable HTTP,進一步簡化雙向串流通訊。
04 · MCP vs OpenAI FC vs LangChain 對照表
選型時常見疑問:「我已有 OpenAI Function Calling,還要 MCP 嗎?」「LangChain Tool 夠不夠用?」下表從架構師視角對照三者:
| 維度 | OpenAI Function Calling | LangChain Tools | MCP |
|---|---|---|---|
| 定位 | 單模型宿主內建能力 | Python 框架層工具抽象 | 跨宿主開放協定 |
| 發現機制 | 靜態 Schema 嵌入請求 | 程式碼內註冊,執行時列舉 | 執行時 tools/list(機讀) |
| 跨 Host 重用 | 僅 OpenAI API / ChatGPT | 需重寫各宿主轉接器 | 一次實作,多 Host 載入 |
| Resources / Prompts | 無原生支援 | 透過 Retriever / Template 模擬 | 協定級一等公民 |
| 傳輸 | HTTP API 內嵌 | 程序內呼叫 | STDIO / HTTP+SSE / Streamable HTTP |
| 生態規模(2026 中) | 宿主私有 | 數千 PyPI 整合 | 10,000+ Server |
| 適用場景 | 純 OpenAI 棧快速驗證 | 自研 Agent 框架內編排 | 多 Host、企業 Catalog、長期維護 |
硬核數據快照: 採用 MCP 統一工具層的團隊,報告整合成本下降 38%–55%;同一 Server 接到 Cursor 與 Claude Desktop 的重複開發工作量減少約 70%;公網掃描顯示未授權暴露的 MCP Server 約 1,000+——部署前必須在隔離環境驗收權限邊界。
05 · 開發環境建置
Python vs TypeScript 選型
官方 SDK 涵蓋 Python(mcp) 與 TypeScript(@modelcontextprotocol/sdk)。Python 側 FastMCP 裝飾器語法簡潔,適合資料工程與 AI 腳本;TypeScript 適合 Node 生態與前端團隊。本文以 Python + FastMCP 為主,TS 讀者可對照 SDK 文件平移概念。
虛擬環境與專案結構
mkdir my-mcp-server && cd my-mcp-serverpython3 -m venv .venvsource .venv/bin/activatepip install "mcp[cli]" pydantic httpx chromadb
建議目錄結構:
my-mcp-server/├── server.py # FastMCP 入口├── tools/ # 各工具模組│ ├── calculator.py│ ├── filesystem.py│ ├── http_client.py│ ├── database.py│ └── datetime_tool.py├── resources/ # Resource 處理器├── prompts/ # Prompt 範本├── tests/ # pytest 單元測試├── pyproject.toml└── Dockerfile
MCP Inspector、Cursor 與 Claude Desktop
MCP Inspector 是官方除錯 UI,可獨立連線 STDIO 或 HTTP Server,視覺化 tools/list 與 tools/call:
npx @modelcontextprotocol/inspector python server.py
Cursor 在 ~/.cursor/mcp.json(或專案級 .cursor/mcp.json)註冊 Server。Claude Desktop 使用 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)。二者格式類似,下文 Hello World 節給出完整範例。
06 · Hello World:第一個 MCP Server
用 FastMCP 實作最小可執行 Server,包含一個 say_hello 工具:
# server.pyfrom mcp.server.fastmcp import FastMCPmcp = FastMCP("hello-server")@mcp.tool()def say_hello(name: str = "World") -> str: """向指定名稱打招呼。""" return f"Hello, {name}! MCP Server is running."if __name__ == "__main__": mcp.run()
本地啟動與 Inspector 驗證:
python server.py# 另開終端機npx @modelcontextprotocol/inspector python server.py
在 Inspector 中點擊 Connect → List Tools → 呼叫 say_hello 並傳入 {"name": "MacDate"},應回傳問候語。
Cursor 設定範例
// ~/.cursor/mcp.json{ "mcpServers": { "hello-server": { "command": "/path/to/my-mcp-server/.venv/bin/python", "args": ["/path/to/my-mcp-server/server.py"] } }}
Claude Desktop 設定結構相同,路徑改為上述 macOS 設定檔。重啟 Host 後,在對話中應能看到 say_hello 工具可用。
07 · Tools:五種典型工具實作
Tool 結構與 Pydantic 輸入驗證
FastMCP 用 Python 型別註解自動產生 JSON Schema。複雜參數可用 Pydantic BaseModel:
from pydantic import BaseModel, Fieldclass CalcInput(BaseModel): expression: str = Field(description="數學運算式,如 2+3*4")@mcp.tool()def calculator(input: CalcInput) -> str: """安全計算器,僅允許數字與四則運算。""" import re if not re.match(r'^[\d\s+\-*/().]+$', input.expression): raise ValueError("非法字元") return str(eval(input.expression))
五種工具一覽
| 工具名 | 用途 | 關鍵實作 |
|---|---|---|
calculator |
安全四則運算 | 正則白名單 + eval 沙箱 |
read_file |
讀取工作區檔案 | 路徑正規化 + 根目錄約束 |
http_get |
代理 HTTP 請求 | httpx 非同步 + 逾時/網域白名單 |
query_db |
唯讀 SQL 查詢 | sqlite3 / asyncpg + 參數化 |
current_time |
回傳指定時區時間 | zoneinfo + ISO 8601 格式 |
檔案工具範例
from pathlib import PathWORKSPACE = Path("/safe/workspace").resolve()@mcp.tool()def read_file(path: str) -> str: """讀取工作區內檔案內容。""" target = (WORKSPACE / path).resolve() if not str(target).startswith(str(WORKSPACE)): raise ValueError("路徑越界") return target.read_text(encoding="utf-8")
非同步工具與錯誤處理
IO 密集型工具應使用 async def,FastMCP 會自動排程:
@mcp.tool()async def http_get(url: str) -> str: """GET 請求,5 秒逾時。""" import httpx async with httpx.AsyncClient(timeout=5.0) as client: try: resp = await client.get(url) resp.raise_for_status() return resp.text[:8000] except httpx.HTTPError as e: return f"HTTP 錯誤: {e}"
錯誤應回傳可讀文字而非裸拋例外(除非參數驗證失敗),便於模型在對話中向使用者解釋並重試。
08 · Resources:唯讀上下文
Resource vs Tool 的分工
Tool 是模型主動決策呼叫的動作(副作用:寫檔案、發 HTTP、改資料庫)。Resource 是模型按需讀取的上下文(無副作用:設定檔、schema 文件、日誌 tail)。Host 可在對話開始時預拉 Resource,減少 Token 浪費。
URI Scheme 與靜態/動態 Resource
- 靜態 Resource:固定 URI,如
config://app/settings.json,內容相對固定。 - 動態 Resource:URI 帶參數或使用 Resource Template,如
log://app/{date},內容隨請求變化。 - 檔案系統 Server:官方
@modelcontextprotocol/server-filesystem將目錄對應為file://Resource,適合唯讀暴露專案文件。
@mcp.resource("config://app/settings")def get_settings() -> str: """回傳應用設定 JSON。""" import json return json.dumps({"env": "production", "debug": False})@mcp.resource("schema://db/{table_name}")def get_table_schema(table_name: str) -> str: """動態回傳指定表的 DDL。""" return f"CREATE TABLE {table_name} (...);"
09 · Prompts:可重用對話範本
Prompts 讓 Host 一鍵注入多輪對話結構,減少重複 Prompt 工程。與 Cursor 的 Agent Skill 互補:Skill 編排「何時用什麼能力」,MCP Prompt 提供「標準對話骨架」。
@mcp.prompt()def code_review_prompt(language: str = "Python") -> str: """產生程式碼審查 Prompt 範本。""" return f"""你是一位資深 {language} 程式碼審查專家。請按以下結構審查使用者提交的程式碼:1. 安全漏洞(SQL 注入、路徑遍歷、金鑰硬編碼)2. 效能問題(N+1 查詢、阻塞 IO)3. 可讀性與命名4. 測試覆蓋建議請用繁體中文輸出,每條發現附行號與修復建議。"""
多輪 Prompt 可透過回傳多條 Message 實作:FastMCP 支援 list[PromptMessage],第一條設 system 角色,後續設 user 角色,Host 按序注入對話歷史。
10 · HTTP 傳輸與安全
STDIO vs HTTP+SSE 對照
| 維度 | STDIO | HTTP + SSE | Streamable HTTP(2026) |
|---|---|---|---|
| 部署位置 | 本地子程序 | 遠端伺服器 / 容器 | 遠端,單端點雙向流 |
| 多 Client 共享 | 每 Host 獨立程序 | 多 Client 連同一 Server | 同左,連線管理更簡 |
| 認證 | 程序級(誰啟動誰負責) | Bearer Token / mTLS / OAuth | 同 HTTP+SSE |
| 適用場景 | 桌面 Host、敏感本地工具 | 企業內網、SaaS 閘道 | 新部署首選 |
| 負載平衡 | 不適用 | 需工作階段黏著 | 改進中 |
HTTP Server 啟動範例(FastMCP):
# 正式環境用 uvicorn 或 mcp 內建 HTTP 模式mcp run server.py --transport streamable-http --port 8080
安全要點: 公網暴露的 MCP Server 必須啟用認證(Bearer Token 或 OAuth 2.1);工具層實施網域白名單、路徑沙箱、SQL 唯讀;稽核日誌記錄每次 tools/call 的參數與呼叫方。2026 年掃描顯示 1,000+ 未授權 Server 裸奔——切勿把內網 API Key 直接寫進無鑑權的 HTTP Server。
11 · 除錯測試與常見錯誤
MCP Inspector 工作流程
- Connect:選擇 STDIO 命令或 HTTP URL,確認
initialize握手成功。 - List Tools / Resources / Prompts:核對能力集與 JSON Schema 是否符合預期。
- Call Tool:手動傳入參數,觀察回傳與錯誤訊息。
- Notifications:若 Server 支援進度推送,在此面板查看。
- Export Log:匯出 JSON-RPC transcript 供團隊複盤。
pytest 單元測試範例
# tests/test_tools.pyimport pytestfrom server import calculatordef test_calculator_basic(): from server import CalcInput result = calculator(CalcInput(expression="2+3*4")) assert result == "14"def test_calculator_rejects_injection(): with pytest.raises(ValueError): calculator(CalcInput(expression="__import__('os')"))
常見錯誤對照表
| 現象 | 可能原因 | 排查步驟 |
|---|---|---|
| Host 看不到工具 | 設定路徑錯誤、Python 非 venv | 檢查 mcp.json 絕對路徑;Inspector 先驗證 |
| Connection closed | Server 啟動崩潰、stderr 污染 stdout | 單獨執行 python server.py 看 traceback |
| tools/call 逾時 | 同步阻塞 IO、無逾時設定 | 改 async + httpx timeout;資料庫加 statement_timeout |
| HTTP 401 | Token 缺失或過期 | 核對 Authorization 標頭;輪替 Key |
| Schema 驗證失敗 | Pydantic 欄位名與模型輸出不符 | Inspector 查看 tools/list 的 inputSchema |
12 · 生產部署
Docker 打包
# DockerfileFROM python:3.12-slimWORKDIR /appCOPY pyproject.toml .RUN pip install --no-cache-dir .COPY . .EXPOSE 8080CMD ["mcp", "run", "server.py", "--transport", "streamable-http", "--port", "8080"]
雲端平台選型
- Railway / Render:零設定容器部署,適合 MVP 與 PoC,按用量計費。
- AWS Lambda / Google Cloud Run:無伺服器,冷啟動需優化 Server 體積;Cloud Run 支援 SSE 長連線較友善。
- VPS(DigitalOcean / Hetzner):完全控制,適合 mTLS 內網閘道;需自建監控與日誌。
監控與版本化: 在 serverInfo.version 中語意化版本(SemVer);接入 Prometheus 或雲端 APM 記錄 tools/call 延遲 P99;灰度發布時新舊 Server 並行註冊到 Host Catalog,對照錯誤率後再切換。
13 · 知識庫實戰:ChromaDB / Qdrant
企業 Agent 最常見的 MCP Server 場景是向量知識庫:把內部文件 embedding 後供模型檢索。以下以 ChromaDB 為例(Qdrant 介面類似,換用戶端即可)。
import chromadbfrom chromadb.utils import embedding_functionsclient = chromadb.PersistentClient(path="./chroma_data")ef = embedding_functions.DefaultEmbeddingFunction()collection = client.get_or_create_collection("docs", embedding_function=ef)@mcp.tool()def index_document(doc_id: str, text: str) -> str: """寫入文件到向量庫。""" collection.upsert(ids=[doc_id], documents=[text]) return f"已索引: {doc_id}"@mcp.tool()def search_knowledge(query: str, top_k: int = 5) -> str: """語意檢索知識庫。""" results = collection.query(query_texts=[query], n_results=top_k) docs = results["documents"][0] return "\n---\n".join(docs or ["無結果"])
Embedding 模型可選 OpenAI text-embedding-3-small(1536 維)或本地 sentence-transformers。ChromaDB 預設使用 all-MiniLM-L6-v2(384 維),單條 512 token 切片是常見實務;索引 10 萬頁文件約需 2–4 GB 磁碟與 8 GB 記憶體。正式環境建議 Qdrant 叢集 + 副本,ChromaDB 適合單機 PoC。
14 · 生態與學習路徑
推薦社群 Server
@modelcontextprotocol/server-filesystem— 檔案讀寫與 Resource@modelcontextprotocol/server-postgres— 唯讀 SQL 查詢@modelcontextprotocol/server-slack— Slack 訊息與頻道@modelcontextprotocol/server-github— Issue / PR / 程式碼搜尋mcp-server-fetch— HTTP 抓取與 HTML 轉 Markdown
2026 趨勢與學習路徑
趨勢: Streamable HTTP 取代純 SSE 成為新部署預設;OAuth 2.1 裝置流進入主流 Host;企業 Catalog 與 Server 簽章/稽核成為合規標配;MCP 與 A2A(Agent-to-Agent)在同一棧分層共存。
建議學習路徑(約 2 週):
- 閱讀 MCP 協定架構解析,理解 Host / Client / Server 三層。
- 跟做本文 Hello World → Tools 五件套,Inspector 驗收。
- 接入 Cursor,跑通真實業務場景(讀 README + 查庫 + HTTP)。
- 實作 ChromaDB 知識庫 Server,對照檢索準確率。
- Docker + HTTP 部署到 Railway,設定 Bearer 認證。
- 在隔離 Mac 節點做 Catalog 彩排,寫入 ADR 後推進正式環境。
15 · 結語:在隔離 Mac 上練熟再上線
雖然你可以在 Windows WSL、Linux 容器或主力 Mac 上直接開發 MCP Server,但主力機混裝 OAuth、正式 API Key 與多款 Host 全域設定,一次誤設就可能讓 tools/call 在背景 cron 裡存取內網;WSL 檔案系統權限與 macOS Seatbelt 沙箱體驗也不等價。公網掃描已發現 1,000+ 未授權暴露的 Server——在污染正式憑證之前,用隔離環境驗證「哪些 Server 值得進白名單」是更穩健的工程紀律。
MCP 讓你寫一次 Server、多 Host 重用,但開發體驗同樣重要:Cursor 與 Claude Desktop 的 MCP 設定路徑、STDIO 子程序行為、Keychain 憑證儲存都是 macOS 原生體驗。若你需要可稽核的「多 Server × 多 Host 對照實測」證據,又與 Xcode / Apple 工具鏈同週期協作,在獨立 macOS 租用節點完成 1–3 天 MCP 開發彩排再推進企業 Catalog,通常比直接在辦公筆電上疊裝 Server 更輕、比裸容器更接近真實桌面 Host 行為。
五步 Mac 隔離 MCP 開發驗收(HowTo)
- 租用隔離 macOS:Mac mini M4 起,SSH 接入;本地使用者、Apple ID 與 OAuth 與主力機完全隔離。套餐見 M 系列算力定價。
- 部署開發環境:安裝 Python 3.12、Node(Inspector)、Cursor;建立獨立 venv,不共享主力機
~/.config。 - 並行開發多個 Server:在同一節點實作 Hello World、Tools 五件套與 ChromaDB 知識庫,Inspector 匯出 tools/list 快照。
- Cursor / Claude Desktop 聯調:註冊 STDIO Server,跑固定任務包(讀檔案、查庫、語意檢索),記錄延遲與越權攔截。
- 匯出 ADR 並釋放:將 Server 白名單、OAuth 範圍與資料分級寫入架構決策記錄,吊銷測試 Key、退租擦碟。