從 0 開發一個 MCP Server:
手把手教你構建 AI 工具調用能力

若你是一名 Python 或 TypeScript 開發者,想讓 Claude、GPT、Cursor 裡的 AI 真正存取資料庫、呼叫 API、讀寫檔案,卻發現大模型本身沒有「手腳」——訓練資料有截止日、無法執行外部操作——本文將帶你從空白專案寫出一個可上正式環境的 MCP Server。我們會走完 Tools / Resources / Prompts 三大能力、stdio 與 HTTP+SSE 兩種傳輸、除錯測試到 Docker 部署的全鏈路;讀完即可在 Cursor 或 Claude Desktop 中接入自研工具鏈。節點與方案以 NOVAKVM 租用價格頁為準。

AI 工具整合經歷了清晰的三段演進:Function Calling(OpenAI 2023)讓模型輸出結構化 JSON 呼叫參數;Plugins / GPT Actions 把 HTTP 端點包裝成對話外掛;MCP(Model Context Protocol) 則由 Anthropic 於 2024 年 11 月開源,把「模型如何發現、描述並呼叫工具」標準化為開放協定——一次實作,Claude Desktop、Cursor、VS Code Continue 等宿主均可複用。

  • LLM 能力邊界:無法存取即時資料、無法直接操作檔案系統或資料庫——必須靠外部工具補上「感官與手腳」。
  • 格式碎片化:OpenAI Function Calling、Claude Tool Use、LangChain Agent 各自定義工具 schema,換模型或換 IDE 就要重寫適配層。
  • 發現機制缺失:傳統 REST API 不會主動告訴 AI「我能做什麼」;MCP 執行時期透過 tools/list 動態暴露能力清單。
  • 工作階段與上下文:MCP 保持持久連線,支援多步 Agent 工作流;REST 無狀態請求難以串聯複雜任務。
  • 安全與權限:Server 端可精細控制哪些工具可寫、哪些資源唯讀,避免模型越權操作正式環境資料。

Client-Server JSON-RPC 架構可概括為以下鏈路:

  • Host(宿主):Claude Desktop、Cursor、VS Code —— 承載使用者互動介面。
  • MCP Client:內嵌於 Host,與每個 Server 維護 1:1 工作階段。
  • MCP Server(你寫的):暴露三大原語 —— Tools(可執行操作)、Resources(唯讀資料)、Prompts(複用提示範本)。
  • 傳輸層:本機開發用 stdio(子程序 stdin/stdout);遠端部署用 HTTP + SSE(Server-Sent Events 推送)。
  • 協定層:全部訊息遵循 JSON-RPC 2.0,如 initializetools/listtools/callnotifications/cancelled
  • 生命週期:握手 → 能力協商 → 正常執行 → 優雅關閉;Client 可隨時 ping 保活。
MCP vs OpenAI Function Calling vs LangChain 工具整合
維度 MCP OpenAI FC LangChain Tools
標準化程度 開放協定,跨廠商 綁定 OpenAI API 框架內部格式
工具發現 執行時期 tools/list 請求時內嵌 schema 程式碼註冊,靜態
Resources / Prompts 原生支援 不支援 需自行封裝
傳輸方式 stdio / HTTP+SSE HTTPS API 程序內呼叫
IDE 原生整合 Cursor、Claude Desktop 等 ChatGPT 外掛生態 需額外橋接層

MCP 解決的不是「能不能調 API」,而是「AI 如何統一發現、選擇並正確呼叫工具」——這是 Agent 時代的核心命題。

官方提供兩套一等 SDK:Pythonmcp 套件(含 FastMCP 高層 API)與 TypeScript@modelcontextprotocol/sdk。Python 適合快速原型與資料/ML 場景;TypeScript 適合 Node.js 生態與前端團隊。下文以 Python FastMCP 為主,TypeScript 結構完全對稱。

setup.sh
mkdir my-mcp-server && cd my-mcp-server
python3 -m venv .venv
source .venv/bin/activate
pip install "mcp[cli]" httpx pydantic python-dotenv
npm install -g @modelcontextprotocol/inspector

推薦專案結構:

project-tree
my-mcp-server/
├── server.py
├── tools/
├── resources/
├── prompts/
├── tests/
├── Dockerfile
├── requirements.txt
└── .env

