跳到內容

05|把後端接成 MCP 工具

Agent 透過 MCP 探索業務資料與呼叫查詢。MCP 是協定介面;真正的 middleware 是後面的身分驗證、輸入限制、SQL 建構與憑證管理程式。

工具 輸入 輸出
whoami 無 驗證後的使用者、角色與資料範圍
describe_business_data 無 業務定義、欄位、輸入 Schema 與限制
query_orders query 物件 訂單、實際 SQL、參數、分頁、request ID、撤銷結果

官方 Python MCP SDK 2.3.0 與 FastAPI 共用同一服務;sso/mcp_api.py 負責協定與 OAuth,sso/orders.py 負責參數及 SQL,sso/bao.py 共用短效憑證流程。

完成前章後,在自己的主機執行:

終端機視窗
python3 scripts/configure_mcp.py
docker compose up -d --build --no-deps sso
docker compose exec -T gateway nginx -s reload

建立 textile-codex public client,使用 PKCE S256、scope orders:read,audience 綁定完整 MCP URL。沒有 client secret、password grant 或 wildcard callback。既有 Web 與 Grafana clients 保持獨立。

Nginx 已包含 MCP 與 protected-resource metadata 路徑。Tailscale 還要轉送 discovery:

終端機視窗
tailscale serve --bg --https=28100 --set-path=/.well-known/oauth-protected-resource/textile/mcp http://127.0.0.1:28400/.well-known/oauth-protected-resource/textile/mcp
{
"query": {
"as_of": "2026-10-20",
"overdue_only": true,
"remaining_only": true,
"sort_by": "oldest_due",
"limit": 10,
"offset": 0
}
}

可另加 customer_id、status、order_date_from、order_date_to。排序僅允許 oldest_due、largest_remaining、newest_order。每頁 1–50 筆、offset 0–5000;日期 2020–2100,不接受反向日期範圍。

不能傳 sql、user、租戶 ID 或資料庫密碼。參數必須是預定型別;多餘欄位拒絕。每頁上限不等於累積匯出額度,這仍是後續要補的控制。

把 limit 改成 500,或加入 sql: "SELECT * FROM hr.payroll"。預期工具拒絕輸入,而不是讓模型自行決定要不要遵守。

後端仍會驗證 JWT 的簽章、issuer、MCP URL audience、期限、subject、Bearer 類型及 client,然後驗證 scope 與業務角色。Portal 的 Token 不能拿來當 MCP Token。

終端機視窗
docker compose exec -T sso python - < scripts/verify_mcp.py

預期 32 項通過,包括錯誤簽章/audience/scope、HR 拒絕、輸入注入、排序、分頁、範圍外客戶為空及撤銷。驗證使用測試簽章鍵,但 OpenBao 和 PostgreSQL 是真實服務;下一章再用真實 OAuth Agent 驗證。

若要支援「按客戶彙總」,先寫清楚單位、取消單處理、範圍與結果上限,再新增輸入 Schema 與參數化查詢。不要把受控工具直接改成 execute(sql: str) 就視為完成安全的動態 SQL。

來源:Python MCP SDK · Keycloak MCP 整合。