跳到主要內容

【2026 最新】MCP 逾時結果驗證怎麼做?外部收據、Trace 與 3 種故障注入教學

最後更新: ·
MCP 逾時結果驗證 教學首圖

你請 AI Agent 用 MCP 工具新增一筆待辦,畫面等到逾時,Agent 卻說「已完成」。這時的 MCP 逾時結果驗證,不能只看那句回答:請求可能還沒送到、已寫入但回覆遺失,或工具回了成功卻沒有把資料真正存好。

這篇寫給第一次替 Agent 接上會改資料的工具的人。你不必先懂分散式系統;我會用一筆虛構待辦,帶你畫出事件、收據、回查與重試的路線。會寫程式的人可把後面的偽程式碼改成自己的 MCP adapter;只想審核流程的人,也能拿三個故障測例驗收團隊的實作。

先說結論:MCP 逾時結果驗證要查三層

一句話記住:完成=呼叫有紀錄+目標狀態已核對+收據留在 Agent 改不到的地方。像快遞送貨:寄件單是工具請求,司機說「送達」是工具回覆,收件人的簽收紀錄才是交付結果。三張紙有不同的證明力。

  • 送出:Client 發出哪一次工具請求?有沒有抵達 Server?
  • 執行:Server 是否開始處理,回了成功、錯誤,還是 Client 先逾時?
  • 驗收:由誰從目標系統重新讀到正確資料?外部紀錄端是否收到不可由 Agent 刪改的結果收據?

MCP 官方的 Tools 規格把工具呼叫定義成 request/result;Python SDK OpenTelemetry 文件說明工具事件可以形成 span。這兩種訊號幫你追路徑;本文再由應用程式建立「讀回目標狀態」的業務驗收,讓寫入結果可以查證。若要先補 Agent 整體工作流程,可讀 Agent Harness 白話解釋。

MCP 逾時結果驗證:先把四種狀態說清楚

假設 Agent 要把待辦 task-42 的狀態改成 done。逾時是一種「我等不到答案」的觀察,不是「沒有執行」的判決。讓前端介面只顯示「待查」,直到獨立回查確認目標狀態。

  • 未送達:Client 送出意圖,但 Server 沒有收件事件;目標查無變更。這是候選的可重試狀態,仍要先查目標。
  • 已寫入、回覆遺失:Server 與目標系統有成功紀錄,Client 只看到 timeout。此時重送新意圖會有重複副作用風險。
  • 回覆成功、寫入失敗:工具把「已接單」誤當「已落盤」,或沒有檢查下游錯誤。應用程式要拒絕把它列為完成。
  • 證據衝突:收據說已寫入,但目標查不到,或事件缺頁。保持 unknown,交由對帳或人工排查。

這裡的 unknown 是刻意設計的業務狀態,不是模型回答的語氣。這個概念和 Agentic Transaction 的對帳與冪等相通;本文進一步處理 MCP 邊界、收據寫入權限與 Trace 被刪改的檢查。

MCP 逾時後分開檢查請求、工具回覆與目標狀態的三層流程
一次工具呼叫的三層證據;最後一層必須讀取目標狀態。

實作第 1 步:替同一個意圖綁定四個識別值

不要只靠一串聊天文字找事故。每個任務建立 run_id;每次 MCP 呼叫建立 call_id;把同一個業務動作固定到 operation_id;追蹤系統另有 trace_id。前兩者幫你找這次對話與封包,第三個用來對帳和安全重試,第四個把跨服務 span 接起來。

最小事件列可以長這樣。這是教學用欄位設計,不是 MCP 規格要求的完整封包,也不含任何真實客戶資料。

{"run_id":"run-demo-1","call_id":"call-1","operation_id":"task-42:done:v1","trace_id":"<trace-id>","stage":"client.sent","observed_at":"<UTC timestamp>"}

在 Client wrapper 記 client.sent、client.timeout、client.result_received;在 Server 邊界記 server.received、server.effect_requested、server.effect_confirmed、server.result_sent。時間用 UTC,事件另加單調遞增序號;跨機器時鐘可能有偏差,排序先依同一邊界的序號,再用關聯 ID 對上其他邊界。