除錯與接入三件套:

  • MCP Inspector:官方視覺化除錯器,可列出 tools/resources/prompts 並手動觸發呼叫。
  • Claude Desktop:編輯 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)註冊 stdio Server。
  • Cursor:Settings → MCP → 新增 Server 設定,支援 stdio 與遠端 HTTP 端點。

用 FastMCP 寫一個最小可用 Server,暴露 say_hello 工具:

server.py
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("hello-server")

@mcp.tool()
def say_hello(name: str) -> str:
    return f"Hello, {name}! MCP Server is running."

if __name__ == "__main__":
    mcp.run()

用 Inspector 啟動驗證:

terminal
npx @modelcontextprotocol/inspector python server.py

瀏覽器開啟 Inspector UI,在 Tools 面板呼叫 say_hello,傳入 {"name": "NOVAKVM"},應回傳問候語。

Claude Desktop 設定claude_desktop_config.json):

claude_desktop_config.json
{
  "mcpServers": {
    "hello-server": {
      "command": "/path/to/my-mcp-server/.venv/bin/python",
      "args": ["/path/to/my-mcp-server/server.py"]
    }
  }
}

Cursor MCP 設定:在專案根目錄建立 .cursor/mcp.json 或在 Cursor Settings → MCP 中新增等價 JSON,重啟 Cursor 後在 Agent 模式即可看到 say_hello 工具。

MCP 工具的函式簽名即文件:參數名、型別註解與 docstring 會自動轉為 JSON Schema 供模型理解。複雜輸入用 Pydantic 模型約束:

tools/search.py
from pydantic import BaseModel, Field

class SearchInput(BaseModel):
    query: str = Field(..., description="搜尋關鍵字")
    limit: int = Field(10, ge=1, le=100, description="回傳筆數上限")

@mcp.tool()
async def search_docs(input: SearchInput) -> list[dict]:
    ...

正式環境級 Server 通常實作以下五類工具:

  • calculator:安全數學運算式求值,禁止 eval 裸執行,用 ast 或專用函式庫解析。
  • file_read / file_write:限定根目錄(chroot 思路),防止路徑穿越;寫入操作需二次確認或白名單副檔名。
  • fetch_url:非同步 HTTP 請求,示例如下。
  • db_query:唯讀 SQL(SELECT),參數化查詢防注入;寫入操作單獨工具並加稽核日誌。
  • get_current_time:回傳 ISO 8601 時間戳,解決模型「不知道現在幾點」的常見問題。
tools/http.py
import httpx

@mcp.tool()
async def fetch_url(url: str, timeout: int = 30) -> str:
    async with httpx.AsyncClient(timeout=timeout) as client:
        resp = await client.get(url)
        resp.raise_for_status()
        return resp.text[:50000]

錯誤處理最佳實務:

  • 工具內捕捉例外,回傳結構化錯誤文字而非讓程序崩潰 —— Client 會把回傳值交給模型自行 retry 或換策略。
  • 對外部 API 設定逾時與重試上限;避免模型陷入無限迴圈呼叫。
  • 敏感資訊(API Key、連線字串)唯讀環境變數,絕不寫入 tool 回傳值或 Resources。
  • 寫入操作工具回傳操作摘要(改了什麼、影響列數),便於模型向使用者確認。

Resource 與 Tool 的核心區別:Resource 是唯讀上下文資料(設定檔、使用者檔案、日誌片段),模型透過 resources/read 拉取;Tool 是可執行操作(查詢、寫入、發請求)。Resource 適合「AI 需要看但不需要改」的資訊。

URI 方案(scheme)約定:

  • config://app/settings —— 靜態設定資源,啟動時註冊。
  • user://{id}/profile —— 動態範本,Client 傳入具體 id 後 Server 即時產生內容。
  • file:// —— 對應本機檔案系統(需路徑沙箱)。

Resource 支援四種 MIME 類型:text/plainapplication/json二進位 blob(Base64 編碼回傳)、stream(大檔案分塊推送)。

resources/config.py
@mcp.resource("config://app/settings")
def get_app_settings() -> str:
    return json.dumps({"env": "production", "version": "1.2.0"})

