iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0
AI Engineering

現代化的 AI 系統設計系列 第 18

[Day18] - Agent 使用 MCP:從工具發現到可驗證的狀態變更

  • 分享至 

  • xImage
  •  

「幫我查 order 123 的退款資格,如果可以就直接退款。」

這句話放進 Agent 之後,模型可能需要先連到訂單 MCP Server 查詢狀態,再連到付款 MCP Server 執行退款。執行期間,Server 可能剛好重新部署、工具清單可能已經更新,兩個 Server 甚至可能都提供同名的 get_order。因此,問題不再只是模型能不能產生正確的 JSON,而是:

Agent 此刻看見了哪些外部能力?它用的是哪個 Server、哪一版定義?呼叫回來之後,什麼證據才足以讓 State 前進?

前面建立的 Agent 已經有 Loop、State、Checkpoint 與 Memory。現在加入 MCP,等於把「下一步可以做什麼」從程式內固定的函式,擴展成執行期間可以協商與更新的能力目錄。這讓整合不同系統變容易,也讓 Runtime 必須多負責一層動態性。


這篇會討論到

MCP 不是把既有工具換一種傳輸格式,而是把外部能力變成一個動態控制面。
可靠的 MCP Agent 至少要把「協商、發現、篩選、路由、呼叫、驗證、提交」分開記錄與判斷。


MCP 進入 Agent 後,能力變成動態的

在只有本地函式的 Agent 裡,工具通常在程式啟動時就註冊完成;模型從固定清單中挑一個名稱,再交給 Harness 執行。MCP 將這個邊界往外推:工具、資料與提示模板可以由不同團隊維護的 Server 提供,Client 在執行期間建立連線並取得能力。

MCP 的 Architecture 把責任分成三個角色:

角色 在 Agent 執行中的責任
Host 持有使用者工作階段、模型與整體 Harness;決定哪些 Server 可以被接上、哪些資料可以進入 Context,以及何時需要同意。
Client 通常一個 Server 一條隔離連線;負責 initialize、能力協商、訊息傳遞與斷線處理。
Server 提供 Tools、Resources、Prompts 等能力;可以獨立部署、更新或暫時不可用。

這個分工帶來一個很容易被忽略的結論:MCP 的工具清單不是靜態設定,而是 Agent 在某一個時間點看到的環境快照。 同一個 Agent,連到不同 Server、不同版本,模型可以做的事情就可能不同。

所以 MCP 解決的是「能力如何互通」,不是「這個能力此刻是否適合使用」。是否允許某個使用者退款、是否仍符合付款服務的前置條件,以及完成後要不要更新業務 State,仍然是應用程式 Runtime 的責任。這正是 MCP Agent 與前面單純的工具呼叫不同的地方。


一次 MCP 執行,從連線生命週期開始

一輪 MCP Agent 執行,不應直接從模型的 tools/call 開始。最小流程可以拆成七個交接點:

  1. 協商:Client 先送 initialize,交換 protocol version 與雙方 capabilities;完成後才送 initialized notification。這是 Lifecycle 規格 定義的第一個生命週期邊界。
  2. 取得目錄:依需求呼叫 tools/listresources/listprompts/list。清單可能分頁,不能假設一次就拿完。
  3. 建立可見集合:Harness 依任務、使用者、Server 狀態與安全政策篩選候選能力,補上 Server namespace,並記錄目錄版本或雜湊。
  4. 提出決策:模型只能從目前可見的候選集合提出工具名稱與參數;這仍是一份意圖,不是外部世界已經改變。
  5. 路由與呼叫:Client 把呼叫送到正確的 Server。若多個 Server 有同名工具,不能只靠工具名稱路由。
  6. 解析結果:依照 outputSchema 驗證 structuredContent,並區分協定層錯誤與工具執行錯誤。isError 是結果訊號,不是業務完成收據。Tools 規格也要求 Client 不要盲信工具的提示性 annotations。
  7. 提交 State:只有應用程式需要的完成證據都出現,控制器才把結果寫入 State、Trace 與後續 Context;否則進入拒絕、補查或 unknown

這七步的價值,在於把「連線當下看見什麼」和「這次呼叫最後造成什麼」分開。若把它們壓成一個 call_tool(),之後就很難回答模型為什麼看見某個工具、呼叫送到哪裡,以及 State 是依據哪一份結果改變。

https://ithelp.ithome.com.tw/upload/images/20260901/20183613kK2Nzq6sH1.png

