指南
MCP 伺服器
讓 Agent 調用你系統裡的工具。
MCP(Model Context Protocol)是 Agent 調用外部工具的開放協議。把你的系統(例如訂單查詢、工單系統、內部 API)封裝成一個遠端 MCP 伺服器,註冊到項目後,在建立會話時用 mcp_servers 指定,這個會話的每一輪開始時平台都會連接它,連上後 Agent 就能調用它的工具。
與技能的區別:技能是說明和腳本,在平台的沙箱裡執行;MCP 伺服器由你託管,Agent 遠端調用,適合需要訪問你內網數據、帶權限控制、或邏輯經常變化的場景。兩者可以同時使用,例如技能裡寫「查訂單用 shop 的 lookup_order 工具」。
你的伺服器需要滿足
- 傳輸:MCP 的 Streamable HTTP 傳輸(2025-03-26 及之後的規範),一個
https端點,通常以/mcp結尾。舊的 HTTP + SSE 傳輸(/sse端點)不支援。證書必須是有效的公網證書,自簽名證書無法通過。 - 可達性:平台從自己的伺服器連接你的端點,所以地址必須是公網地址,不能解析到內網、本機或鏈路本地地址(例如
10.x、192.168.x、127.0.0.1、169.254.x)。平台不跟隨 HTTP 跳轉,請直接填最終地址。 - 鑑權:三種方式之一——不鑑權、
Authorization: Bearer <token>、或自訂請求頭(例如X-Api-Key)。憑證是靜態的;不支援需要瀏覽器授權的 OAuth 流程。 - 工具:透過
tools/list列出。註冊時最多保留 256 個工具,名字 ≤ 128 字元,描述取前 500 字元存檔(Agent 調用時看到的是完整描述)。每個工具請寫清楚用途、參數含義和返回內容——Agent 只能根據名字和描述決定何時調用、怎麼填參數。 - 副作用:工具會被 Agent 自動調用,平台不會在調用前徵求人工確認。對有副作用的操作(下單、退款、刪除),請在伺服器端做好權限驗證和冪等處理,或者不要暴露給 Agent。
一個最小的 Python 伺服器(mcp SDK 2.x + uvicorn),帶 Bearer 鑑權:
import os
import uvicorn
from mcp.server.mcpserver import MCPServer
from mcp.server.transport_security import TransportSecuritySettings
TOKEN = os.environ["MCP_TOKEN"]
server = MCPServer(name="shop-mcp", version="0.1")
@server.tool(description="按訂單號查詢訂單狀態。")
def lookup_order(order_number: str) -> str:
return f"訂單 {order_number}:已發貨"
# 在反向代理(nginx 等)後面時,SDK 預設會拒絕它不認識的 Host;關掉這項檢查,
# 或改為 TransportSecuritySettings(allowed_hosts=["mcp.example.com"])。
mcp_app = server.streamable_http_app(
stateless_http=True,
transport_security=TransportSecuritySettings(enable_dns_rebinding_protection=False),
)
async def app(scope, receive, send):
"""Bearer 驗證,其餘交給 MCP SDK。"""
if scope["type"] == "http":
headers = dict(scope["headers"])
if headers.get(b"authorization") != f"Bearer {TOKEN}".encode():
await send({"type": "http.response.start", "status": 401, "headers": []})
await send({"type": "http.response.body", "body": b"unauthorized"})
return
await mcp_app(scope, receive, send)
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8017)用 nginx 等反向代理加上 https,端點就是 https://your-domain/mcp。
註冊
註冊時平台會先探測一次:用你給的憑證完成 MCP 握手,列出工具(最長等 60 秒)。通過才保存,地址或憑證寫錯會在這一步報錯。
curl -s "$AXON_API/mcp-servers" \
-H "Authorization: Bearer $AXON_KEY" -H "Content-Type: application/json" \
-d '{
"name": "shop",
"url": "https://mcp.example.com/mcp",
"auth": {"type": "BEARER", "token": "your-mcp-token"},
"allowed_tools": ["lookup_order", "create_ticket"]
}'name:工具的命名空間,項目內唯一。改名會改變工具名。url:建立後不能改;要換地址,刪掉重新註冊。同一個地址在項目內只能註冊一次。auth:{"type": "NONE"}、{"type": "BEARER", "token": "…"}或{"type": "HEADER", "name": "X-Api-Key", "value": "…"}。憑證加密保存,任何接口都不會返回它;回應裡的auth只有類型(和請求頭的名字)。allowed_tools:只讓 Agent 使用這些工具,名字必須在探測到的tools裡,否則返回422 unknown_mcp_tool。不填或null表示全部。注意區別:null時你的伺服器之後新增的工具,下一輪會自動可用;設了白名單時,新工具要先用 PATCH 加進白名單。- 回應裡的
tools是探測到的工具快照,server_name是伺服器自報的名字。
探測失敗返回 422 mcp_probe_failed,message 說明原因:
| message 開頭 | 含義 |
|---|---|
TLS verification failed | 證書無效、過期或域名不匹配 |
The MCP server rejected the credential (401) / (403) | 憑證錯誤,或鑑權方式填錯(例如該用 HEADER 卻填了 BEARER) |
The server answered, but not with MCP | 地址指向了網頁或其他接口,不是 Streamable HTTP 端點;舊的 /sse 端點也會這樣 |
The MCP server answered HTTP 5xx/4xx | 伺服器報錯,看你那邊的日誌 |
The MCP server did not finish … in time | 60 秒內沒完成握手和列出工具 |
The MCP server could not be reached | 連不上:端口未開放、防火牆、DNS 等,後面附具體錯誤 |
地址本身不合規(不是 https、解析到內網等)返回 422 invalid_mcp_server_url。
在會話中使用
建立會話時用 mcp_servers 指定伺服器 ID(最多 10 個,需要 mcp_servers:read 權限)。和模型、指令一樣,會話的 MCP 伺服器建立後不能改;要換,就新建會話。
curl -s "$AXON_API/sessions" \
-H "Authorization: Bearer $AXON_KEY" -H "Content-Type: application/json" \
-d "{\"model_id\": \"deepseek-v4-flash\", \"mcp_servers\": [\"$MCP\"]}"每一輪裡發生的事:
- 輪次開始時,平台用註冊時的憑證連接會話指定的所有伺服器(並行,每個最多等 20 秒),列出工具,交給 Agent。連接每輪新建、本輪結束斷開,你的伺服器不需要維持長連接。
- 這些工具與內置工具的調用方式相同:
agent.tool_use的name為mcp__<name>__<工具名>,input是工具參數;你的伺服器返回的結果出現在agent.tool_result的content裡(文字;過長會截斷)。伺服器返回的錯誤會以is_error: true交給 Agent,由 Agent 決定是否調整參數重試。 - 每次連接的結果記錄在伺服器上:成功寫
last_connected_at並清空last_connect_error,失敗寫last_connect_error。排查「Agent 沒有調用我的工具」時先看這兩項。
{"type": "agent.tool_use", "name": "mcp__shop__lookup_order", "input": {"order_number": "A1001"}, …}
{"type": "agent.tool_result", "content": "訂單 A1001:已發貨", "is_error": false, …}工具名的規則:mcp__<name>__<工具名>。伺服器名稱裡的連字元變成底線,例如 my-shop 的工具叫 mcp__my_shop__lookup_order;工具名裡字母、數字、底線以外的字元也替換成底線;整體超過 64 字元時截斷並附一段短哈希。
連接失敗時(伺服器掛了、憑證失效、超過 20 秒):這一輪 Agent 沒有該伺服器的工具,並被明確告知「這些工具本輪不可用,不要調用」,輪次照常進行,其他伺服器不受影響;下一輪會重新連接。失敗原因寫在 last_connect_error 裡,查詢 MCP 伺服器可以看到。
修改與維護
| 要做什麼 | 怎麼做 | 影響 |
|---|---|---|
| 換憑證(輪換 token) | PATCH 傳新的 auth | 用新憑證重新探測,通過才保存;已有會話下一輪起用新憑證 |
| 改名 | PATCH 傳 name | 工具名隨之改變,已有會話下一輪起看到新名字 |
| 調整白名單 | PATCH 傳 allowed_tools,null 取消限制 | 名字必須在當前 tools 裡;下一輪生效 |
| 伺服器新增或刪除了工具 | POST …/probe 重新探測 | 刷新 tools 快照(白名單為 null 時,Agent 每輪連接時拿到的已是最新工具,探測只更新接口裡看到的快照) |
| 換地址 | 刪除後重新註冊 | 新的 ID;引用舊 ID 的會話從下一輪起沒有它的工具 |
| 刪除 | DELETE | 已指定它的會話不受影響,但從下一輪起不再連接,Agent 不再有它的工具(不會收到提醒);已發出的事件不變;名字和地址可以給新伺服器使用 |
接口細節見修改 MCP 伺服器、重新探測、刪除 MCP 伺服器。
安全
- 只接受
https和公網地址;連接時再次驗證,並且連接固定到驗證過的 IP、不跟隨跳轉,防止透過 DNS 把平台引向內網。 - 憑證加密保存,只在連接你的伺服器時解密使用;接口不返回,日誌裡也不記錄。
- 平台從自己的伺服器發起連接。如果你的伺服器按來源 IP 限制訪問,請聯絡我們取得出口地址。
- 工具調用是 Agent 自主發起的。請把 MCP 伺服器當成一個帶權限的 API 來設計:只暴露必要的工具,按憑證區分權限,關鍵操作在伺服器端驗證。
排查 MCP 問題
| 現象 | 看什麼 |
|---|---|
註冊返回 422 mcp_probe_failed | 按上面的 message 對照表處理;先用 curl 從公網訪問一次你的端點 |
註冊返回 422 invalid_mcp_server_url | 地址不是 https,或域名解析到了內網/本機 |
| Agent 沒有調用工具 | 先看伺服器的 last_connect_error;為空再檢查 allowed_tools 是否把工具排除了,以及工具描述是否足夠清楚;建立會話時是否真的傳了 mcp_servers |
| 工具調用返回錯誤 | agent.tool_result 的 content 是你的伺服器返回的錯誤文字,到伺服器日誌裡對照 |
| 改了伺服器但 Agent 還在用舊工具 | 已有會話下一輪才會重新連接;白名單模式下新工具要先加進 allowed_tools |