MCP 工具搜尋最容易出現的浪費,不是 Agent 真的呼叫了太多工具,而是它還沒開始工作,Context(模型這一輪能閱讀的內容空間)就先被一整排工具說明塞滿。你接上一個 Jira、GitHub、資料庫與瀏覽器 server,每個工具又帶著完整 JSON Schema,Agent 像是每次進五金行都得先背完整本型錄,才准問「我要一支螺絲起子」。
2026 年 8 月 19 日,r/LLMDevs 一則開發者自報案例用刻意放大的單一 fixture 示範:217,316 bytes 的 tool-schema payload,被改寫成 5,062 bytes 的 discovery payload;作者以每 token 約四字元粗估,稱約從 54K 降到 1.3K tokens。這不是普遍節省率;原帖也沒有提供可供獨立重現的 fixture、模型版本與重複次數,但它把一個真問題照得很亮:模型需要先知道「哪個工具可能有用」,不必先吞下每個參數的百科全書。
這篇專為第一次做 Agent 系統的讀者寫。我不假設你懂 MCP SDK,會用白話帶你建立 search → inspect → execute 三階段代理層、保留權限與副作用資訊,再用固定任務 A/B Test 同時驗證 token、延遲與 wrong-tool failure。若你只使用 Claude Code,也會先看到更省事的內建路線,不必重造已經存在的能力。
MCP 工具搜尋先說結論:先看索引卡,再借完整說明書
Lazy Schema Loading = Search(看索引卡)+ Inspect(展開完整 Schema)+ Execute(驗證後執行)。
把每個 MCP tool 想成倉庫裡的一台機器。搜尋卡只回答「它做什麼、需要哪些主要輸入、會不會改資料、需要什麼權限」;模型選中候選後,才展開完整 inputSchema;真正呼叫前,再用原始 schema 驗證參數並走權限與確認流程。小卡是目錄,不是執行契約。
- Search:從短摘要找出 3~5 個候選,不讓模型讀完整目錄。
- Inspect:只把選中候選的完整 schema 放進目前這段 Context。
- Execute:用未裁切的 schema、目前身分與本地 policy 再驗一次,通過才呼叫 MCP server。