長時間工具也會放大這個問題。2025-11-25 規格中的 Tasks 是實驗性機制,讓 tools/call 可以先回傳 task,再由 Client 取得延後結果。它解決的是「結果還沒回來時如何保存工作」,不代表付款服務已經完成;最後仍要用領域證據判斷能否提交。


工具發現不是把全部工具塞進 Context

當 Agent 只有三個工具,把完整描述放進 Prompt 看似簡單;接上十個 Server 後,這個做法會同時造成 token 成本、同名衝突與錯誤選擇。更危險的是,模型可能看見一個目前不可用、需要額外核准,或只適用於另一個租戶的工具。

因此,MCP Agent 要有一個「能力目錄層」,至少處理四件事:

  • 篩選:依任務與使用者情境只開放必要的工具。讀取工具與寫入工具可使用不同政策;寫入工具預設不應因為出現在清單中就自動放行。
  • 命名:以 server_name.tool_name 或等價的 namespace 保留來源。order.get_orderlegacy_order.get_order 是兩個不同的能力,Trace 也必須保存完整路由。
  • 快取:工具定義不常變時可以快取,減少每一輪都重新取得清單的成本;但快取必須有版本、到期時間與失效策略。
  • 更新:Server 若宣告 listChanged,收到通知後應讓目錄失效並重新取得,而不是繼續使用舊 Schema。連線失敗時也要隔離該 Server,不能讓一個壞掉的來源污染整個 Agent。

這也是目前 Agent 實作開始出現「延後載入」與「工具搜尋」的原因:模型先看到少量能力或搜尋介面,需要時才載入完整定義。OpenAI Agents SDK 的 MCP 文件把多 Server 管理、工具篩選、分頁、快取與追蹤列成獨立設定;它的實作選擇可以當作工程參考,但核心原則不依賴特定框架:可見工具集合是 Runtime 的輸出,不是 Server 清單的原樣複製。

每次執行至少應在 Trace 留下:Server 身分、連線狀態、協商版本、可見工具集合、篩選原因與目錄版本。如此一來,日後才能重建「模型當時為什麼有這個選項」,而不是只看到最後一個工具呼叫。

https://ithelp.ithome.com.tw/upload/images/20260901/20183613FLg2B15ZEa.png


MCP 回傳結果,距離 State 提交還有一個閘門

MCP 的 tools/call 回應可以是文字內容,也可以在宣告 outputSchema 時回傳 structuredContent。這讓 Client 有機會驗證資料形狀,但形狀正確仍然不等於業務動作完成。

以退款為例,MCP Server 可能回傳:

{
  "isError": false,
  "structuredContent": {
    "status": "accepted",
    "refund_id": "rf_789",
    "provider_receipt": null
  }
}

isError: false 只表示工具沒有把這次執行標成錯誤;status: accepted 可能只是付款服務接受非同步請求。若應用程式需要「退款已完成」,就不能在這一步直接把訂單寫成 refunded,而要等待可查證的付款收據或重新查詢最終狀態。

因此,MCP Client 與業務 Runtime 之間要有自己的執行契約:

server: payment
tool: refund_order
mode: write

before_call:
  - 重新讀取訂單目前狀態
  - 確認訂單屬於目前使用者與任務
  - 確認金額使用訂單原幣,且仍有可退餘額

commit_requires:
  - refund_id
  - provider_receipt
  - observed_at

if_timeout: unknown

https://ithelp.ithome.com.tw/upload/images/20260901/20183613AubPQcQJyv.png

這裡的 rejectedfailedcommittedunknown 是應用層的狀態,不是 MCP 標準列舉:

狀態 Runtime 可以知道什麼 下一步
rejected 呼叫前的形狀、權限或最新前置條件不成立,沒有送出副作用 修正、補問或停止
failed Server 明確回報執行失敗,且可判斷沒有完成 依錯誤處理,不盲目重試
committed 有領域需要的識別碼、收據與觀察時間 更新 State,讓後續 Loop 使用
unknown 請求可能已送出,但目前沒有足夠證據 先查證或等待,不宣告成功、不直接重播

這個閘門把 MCP 的互通契約和系統的完成定義接起來:MCP 負責把結果可靠地傳回來,Runtime 負責決定這份結果是否足以改變世界的描述。

https://ithelp.ithome.com.tw/upload/images/20260901/20183613hL0ai3vF2h.png


Tools、Resources、Prompts:三種能力不是同一路徑