OpenTelemetry Trace API定義了 trace/span ID、span event 與 status。它適合定位哪一段等待;但 span 的 Ok 是應用程式對該段操作的判定,不能拿來取代目標資料庫的回查。想看一般 Agent 監控的工具、Token 與成本視角,可接著讀 Agent Observability 入門。

實作第 2 步:把「結果收據」交給另一個權限域

真正關鍵的收據由執行寫入的可信服務產生,而不是由模型口述。收據最少包含 operation_id、目標物件 ID、預期狀態、實際讀回的狀態或版本、執行結果、時間與來源服務身分。避免把 API key、原始提示或個資整包丟進去。

做一個獨立的 append-only 收據端:MCP Server 用限定憑證只能新增事件;Agent 執行環境拿不到改寫或刪除收據的權限;審核者另用唯讀身分查詢。若 Agent 對整台主機都有管理權,單靠同機資料夾權限仍會失守,收據應跨主機或跨管理權限存放。

OWASP Logging Cheat Sheet要求保護日誌傳輸與儲存的完整性,並限制修改、刪除權限。2026 年 9 月 24 日的 Trace 篡改研究初版在特定 harness、權限與測例中觀察到本機軌跡被刪改;它提醒我們劃清記錄權限,並不能推論每個 Agent 或每個部署都會如此。

外部收據也有自己的失敗模式:發送端還沒送出就崩潰、collector 佇列滿、目標狀態在回查後又被別的流程修改。因此對高價值動作,要把業務寫入與 outbox 事件放在同一個本地交易,讓背景 worker 再投遞;收據端回 ACK 後才把「收據已保存」標成真。OTel Collector 官方監測文件列有隊列滿、匯出失敗與掉資料的監測指標;不要把「我呼叫了 collector」當成收據已保存。

實作第 3 步:三個故障注入,逐一核對

用測試環境與虛構待辦,固定同一個 operation_id,每一輪清空測例狀態。故障開關放在 Client wrapper、MCP Server 與資料寫入 adapter 的不同位置;不要讓模型代替測試器判定 pass/fail。

① Client 逾時,Server 尚未執行

在傳送後、Server handler 前阻斷請求。預期可見 client.sent 與 client.timeout,卻查不到 server.effect_confirmed;目標物件仍是原狀。判定為 unknown,回查後才考慮用同一個 operation_id 重試。只看「沒有 server log」還不夠,因為 log 本身可能遺失。

② 已寫入,但成功回覆遺失

讓資料庫成功提交,再在回覆抵達 Client 前斷線。預期 Client timeout、Server 有提交事件、目標狀態與版本符合預期,收據端也有同一操作的紀錄。Agent 對外應報「已核對完成」,而非再造一把新 key 重送。

③ 回覆成功,但下游寫入失敗

讓 adapter 回傳持久化失敗,卻模擬上層錯誤地生成成功文字。預期測試器檢出:client.result_received 存在,但目標狀態不符,且沒有可核對的成功收據。這一輪必須算失敗;修正 handler,使它在下游確認前不回成功。MCP Python SDK 錯誤處理文件的官方 SDK 說明也提醒:把錯誤文字當一般工具字串回傳,可能讓模型誤認工具成功;要用正確錯誤語意。

這三組都是建議的測試預期,不是宣稱 AlphaLab 已在某家產品跑出這些結果。驗收紀錄至少保存測試輸入、故障開關位置、四種事件、目標資料前後狀態與收據端 ACK;少一項就標「證據不足」。

實作第 4 步:把重試寫成可檢查的狀態機

不要讓 Agent 看見 timeout 就自行再呼叫寫入工具。把重試決策放在應用程式:先用 operation_id 查業務系統,確認目標是否已符合預期;如果是,標記完成;如果不是且服務明確支援同 key 去重,才用同 key 重送;若查不到權威結果,維持待查並升級處理。

on_timeout(operation_id):
    state = read_authoritative_target(operation_id)
    if state.matches_expected and receipt_store.has_ack(operation_id):
        return "verified_done"
    if state.is_proven_not_applied and target_supports_idempotency(operation_id):
        return retry_same_operation_id()
    return "unknown_needs_reconciliation"