先別急著造 Proxy:Claude Code 已有內建 Tool Search
截至 2026 年 8 月 22 日,Claude Code 的 MCP 文件明載 Tool Search 預設啟用:啟動時載入工具名稱與 server instructions,完整定義等到需要時才載入。你可以先在 Claude Code 執行 /mcp 看各 server 與工具數,再用 /context檢查 Context 去向;若沒有相容性理由,第一步應是確認內建機制是否正常,而不是先加一層第三方 Proxy。
要做門檻式切換,可用 ENABLE_TOOL_SEARCH=auto:可延後的工具定義未達 Context window 10% 時先載入,達門檻後才延後;也能用 auto:5自訂百分比。Claude Agent SDK 文件同時提醒,工具少於約 10 個、schema 又小時,直接載入通常更快,因為搜尋會多一個 round trip。這正是為什麼本文的最後答案不是「一律 lazy」,而是「先量,再切」。
內建路線也有邊界:自訂 API host、雲端託管環境、模型相容性與組織設定都可能改變載入方式。不要從畫面感覺猜;依同一份官方頁面檢查實際設定,並把「完整工具是否被模型預載到初始 Context」列入 A/B trace。若你使用其他 client、自己做 Agent Harness,或需要跨多個 provider 統一搜尋,下面才是要動手的部分。
MCP 工具搜尋的底層:協定負責列工具,Harness 決定給模型看多少
MCP 2026-07-28 tools 規格定義 server 透過 tools/list回傳完整工具定義,client 再用 tools/call執行;標準裡沒有 tools/search、tools/inspect或 defer_loading。規格也明說,實作可採自己的互動介面;換句話說,MCP 解決「client 怎麼取得與呼叫工具」,而你的 Harness 決定「哪些資訊何時進模型 Context」。本文的 Search、Inspect、Execute 都是 host/adapter 內部 API,不是 MCP wire methods。
2026-07-28 的 tools/list支援分頁與 cache metadata,工具清單改變時也能配合 listChanged通知。這讓 Proxy 可以先把完整 catalog 存在模型看不到的記憶體或資料庫,再建立短卡索引。但 cache key 必須包含呼叫者身分與授權範圍:同一個 server 可依每次 request 帶的授權回傳不同工具,不能把管理員的 catalog 共用給一般使用者;工具集也不能因 connection 不同或前一個 request 的副作用而改變。因此 Lazy Loading 要發生在 host 到模型的 Context 層,不是先搜尋再偷偷改 server 的 tools/list。
另一個關鍵是名稱碰撞。規格只要求同一個 server 內的 tool name 唯一,聚合多個 server 時可能都叫 search;server 自報的名稱也不適合拿來做安全識別。實作上請用「本地 server 設定 ID+tool name+schema digest」組成 action ID,而不是只存一個容易撞名的 search。
一張可搜尋工具卡,最少要留下哪些欄位?
工具卡要短,但不能短到只剩漂亮名稱。下面是本文建議的應用層格式;它不是 MCP 官方 schema,而是你自己的 discovery contract。真正的 inputSchema仍完整保存在 catalog 裡。
{
"action_id": "support-prod:tickets.create@sha256:8c4e…",
"title": "建立客服單",
"summary": "建立一張客服單並指派佇列",
"intents": ["建立客服單", "升級客訴"],
"required_inputs": ["subject", "body", "queue"],
"risk": "write-reversible",
"auth_scopes": ["tickets:write"],
"confirmation": "required",
"schema_digest": "8c4e…"
}
- 辨識欄:
action_id、title、summary,讓搜尋與人類都能看懂。 - 意圖欄:
intents與常見別名,避免只靠精確字串。 - 參數摘要:只列必要欄位名稱與用途,不複製整個巢狀 schema。
- 風險欄:read/write、可逆性、外部世界、確認需求與 credential scope。
- 完整性欄:
schema_digest與 catalog version,確保 Inspect 與 Execute 看的是同一版。
MCP 的 ToolAnnotations schema提供 readOnlyHint、destructiveHint、idempotentHint與 openWorldHint,但規格明文要求:不可信 server 傳來的 annotations 不能直接決定工具使用。做風險卡時,把 annotations 當線索;本地 allowlist、實際 OAuth scope、工具名稱與操作類型可以提高風險等級,不能因一個自報的 readOnlyHint:true就自動放行。
MCP 工具搜尋的 7 步 Lazy Schema Loading 實作
Step 1|量出 Schema Tax,不先猜節省率
痛點:你看到 54K 就想直接套用 97.7%,但那是別人的單一壓力 fixture。解法:固定同一個 model、system prompt、使用者訊息與空輸出上限,做「完整 tools」與「只帶 discovery tools」兩次 token count。Anthropic 使用者可把相同 request 交給Token Counting endpoint,它會把 tools 納入計數;其他供應商則使用各自的 tokenizer/usage 欄位。記錄 catalog_bytes、input_tokens與 model ID,別用固定的 bytes ÷ 4 冒充所有 tokenizer。
Step 2|抓完整 Catalog,逐頁保存並做 Digest
痛點:只抓第一頁會讓搜尋靜悄悄漏工具。解法:透過你選用的 MCP SDK 走完 tools/list分頁,把每份原始 tool definition canonicalize 後計算 SHA-256。Catalog 要綁定 protocol version、server config ID、授權範圍與取得時間;收到清單變動事件或 freshness TTL 到期,就從第一頁重抓並原子替換對應 scope 的索引,不把多頁結果誤當永遠一致的 snapshot。
Step 3|把完整 Schema 蒸餾成「短而不瞎」的卡片
痛點:只保留 tool name,模型會把 ticket.search、ticket.create與 ticket.delete混在一起。解法:由程式抽出名稱、描述、required fields,再疊上人工維護的 intent aliases 與本地 risk policy。卡片設硬上限前,先驗證最長名稱、權限與風險欄不會被截掉;需要縮短時,優先刪例句,不刪副作用。
Step 4|Search 回傳候選,不替模型偷做決定
痛點:模糊意圖可能同時命中三個工具。解法:結合 lexical search(關鍵字)與 semantic search(語意),回傳有穩定 tie-break 的 top-k 卡片;分數接近時保留多個候選,讓模型根據使用者目標挑選,或要求補充問題。搜尋 trace 至少保存 query、候選 action IDs、scores、選中項與拒絕原因。
Step 5|Inspect 完整 Schema,生成參數後再做 JSON Schema 驗證
痛點:卡片看得懂意圖,卻沒有 enum、格式、巢狀條件與 $ref。解法:選中工具後,以 action ID 取回 digest 相同的完整 schema,才讓模型填 arguments;執行端再用支援該 draft 與 $ref解析的 validator 檢查,預設禁止從網路抓外部 reference,無法解析就 fail closed,並限制 schema 深度與驗證時間。schema digest 漂移就中止這次提案、重新 Inspect,不能拿舊卡配新工具。
Step 6|把 Policy Gate 放在 Execute 前面
痛點:「選對工具」不等於「有權執行」。解法:用目前使用者、connector、OAuth scope、環境與 arguments 做授權;寫入、刪除、付款、對外傳送與 unknown risk 類別顯示工具、目標與參數,取得人類確認後才送出。MCP 規格也建議應用程式清楚顯示暴露給模型的工具、呼叫指示與操作確認。
Step 7|把 Execute 收據寫進 Trace,讓錯選可以回放
痛點:只看最終回答,找不到是搜尋、選擇、填參數、授權還是 server 執行出錯。解法:每次留下 query → candidates → inspected_digest → proposed_args → validation → policy_decision → tool_result事件鏈。這和Agent Observability的思路相同:先把黑盒拆成可定位的階段,回歸測試才知道哪一段退步。
完整走一次:從「幫客戶處理重複扣款」到安全呼叫
假設 catalog 裡有 payments.search、tickets.create、payments.refund與 payments.delete_record。使用者只說:「幫這位客戶處理重複扣款。」Search 不應直接猜退款,而是回傳搜尋交易、建立客服單與退款三張卡;刪除紀錄因意圖較遠,只保留在低順位。
- Agent 先選
payments.search查兩筆交易,這是 read 類操作。 - 結果確認其中一筆重複後,Search 再找到
payments.refund。 - Inspect 展開退款工具的完整 schema,發現需要
payment_id、amount、reason與 idempotency key。 - Validator 確認 amount 格式與 enum;Policy Gate 檢查
refund:writescope,並把目標交易與金額顯示給使用者確認。 - Execute 成功後保存 server result 與 request ID;相同 idempotency key 的重試不會被 Agent 自行換掉。
這個例子的重要處,不是少看了幾個 tokens,而是高風險細節在真正需要時完整回來。如果 Search 卡把「退款」與「刪除交易紀錄」壓成同一個「處理付款」摘要,token 省得再多也是失敗。
語言無關 Pseudocode:把三階段接起來
catalog = buildCatalog(mcpClient.listToolsAllPages(), authScope)
cards = catalog.map(makeSearchCard)
hits = search(cards, userIntent, topK = 5)
choice = model.choose(hits)
tool = catalog.get(choice.actionId)
assert sha256(canonicalJson(tool.definition)) == choice.schemaDigest
args = model.fill(tool.inputSchema)
jsonSchemaValidate(args, tool.inputSchema)
decision = policy.authorize(identity, tool, args)
if decision.requiresConfirmation:
user.confirm(tool.title, args)
result = mcpClient.callTool(tool.name, args)
trace.append(hits, tool.digest, args, decision, result)
這段刻意省略了 transport reconnect、protocol negotiation、分頁錯誤、timeout、rate limit、$ref遠端資源政策與 secret redaction;它只能當架構骨架。Production 請讓正式 MCP SDK 處理 wire protocol,並依規格的 security considerations補上 schema 驗證、結果驗證、逾時、稽核與人類確認。
怎麼驗收 MCP 工具搜尋:固定任務 A/B Test
不要只比第一輪 token。A 組讓 Agent 一開始看完整 tool definitions;B 組只看 discovery 介面,選中後才 Inspect。兩組使用同一批任務、相同 model、prompt、temperature、授權、server snapshot 與起始資料,交錯執行並保留所有失敗。若你已讀過MCP vs CLI A/B Test,這次只是把變因收窄成「完整載入 vs Lazy Schema Loading」。