把 MCP 簡化成「遠端工具呼叫」會漏掉 Agent 實際會接觸的另外兩種能力。規格將它們分開,是因為控制權與風險不同:

MCP 能力 誰決定何時使用 進入 Agent 後的處理
Tools 模型提出使用意圖,Client/Host 執行 進入工具篩選、權限、核准、呼叫與結果提交流程
Resources 應用程式或 Host 決定要不要放入 Context 先依 URI、租戶與新鮮度讀取;不能把 Server 的所有資源自動倒進 Prompt。見 Resources 規格
Prompts 通常由使用者或 Host 選擇模板 視為外部指令來源,必須檢查信任、版本與可見範圍。見 Prompts 規格

這三條路徑在 Trace 中也不應混成同一種事件。一次 Resource 讀取,可能只是補充證據;一次 Prompt 取得,可能改變模型的指令上下文;一次 Tool 呼叫,則可能產生外部副作用。把來源與控制者記清楚,之後才能在事故中分辨「模型做了錯誤決策」和「Host 把不該看見的資料放進 Context」。

有些 MCP Server 還會透過 Sampling 請 Client 代為呼叫模型,形成 Server 內的子迴圈。這不會把模型存取權交給 Server:Client 仍應掌握模型、工具權限與人工審核。對 Agent Harness 而言,它只是另一種需要設定深度、預算與停止條件的巢狀執行。


把 MCP Agent 測成可重現的基線

MCP Agent 的測試不該只驗證「JSON 能不能通過」或「呼叫次數是不是一次」。真正要測的是:在能力會變動、Server 會失敗、結果可能延後的環境裡,State 是否仍然正確。

測試情境 應觀察的 Runtime 行為
initialize 版本或 capability 不相容 在協商階段停止,不呼叫未支援的方法;Trace 記錄原因。
Server 發出 listChanged 讓工具快取失效,重新取得目錄,再決定是否重建模型可見集合。
多個 Server 有同名工具 以完整 namespace 路由;Trace 能指出實際 Server,不接受模糊名稱。
Schema 合法但訂單已退款 在副作用前拒絕,重新讀取 State 或要求補充資訊。
isError: false 但沒有付款收據 不提交 committed;標成待查或 unknown
呼叫逾時,結果不明 保存 request id 與 checkpoint,先做查證,不直接重播寫入動作。
Prompt 或工具 annotations 要求提高權限 視為不可信提示,交給政策與核准流程,不讓文字描述自行放行。

這些測試可以從研究工作中找到共同方向。 ToolSandbox 用「必須發生的 milestone」與「絕不能發生的 minefield」評估有狀態工具;τ-bench 把政策與動態 API 放進多輪任務,最後比對資料庫狀態;較新的 E-Bench 則以狀態差異做可重現的寫入型任務評估。它們共同指向同一個工程結論:呼叫軌跡只能說明 Agent 做過什麼,最終狀態與禁止事件才說明它做對了什麼。

如果要先做一個最小的 MCP Agent Baseline,我會要求它至少保存四份資料:

  1. server identity + protocol version + capabilities:當時連到誰、談成什麼。
  2. visible catalog:模型看到哪些工具、為什麼被篩進來,以及使用哪一版 Schema。
  3. call record:模型提出的意圖、實際路由、核准結果與原始回應。
  4. commit evidence:State 為什麼前進;若證據不足,明確留下 unknown 與後續查證工作。

做到這裡,MCP 才不只是「讓 Agent 呼叫外部 API」的接線工作,而是讓 Agent 可以在動態環境裡取得能力,同時保留可重建、可拒絕、可恢復的執行邊界。

下一個要接上的問題會是:即使工具已被發現、路由也正確,誰有權使用它?在什麼條件下需要人工核准? 那會把 Identity、Permission、Policy 與 Approval 接到這條 MCP 執行鏈上;unknown 之後的查證、冪等與補償,則留給後續的可靠執行主題。


AI 你怎麼看?

挑一個你正在使用的 MCP Server,試著回答三件事:Agent 看見的是哪一版能力目錄?一次寫入型呼叫的完成證據是什麼?如果 Server 在途中更新工具定義或回傳未知結果,Runtime 會在哪一個閘門停下來?

https://ithelp.ithome.com.tw/upload/images/20260901/20183613F6yHY691L2.png



上一篇
[Day17 ] - Agent 記住得越多越好嗎?Memory 的寫入、取回、修正與遺忘
系列文
現代化的 AI 系統設計18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言