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

約 22 分鐘閱讀 · MACCOME

若你想讓 Claude、Cursor 或 Gemini 直接查公司資料庫、讀內部文件、執行自訂 API,卻卡在「Function Calling 寫了三次、換模型又要重寫」——本文是 2026 年面向後端與 AI 工程師的 MCP Server 動手教學。你會得到:協定原理速覽、Python FastMCP 環境、Hello World 到 Tools/Resources/Prompts 完整範例、HTTP+SSE 遠端模式、MCP Inspector 除錯,以及 ChromaDB 知識庫實戰。結構:六道痛點 → 三大能力對照表 → 八步落地 → 三條硬數據 → 生態展望 → FAQ。協定層背景請先讀MCP 為何是 AI 時代 HTTP;與Agent Skill 指南互補——Skill 教 Agent「怎麼做」,MCP 提供「能做什麼工具」。

六道痛點:為什麼「硬寫 Function Calling」撐不住

  1. 每換一個 LLM 就要重寫工具層:OpenAI、Anthropic、Google 的 schema 與呼叫格式各異,N×M 整合成本線性爆炸。
  2. 工具清單寫死在 Prompt 裡:新增一個 API 就要改 system prompt,AI 無法在執行時期動態發現新能力。
  3. 混淆 Tools、Resources、Prompts:把唯讀文件當可執行函式,或把提示範本當 API,除錯時 JSON-RPC 報錯難以定位。
  4. 只在本地 STDIO 跑通就上大線:跨團隊共享時未評估 HTTP+SSE 的工作階段親和性與 TLS,長連線頻繁斷線。
  5. 跳過 MCP Inspector 直接接 Cursor:Host 層錯誤訊息被包裝,看不出是 Server 還是 Client 的 schema 問題。
  6. 在會睡眠的筆電上跑知識庫 Server:向量索引載入需穩定記憶體與 7×24 在線,合蓋即斷,Agent 工作流無法常駐。

MCP(Model Context Protocol) 用開放標準把「AI 如何發現、選擇並呼叫工具」統一起來。本篇不重複協定辯論,直接帶你從空目錄寫出第一個可連 Cursor 的 Server。

一、MCP 協定原理:Host、Client、Server 與 JSON-RPC

三層角色

  • Host(宿主):Claude Desktop、Cursor、VS Code——內嵌 MCP Client,維護與每個 Server 的 1:1 工作階段。
  • Client:向 Server 發送 initializetools/listtools/call 等 JSON-RPC 請求。
  • Server:你將要寫的程式——暴露 Tools、Resources、Prompts,再對接資料庫、REST API、檔案系統。

傳輸層選型

本地開發首選 STDIO(標準輸入/輸出):Host 以子行程啟動 Server,零連接埠衝突。跨網路共享用 HTTP + SSE:Client 透過 SSE 接收 Server 推送,適合遠端伺服器部署。

能力 Tools Resources Prompts
本質 可執行函式,有副作用 唯讀資料 URI 預設提示範本
典型用途 查 DB、發 Slack、跑腳本 讀設定檔、知識庫片段 程式碼審查、PR 摘要範本
RPC 方法 tools/listtools/call resources/listresources/read prompts/listprompts/get
Agent 使用頻率 最高(核心「手腳」) 中(補充上下文) 低(標準化重複任務)
json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "query_users",
    "arguments": { "limit": 10 }
  },
  "id": 2
}
info

與 REST 的差別:REST 解決「能不能呼叫 endpoint」;MCP 讓 AI 在執行時期透過 tools/list 動態發現工具,且每個 Tool 自帶 JSON Schema 描述參數。詳見協定解讀文

二、環境準備:Python 3.11+ 與 FastMCP

本篇以 Python + 官方 Python SDK 的 FastMCP 為主;TypeScript 團隊可對照 @modelcontextprotocol/sdk,API 概念一致。

bash
mkdir my-mcp-server && cd my-mcp-server
python3 -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install "mcp[cli]" chromadb   # FastMCP + 後續知識庫實戰

# 驗證 CLI
mcp --help

目錄建議:

text
my-mcp-server/
├── server.py          # MCP Server 主程式
├── requirements.txt
├── .env               # API Key、DB 連線(勿提交 Git)
└── data/              # 本地知識庫向量索引

三、Hello World:最小可運行 Server

以下 Server 暴露一個 ping 工具,確認 JSON-RPC 握手成功:

python
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("hello-mcp")

@mcp.tool()
def ping(message: str = "hello") -> str:
    """回傳確認訊息,用於連線測試。"""
    return f"pong: {message}"

if __name__ == "__main__":
    mcp.run()  # 預設 STDIO 傳輸

終端機測試(不透過 Host):

bash
# 安裝 MCP Inspector(Node 18+)
npx @modelcontextprotocol/inspector python server.py

Inspector 開啟瀏覽器 UI,可手動發 tools/listtools/call,確認 ping 出現在清單且能回傳 pong

Cursor 設定(STDIO 模式)

在 Cursor Settings → MCP → Add Server,或編輯 ~/.cursor/mcp.json

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

四、Tools:讓 AI 查資料庫與呼叫 API

Tool 是 MCP 的核心。FastMCP 用型別註解自動生成 JSON Schema;docstring 會成為 AI 理解用途的說明。

python
import os
import httpx
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("biz-tools")

@mcp.tool()
async def get_weather(city: str) -> str:
    """查詢指定城市的即時天氣(示範外部 API 整合)。"""
    api_key = os.environ.get("WEATHER_API_KEY", "")
    async with httpx.AsyncClient() as client:
        r = await client.get(
            f"https://api.example.com/weather?q={city}&key={api_key}"
        )
        return r.text

@mcp.tool()
def query_users(limit: int = 10) -> list[dict]:
    """從 PostgreSQL 查詢使用者列表。limit 上限 100。"""
    limit = min(max(limit, 1), 100)
    # 實務中替換為 psycopg / SQLAlchemy 查詢
    return [{"id": 1, "name": "demo", "limit_used": limit}]
warning

安全紅線:Tool 內一律做參數校驗與權限檢查;勿把 raw SQL 或 shell 指令直接暴露給 AI。生產環境在 Server 層集中管理 API Key,而非寫進 Prompt。

五、Resources:暴露唯讀文件與設定

Resources 以 URI 識別,適合讓 AI 讀取不需「執行」的靜態內容——設定檔、Markdown 知識片段、OpenAPI spec。

python
from pathlib import Path
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("docs-server")
DOCS = Path(__file__).parent / "docs"

@mcp.resource("docs://readme")
def readme() -> str:
    """專案 README 全文。"""
    return (DOCS / "README.md").read_text(encoding="utf-8")

@mcp.resource("docs://api-spec")
def api_spec() -> str:
    """內部 REST API OpenAPI 規格。"""
    return (DOCS / "openapi.yaml").read_text(encoding="utf-8")

Client 透過 resources/list 發現 URI,再以 resources/read 拉取內容——與 Tools 的「執行」語意明確分離。

六、Prompts:標準化重複性 Agent 任務

Prompts 提供帶參數的提示範本,Host 可一鍵注入對話上下文,減少使用者反覆貼同一段指令。

python
from mcp.server.fastmcp import FastMCP
from mcp.types import PromptMessage, TextContent

mcp = FastMCP("review-prompts")

@mcp.prompt()
def code_review(language: str = "python", focus: str = "security") -> list[PromptMessage]:
    """產生程式碼審查提示,聚焦指定語言與審查面向。"""
    text = f"""請審查以下 {language} 程式碼,重點檢查:{focus}。
列出:1) 高風險問題 2) 建議修復 3) 可選重構。使用繁體中文回覆。"""
    return [PromptMessage(role="user", content=TextContent(type="text", text=text))]

七、HTTP 傳輸:跨團隊共享遠端 Server

當 STDIO 子行程無法滿足「多 Client 共用同一 Server」時,改用 HTTP+SSE。FastMCP 支援以 Starlette / uvicorn 啟動:

python
# server_http.py — 在原有 FastMCP 實例上
if __name__ == "__main__":
    mcp.run(transport="sse", host="127.0.0.1", port=8765)
json
{
  "mcpServers": {
    "remote-biz-tools": {
      "url": "https://mcp.example.com/sse",
      "headers": { "Authorization": "Bearer YOUR_TOKEN" }
    }
  }
}

注意事項:

  • TLS 必開:生產環境禁止明文 HTTP 暴露 MCP 端點。
  • 工作階段親和:SSE 長連線需 sticky session 或單實例部署,水平擴展比無狀態 REST 複雜。
  • OAuth 2.1:2026 年 MCP 規範正推進標準化身份驗證,企業內網可先以 mTLS + Bearer Token 過渡。

八、除錯與測試:MCP Inspector 與日誌

推薦除錯流程:

  1. Inspector 單獨驗證 Servernpx @modelcontextprotocol/inspector python server.py,排除 Host 設定問題。
  2. 檢查 stderr:STDIO 模式下 log 必須寫 stderr,不可污染 stdout(會破壞 JSON-RPC)。
  3. schema 驗證:Tool 參數型別與 docstring 不一致時,tools/call 會回傳 -32602 Invalid params
  4. Cursor MCP 日誌:Help → Toggle Developer Tools → Console,搜尋 mcp 關鍵字。
症狀 可能原因 處置
Server 無法啟動 Python 路徑錯誤、venv 未啟用 在 mcp.json 寫絕對路徑;Inspector 先跑通
tools/list 為空 裝飾器未生效、import 失敗 確認 @mcp.tool()run() 前註冊
HTTP SSE 頻斷 反向代理逾時、筆電睡眠 調 Nginx proxy_read_timeout;遷至 7×24 節點
Authorization 失敗 Token 過期、Header 名稱不符 對照 Server middleware 與 Client headers

九、生產部署:Docker 常駐與健康檢查

將 Server 容器化,便於在雲端伺服器以固定設定重啟:

dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8765
CMD ["python", "server_http.py"]
yaml
# docker-compose.yml
services:
  mcp-server:
    build: .
    ports: ["8765:8765"]
    env_file: .env
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://127.0.0.1:8765/health"]
      interval: 30s
      timeout: 5s
      retries: 3

部署檢查清單:Secrets 走環境變數或 Vault;限制 Tool 的網路 egress;對外只暴露 SSE 端點而非整台主機 SSH。

十、實戰專案:ChromaDB 個人知識庫 MCP Server

整合向量資料庫,讓 Cursor 能語意搜尋你的筆記與文件:

python
import chromadb
from chromadb.utils import embedding_functions
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("kb-search")
client = chromadb.PersistentClient(path="./data/chroma")
ef = embedding_functions.DefaultEmbeddingFunction()
collection = client.get_or_create_collection("notes", embedding_function=ef)

@mcp.tool()
def search_notes(query: str, n_results: int = 5) -> list[dict]:
    """語意搜尋個人知識庫,回傳最相關的筆記片段。"""
    n_results = min(max(n_results, 1), 20)
    res = collection.query(query_texts=[query], n_results=n_results)
    out = []
    for doc, meta, dist in zip(res["documents"][0], res["metadatas"][0], res["distances"][0]):
        out.append({"text": doc, "source": meta.get("source", ""), "distance": dist})
    return out

@mcp.tool()
def ingest_note(text: str, source: str = "manual") -> str:
    """寫入一則筆記到向量索引。"""
    import uuid
    collection.add(documents=[text], metadatas=[{"source": source}], ids=[str(uuid.uuid4())])
    return f"ingested: {len(text)} chars from {source}"

首次 ingest 後,在 Cursor 中問「搜尋知識庫:MCP 部署注意事項」,Agent 應呼叫 search_notes 並引用回傳片段。向量索引建議放在持久化卷,避免容器重建後資料遺失。