@mcp.resource("user://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
    profile = db.fetch_user(user_id)
    return json.dumps(profile)

檔案系統 Resource Server 可遞迴註冊目錄下檔案,讓 AI 在編碼時直接「看到」專案結構與關鍵設定,而無需逐檔呼叫 read tool。

MCP Prompt 是預先定義的提示範本,Host 可列出並一鍵注入對話上下文 —— 適合程式碼審查、事故複盤、API 設計評審等重複性工作流。Prompt 可含占位參數,支援多輪 message 結構。

prompts/review.py
from mcp.types import PromptMessage, TextContent

@mcp.prompt()
def code_review_prompt(language: str, focus: str = "security") -> list[PromptMessage]:
    return [
        PromptMessage(
            role="user",
            content=TextContent(
                type="text",
                text=f"請對以下 {language} 程式碼做 {focus} 維度審查,列出問題與改進建議:\n\n"
            )
        )
    ]

多輪範本示例:第一輪注入角色與約束,第二輪注入待審程式碼占位符,第三輪要求輸出結構化 JSON(severity / file / line / suggestion)。團隊可將最佳實務固化為 Prompt,新成員無需重複撰寫 system prompt。

stdio vs HTTP + SSE 傳輸對照
維度 stdio HTTP + SSE
部署位置 本機子程序 遠端伺服器 / 容器
網路需求 需公網或內網可達
水平擴展 單機 負載平衡 + session affinity
鑑權 程序隔離 Bearer Token / API Key
適用場景 個人開發、Claude Desktop 團隊共享、7×24 雲端常駐

FastMCP 支援 streamable-http 傳輸,一行切換:

server.py
if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="0.0.0.0", port=8080)

正式環境 HTTP 部署須補齊:

  • Bearer Token / API Key:在反向代理或 middleware 層校驗 Authorization 標頭。
  • CORS:若瀏覽器端 Inspector 跨域存取,設定允許的來源網域。
  • Rate Limiting:按 IP 或 API Key 限流,防止模型迴圈呼叫打爆後端。
  • TLS:公網暴露必須 HTTPS,推薦 Caddy / Nginx 終止 SSL。

MCP Inspector 用法:啟動後左側列出 Server 能力樹;Tools 面板可填 JSON 參數手動觸發;Notifications 面板觀察 Server 推送;Logs 面板查看 stderr 輸出。改程式碼後 Inspector 會自動重啟子程序。

tests/test_tools.py
import pytest
from server import say_hello

def test_say_hello():
    result = say_hello("World")
    assert "Hello, World!" in result

@pytest.mark.asyncio
async def test_fetch_url():
    result = await fetch_url("https://httpbin.org/get")
    assert "origin" in result
MCP Server 常見錯誤與排查
現象 可能原因 解決方案
工具不顯示 裝飾器遺漏、Server 啟動失敗 查 stderr 日誌;Inspector 重連
JSON 序列化失敗 回傳 datetime/Decimal 等不可序列化物件 手動 json.dumps 或轉 str
呼叫逾時 外部 API 慢、無 timeout 設定 工具內設 timeout;Client 側調大 limit
權限拒絕 檔案路徑超出沙箱、DB 憑證錯誤 檢查 ALLOWED_PATHS 與 .env 設定

六步正式環境部署清單:

  1. 鎖定依賴版本:pip freeze > requirements.txt,在 CI 中固定 Python 與 mcp SDK 版本,避免上游 breaking change。
  2. 撰寫 Dockerfile:多階段建置,最終映像只含執行時期依賴;非 root 使用者執行 Server 程序。
  3. 設定環境變數:API Key、DB 連線字串、ALLOWED_PATHS 全部走 secrets 管理,禁止硬編碼。
  4. 選擇託管平台:Railway / Render 適合快速驗證;AWS Lambda + HTTP adapter 適合低頻呼叫;Cloud Run / VPS 適合 7×24 常駐。
  5. 接入監控:結構化日誌(JSON)、/health 端點、Prometheus metrics 或 Sentry 例外上報。
  6. Cursor / Claude 接入驗證:遠端 URL + Bearer Token 寫入 MCP 設定,呼叫 tools/list 確認工具清單完整後放量。

Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER nobody
EXPOSE 8080
CMD ["python", "server.py"]

託管平台選型:

  • Railway / Render:Git push 自動部署,免費 tier 適合 MVP;注意冷啟動對 SSE 長連線的影響。
  • AWS Lambda:按呼叫計費,需 HTTP-to-stdio 適配層;適合低頻內部工具。
  • Google Cloud Run:容器原生、自動擴縮;SSE 需設定 min-instances ≥ 1 保活。
  • VPS / 裸金屬:完全控制網路與磁碟,適合敏感資料不出內網的 MCP Server。