這段是偽程式碼:正式系統還要處理權限、查詢逾時、並發競爭、收據晚到、敏感資料遮罩與重試上限。冪等 key 的有效期、同 key 參數是否必須一致,也要照你用的目標 API 設計;例如 Stripe 的官方冪等說明描述了同 key 回傳既有結果及 key 保留期。把那套規則照搬到任意 MCP 工具並不安全。若系統需要跨多個服務的一致性,接著看 Agentic Transaction 實作。

常見的 5 個坑:收據可信度也要驗收

  • 把 JSON-RPC 成功當成業務成功:解析工具結果後,仍要讀回目標狀態與版本。
  • 只有本機 Trace:Agent 若能刪本機檔,事故後的缺頁就難判讀。檢查權限隔離與外部留存。
  • 收據和 Agent 共用管理憑證:即使收據在另一個資料庫,共用可刪除權限仍等於同一個信任域。
  • 只存雜湊不核對物件:雜湊只能驗證某份 bytes 是否相同;收據要指向權威物件及版本。
  • 逾時後換 key 盲重試:把一次使用者意圖固定到同一個 operation_id,並先對帳。

若你正在調查來源污染,Prompt Injection Tool Trace教的是不可信內容第一次從哪個 span 進入;本文回答的是「這次寫入究竟完成沒有,收據能否被 Agent 改掉」。若還在決定是否把 API 包成 MCP,可先讀 MCP Production 7 關。

FAQ:把「看起來完成」拆開問

Agent 說完成,能當成證據嗎?

不能單獨當證據。它是使用者介面的說法;請對照目標系統狀態與可信收據。

工具回 isError: false 就算寫入成功?

不一定。那是工具結果語意;寫入是否持久完成,仍由下游讀回或交易收據證明。

Client timeout 可以立刻重試嗎?

先對帳。若結果仍不明,應維持 unknown;只在目標服務的冪等契約允許時重送同一意圖。

加了 OpenTelemetry 就有不可篡改收據?

沒有這項推論。OTel 幫你關聯事件;收據權限、持久化與來源驗證要另外設計。

只有 Server log,夠嗎?

不夠判定缺席。Server log 也可能掉資料;目標資料與外部收據要一起對。

收據端沒收到 ACK,業務寫入算失敗嗎?

業務狀態與證據狀態要分開。若目標已寫入,標成「已執行、收據待補」並由 outbox 補投遞,不應重新執行同一副作用。

要把完整提示和工具參數送去外部端嗎?

先存最小必要的關聯 ID、結果、物件版本與遮罩後欄位。秘密與個資留在有權限的業務系統。

MCP Tasks 能代替結果回查嗎?

Tasks 可讓相容的 client 查長任務狀態;最終業務資料仍應由權威目標驗收。這項擴充依協商與服務端實作而定。

本文的 Tasks 判斷依 MCP Tasks draft:它提供長任務 handle 與狀態查詢,仍標記為 draft;本文沒有把它當成所有 MCP Client 的內建能力。

給新手的 3 個重點

  • 把 timeout 翻譯成「結果待查」,不要翻譯成「沒做」。
  • 讓業務服務回查目標,並把收據送往 Agent 沒有刪改權限的地方。
  • 每次故障注入都保留同一 operation_id,核對目標狀態與收據後再談重試。

接著閱讀

左右滑動查看更多推薦

結語:先查簽收,再宣布送達

下一次 MCP 工具逾時,先問四個問題:這是哪個 operation_id?Server 收到沒有?權威目標現在是什麼狀態?外部收據有沒有 ACK?四個答案接上,Agent 才能從「它說完成」走到「我們查證完成」。想把這套檢查接進自己的 Agent 工作流,可從 AlphaLab 課程選一門實作課,先用一筆虛構待辦跑完三種故障。

ALPHALAB 社群

有問題?來 Telegram 聊

和 Terry、編輯、其他網友一起討論這篇文章。提問、分享觀點,回覆更即時。

加入 Telegram 討論

📩 訂閱 AlphaLab 電子報

每週最多三封:一封 Weekly 週報與最多兩封關鍵 Alpha Signal。

我們不會 spam,隨時可退訂。