十一、生態展望:10,000+ Server 與垂直藍海

  • 2026 年生態規模:社群與官方 registry 已超過 10,000 個 MCP Server;每新增一個 Server,所有支援 MCP 的 Client 立即可用。
  • 四大雲端託管:Google Cloud、Azure、AWS 均已提供託管 MCP 接入,企業可把內網 API 封裝為 Server 而不綁定單一 LLM。
  • AAIF 治理:Linux Foundation 旗下 Agentic AI Foundation 接手協定治理,OAuth 2.1 與統一 registry 列入路線圖。
  • 垂直機會:財務報表、CRM、DevOps Runbook、合規審查——寫一次 Server,Claude / GPT / Gemini 共用,仍是 2026 年開發者藍海。

八步落地:從空目錄到生產可用

  1. 讀協定速覽:確認 Host/Client/Server 分工(可速讀MCP HTTP 協定文)。
  2. 建立 venv 並安裝 mcp[cli]:Python 3.11+,驗證 mcp --help
  3. Hello World + Inspectorping 工具跑通 STDIO。
  4. 接入 Cursor mcp.json:用絕對路徑指向 venv 的 python 與 server.py。
  5. 實作核心 Tools:先接一個真實 API 或資料庫查詢,附參數校驗。
  6. 按需加 Resources / Prompts:唯讀文件走 Resource,重複任務走 Prompt。
  7. HTTP+SSE 與 Docker:跨團隊共享時容器化,配置 TLS 與 healthcheck。
  8. 遷至 7×24 節點:知識庫索引與長連線 Agent 避開會睡眠的筆電,改用穩定雲端 Mac 或 Linux 伺服器。

三條可寫進技術評審的硬數據

  • 整合成本降幅 38–55%:同一 MCP Server 可在 Claude → GPT → Gemini 間切換,無需重寫工具層(資料來源:2026 年企業 AI 整合調研綜述)。
  • 生態 10,000+ Server:網路效應已過臨界點;社群 Server 覆蓋 GitHub、PostgreSQL、Slack、瀏覽器自動化等主流場景。
  • Inspector 除錯效率:在接入 Host 前用 Inspector 驗證,平均可將「連不上 MCP」工單排查時間從數小時縮至 15 分鐘 以內(站內多個 OpenClaw/MCP 實操文的一致經驗)。

結語:寫一次,到處跑——但別在會睡的機器上跑

從 Hello World 到 ChromaDB 知識庫,你已掌握 MCP 三大能力與兩種傳輸模式。下一步可以是:把公司內網 API 封裝成 Tools、用 Resources 暴露合規文件、用 Prompts 標準化 code review 流程。

但若把知識庫向量索引與 HTTP+SSE 長連線跑在會睡眠的筆電、或與同事共用、記憶體與 CPU 被搶佔的開發機上,你會遇到三項隱性成本:SSE 工作階段因合蓋中斷、索引載入失敗導致 Tool 呼叫重試、以及無法維持 7×24 Agent 編排。對需要穩定 MCP 工作階段的生產環境,把 Server 落在 MACCOME Mac mini(M4 / M4 Pro)獨占節點,通常比在本地與睡眠策略搏鬥更省總成本;公開檔位見Mac Mini 雲端租用價格,接入問題可參考雲端 Mac 協助中心

常見問題

MCP Server 應該用 Python 還是 TypeScript 開發?

兩者皆有官方 SDK。Python 的 FastMCP 上手最快,適合後端與資料庫整合;TypeScript 適合 Node.js 生態。建議先用 Python 完成 STDIO 驗證,再評估 HTTP 部署。

Tools、Resources、Prompts 三者有什麼差別?

Tools 是可執行函式;Resources 是唯讀 URI 資料;Prompts 是提示範本。Agent 工作流以 Tools 為主。協定層對照見MCP 協定解讀

MCP 和 Agent Skill(SKILL.md)怎麼配合?

Skill 教 Agent「何時、按何步驟」完成任務;MCP 提供可呼叫的工具。詳見Agent Skill 指南

生產環境如何常駐 MCP Server?

本地開發用 STDIO;跨團隊用 HTTP+SSE + Docker。避免筆電合蓋中斷長連線。MACCOME 提供 M4/M4 Pro 雲 Mac 獨占節點,適合 7×24 MCP 常駐。報價見租用價格頁