可觀測性三件套:

  • Logging:structlog 或 python-json-logger,每筆 tool call 記錄 name、duration_ms、status。
  • Prometheus:暴露 mcp_tool_calls_totalmcp_tool_duration_seconds 等指標。
  • Sentry:捕捉未處理例外,關聯 Server 版本 tag 便於回滾。

版本相容性:MCP 規格 2025-03-26 引入 Streamable HTTP;部署前核對 Client(Cursor 版本、Claude Desktop 版本)與 Server SDK 是否支援同一傳輸。建議在 README 中標註 mcp>=1.2.0 等最低版本要求。

綜合實戰專案 —— 知識庫 MCP Server:用 ChromaDB 或 Qdrant 儲存文件向量,watchfiles 監聽目錄變更自動 re-index,暴露 search_knowledgewrite_note 兩個工具。在 Cursor 中接入後,Agent 編碼時可檢索團隊內部文件,而非僅依賴訓練資料。

tools/knowledge.py
@mcp.tool()
async def search_knowledge(query: str, top_k: int = 5) -> list[dict]:
    embedding = await embed(query)
    results = collection.query(query_embeddings=[embedding], n_results=top_k)
    return [{"text": doc, "score": score} for doc, score in zip(...)]

@mcp.tool()
async def write_note(title: str, content: str) -> str:
    doc_id = collection.add(documents=[content], metadatas=[{"title": title}])
    return f"Note saved: {doc_id}"

推薦複用的社群 MCP Server:

  • @modelcontextprotocol/server-filesystem —— 安全沙箱檔案讀寫
  • server-github —— Issue、PR、程式碼搜尋
  • server-brave-search —— 連網即時搜尋
  • server-postgres —— 唯讀 SQL 查詢
  • server-slack —— 頻道訊息與通知

2026 年 MCP 生態關鍵數據:

  • 生態規模:截至 2026 年,公開 MCP Server 已超過 10,000 個,GitHub 上 modelcontextprotocol 組織儲存庫 Star 合計超 50,000
  • 廠商 adoption:2026 年 Q1 OpenAI、Q2 Google Gemini 與 Microsoft Copilot 均已宣布原生 MCP 支援;治理權移交 Linux Foundation 旗下 AAIF。
  • 企業整合成本:採用 MCP 標準化介面後,企業 AI 工具鏈整合開發成本降幅約 38–55%(產業調研口徑)。

學習路徑建議:

  1. 閱讀官方規格,理解 JSON-RPC 訊息流
  2. 用 FastMCP 完成 Hello World + Inspector 除錯
  3. 實作 3 個以上真實 Tools(檔案、HTTP、DB)
  4. 新增 Resources 與 Prompts,體驗三大原語差異
  5. 切換 HTTP 傳輸,Docker 部署到雲端
  6. 接入 Cursor,完成知識庫或 GitHub 整合實戰

以下公開資料可作為規格與 SDK 的核對入口;若上游儲存庫更新,請以連結為準。

Model Context Protocol — 官方規格與文件

modelcontextprotocol/python-sdk — Python MCP SDK

modelcontextprotocol/typescript-sdk — TypeScript MCP SDK

modelcontextprotocol/inspector — MCP Inspector 除錯工具

把 MCP Server 跑在會休眠的筆電上,常見故障是:tools/list 工作階段中斷、OAuth 過期、磁碟滿導致向量庫損壞、網路切換後 SSE 斷連 —— 比「選哪個模型」更影響日常開發體驗。Docker on laptop 仍有宿主機休眠問題;免費 tier PaaS 冷啟動讓長連線頻繁斷開;Lambda 不適合 SSE 常駐場景。

若你需要 7×24 常駐 MCP 工具鏈、穩定 SSH 與可預期的 Apple Silicon 算力,把 Cursor Agent 與自研 Server 遷到獨占裸金屬通常更划算:NOVAKVM 提供多區域 Mac Mini M4 / M4 Pro 彈性租期,適合 Cursor MCP、Claude Desktop 遠端開發與向量庫同機部署。方案見 租用價格頁,下單見 雲端訂購頁,部署問題見 雲端說明中心