- Context 成本:首輪 input tokens、整個 task 的 uncached/cached input,以及 catalog bytes。
- 速度:到第一次正確工具提案的時間、到任務完成的時間、Search 額外 round trips。
- 選擇品質:top-1/top-k 命中、需要澄清的比例、search miss、錯選工具。
- 參數品質:schema-valid rate、缺少 required field、enum/format 錯誤與重試次數。
- 安全品質:未授權提案、危險工具未確認、同名 tool collision、stale digest 與副作用重複。
- 任務品質:最終完成率與人工介入;只有同等或更好的任務品質,token 節省才有意義。
先用唯讀與可重置測試環境跑,再加入「搜尋同義詞」「三個近似工具」「tool name 相同但 server 不同」「schema 更新」「權限較低使用者」與「破壞性工具混在候選」等對抗題。想把這套評測擴成回歸門,可接著讀AI Evals 實作指南與Agent Harness 動手做。
7 個最常踩的坑
- 把 bytes 當 tokens:不同 tokenizer 與內容形狀會改變結果;用實際 model 的 token counter。
- 卡片刪掉風險欄:required inputs 可以晚點看,副作用與確認需求不能消失。
- 只驗證 tool name:多 server 可能同名;action ID 必須綁本地 server identity 與 schema digest。
- 共享錯誤 Catalog:工具集合可能依授權而變;cache key 必須含 subject/scope。
- 相信 server annotations:它們是提示,不是安全證明;本地 policy 才是放行者。
- 只測正常問法:近義詞、錯字、模糊意圖與高風險近鄰才會暴露 wrong-tool failure。
- 以為 schema 小了,result 也會小:Lazy Schema Loading 處理工具定義;大型查詢結果仍要分頁、摘要與設定輸出上限。
現成實作可以怎麼參考?
若你的 client 沒有內建 discovery,可閱讀開源的mcp-tool-search:它用 proxy 預掃 backend servers,對模型暴露搜尋、取 schema、呼叫與列 server 四個工具。README 的 85~96% 是專案自報估算,表格範圍也不完全一致,不能當成通用 benchmark。這個專案採靜態 catalog,工具或設定改變後要重建;實際 backend transport、credential 與版本相容性都要先驗證。真正可移植的是「catalog 留在代理層、模型按需取 schema」的結構,不是安裝後必然省下某個百分比。
如果你在 Anthropic API 自建工具層,Tool Search API已提供供應商特定的 defer_loading與 tool_reference機制;deferred definitions 每次仍要放進 API request 的 top-level tools,只是不進模型的初始 Context。若你做跨 provider Harness,就把本文的卡片與 policy contract 放在自己的 gateway,再由各 provider adapter 轉成對方接受的格式;這是可攜架構,不是 drop-in wire compatibility。先理解AI Agent Harness 是什麼,會更容易看懂這層為何不屬於模型本身。
常見問題(FAQ)
Q1:Claude Code 使用者需要自己架 MCP Tool Search 嗎?
先不用。目前 Claude Code 預設延後 MCP schema、按需搜尋;先用 /mcp、/context與 trace 確認你的 host/model/設定走的是 Tool Search。只有需要跨 client 統一 catalog、特殊搜尋或自訂 policy 時,再評估 Proxy。
Q2:MCP 規格會強迫模型每輪讀完整 schema 嗎?
不一定。MCP 規格定義 client 與 server 的列出/呼叫契約,也允許實作採不同互動方式;完整 schema 是否被送進模型 Context,是 client/Harness 的設計。
Q3:54K 降到 1.3K,代表我也能省 97.7% 嗎?
不能這樣推。那是作者刻意放大的單一 schema fixture,token 還是用 bytes 粗估。你的結果由工具數、schema 長度、卡片欄位、tokenizer、cache 與每個任務實際 Inspect 幾個工具決定。
Q4:只做 Search,不做 Inspect 可以嗎?
不適合一般有參數的工具。搜尋卡負責候選召回,enum、條件、格式、巢狀欄位與 $ref仍要靠完整 schema;高風險操作更應在填參數前展開。
Q5:MCP ToolAnnotations 可以直接當權限規則嗎?
不能單獨使用。規格把它們定義為 hints,並要求不可信來源不能主導 tool-use decision。權限要回到本地 policy、實際 credential scope、使用者身分、目標與參數。
Q6:有 Prompt Cache,還需要 Lazy Schema Loading 嗎?
看你的瓶頸。Cache 可能降低重複前綴的計費或計算,但 schema 仍占可用 Context,也可能影響選擇品質;Anthropic 文件另指出 deferred tools 不進初始 prompt prefix,可保留既有 prompt cache。用同任務量 token、延遲與正確率再決定。
Q7:這會一起縮小大型 Tool Result 嗎?
不會自動縮小。本文處理的是工具定義的載入時機;結果內容要另外做 server-side pagination、欄位選擇、摘要、artifact storage 或 output budget。
Q8:什麼時候不值得導入?
工具少、schema 小、每輪幾乎都會用到時。此時 Search 的額外 round trip 可能比省下的 Context 更昂貴。保留完整載入當 control arm,讓數據而不是架構潮流做決定。
給新手的 5 個重點
- 先確認 client 是否已有 Tool Search;Claude Code 目前已有內建路線。
- Lazy Schema Loading 的核心是「索引卡 → 完整契約 → 受控執行」,不是把 schema 永久刪掉。
- 風險、權限、確認需求與 schema digest 必須跟著卡片走。
- A/B Test 先守任務完成率、wrong-tool 與副作用,再看 token。
- 工具很少時保留 upfront loading;工具越多、每次用得越少,按需載入才越有機會划算。
想把這個 gateway 做成可維護的 Agent 系統,可從 AlphaLab 的AI 課程建立完整學習路線;若眼前目標只是控制 Context,先讀Claude 省 token 實戰,把 schema、tool result、history 與 cache 分開量。
接著閱讀
左右滑動查看更多推薦
結語:別讓 Agent 背著整本型錄找一支螺絲起子
現在回到那句錨點:Lazy Schema Loading = 先看索引卡,再借完整說明書,最後才動手。它的價值不只是少幾個 tokens,而是把工具發現、參數理解與安全執行拆成三個能分別量測、分別失敗、分別修正的階段。
今天就挑一個固定任務:先跑完整 catalog baseline,再跑 lazy arm;同時記下 input tokens、首次正確工具提案時間、最終完成、schema validation、wrong-tool 與 policy decision。若 B 組只省 Context 卻更常選錯工具,就先修卡片與搜尋;若品質守住,再把更多 server 移進按需載入。這才是把 54K 的驚嘆號,變成你自己系統裡可重跑的工程決策。
