waitForLoadState、getSnapshot、snapshot、getConsoleMessages。模型一直喊這幾個函式名,工具一跑就失敗,因為它們全是模型自己編的,清單上根本沒有。

3 月 31 日,有人在 Claude Code 的 GitHub 開了 issue #41593 講這件事。回報者寫了一個叫 code_executor 的 MCP 工具,description 裡塞了一個 <functions> 區塊,把約 60 個瀏覽器自動化函式連同參數簽章全列進去,整段大約 9,336 字元。

pageNavigate、pageClick、takeSnapshot、pageScreenshot、pageWait 都在那份清單裡,模型卻完全看不到。原因很單純:模型收到的描述只剩 60 個函式裡的 15 個,照字母排序從 addInitScript 排到 getBoundingBox 就沒了。15 個之後的那些,它從頭到尾沒看過。

你去哪裡查,都會看到完整的那一份

這類問題最難纏的地方,是你會先懷疑自己。描述寫得不夠清楚?函式命名太像?於是打開 /mcp 確認 server 送了什麼。照下面這份 issue 的回報,你在那裡會看到整段完整的描述,一個字都沒少。

7 月 26 日另一份 issue #81268(回報版本 2.1.220)講的就是這個死胡同。回報者的說法是:/mcp 顯示的是完整、沒被截斷的描述,送進 API 的卻是截斷版。你在 /mcp 驗證過的那段文字,模型根本收不到。他還指出,server instructions 被截的時候會留一行 debug 紀錄,工具的 description 被截則什麼都沒留。

兩個查證管道,一個給你看錯的版本,一個對描述截斷完全沉默。照這個回報,你在 Claude Code 裡查得到的每一處,看起來都沒事。

8 月 18 日的 issue #87650(回報版本 2.1.234)把理由講得更細。回報者從二進位檔撈出來的片段顯示,同一個工具物件有兩個方法:description() 給 /mcp 介面用,回傳完整字串;prompt() 負責組進模型的 context,回傳的是截斷後再接上 "… [truncated]" 的版本。這是回報者自己反組譯得到的說法,Anthropic 沒有在 issue 裡確認,但它剛好解釋了前一份 issue 為什麼會在 /mcp 撲空。

考卷只印了正面

段考發下來的考卷只印了正面。正面最後一題剛好寫完,句號也在,看起來就是整份考卷。你寫完、交卷,才知道背面還有二十分。

監考老師手上那份是雙面的。你舉手問「考卷有幾題」,他低頭看自己那份,回你「都在上面啊」。

/mcp 就是監考老師手上那份。模型拿到的是只印正面的那張,而且它沒辦法舉手。

#87650 的案例把「正面剛好寫完」這件事演得很完整。同一個 OpenAPI 程式碼執行 MCP server,claude.ai 那邊收到完整描述 16,275 字元,Claude Code 收到 2,061 字元,也就是 2,048 加上 13 字元的截斷標記,只剩 12.7%。留下來的前綴裡有一段 TypeScript RequestOptions 介面,列了 method, path, query, body, contentType, rawBody,看起來是一個寫完、封好的介面。headers、bodyBase64、multipart、returnAs 全寫在第 2,048 字元之後。照回報者的描述,模型看不出介面還沒完,於是很有把握地照那個比較窄的版本去呼叫。

描述被截斷,最慘的情況並不是看到半句話。半句話至少看得出來斷了,比較糟的是截斷點剛好落在一個看起來完整的地方。

官方文件其實寫了,只是寫在你不會去翻的地方

三份 issue 都是使用者回報。行為本身,官方文件有寫,位置在 MCP 文件講 tool search 那一節底下、給 server 作者看的小段落:

Claude Code truncates each tool description and each server’s instructions at 2,048 characters by default. Keep them concise, and put critical details near the start.

每個工具的 description 一個上限,每個 server 的 instructions 一個上限,各自 2,048。同一頁也寫了 tool search 預設開啟時,session 開頭只載入工具名稱和 server instructions(原文是 Only tool names and server instructions load at session start)。我的讀法是:instructions 等於常駐在每一次請求裡,給它設上限說得通。不過官方沒有交代這個上限的設計理由,這句是我的推測。

工具太多塞爆 context 那件事,6 月那篇《Claude Code MCP Tool Search 完整教學》寫過了,這裡不重講。輸出端也有一把剪刀:MAX_MCP_OUTPUT_TOKENS 管的是 MCP 工具「回應」的 token 上限,預設 25,000,超過 10,000 token 會顯示警告。那一側連同逾時,8 月那篇《它不是壞掉,是被計時器砍掉》寫過。這篇只管一件事:單一段描述太長,後半段被切掉。

用兩個記號確認它有沒有被切

要確認自己的工具是不是中招,#81268 附了一個很好抄的最小重現:做一個只有一個工具的 stdio MCP server,description 剛好 3,000 字元,頭尾各放一個記號字串。

1
HEADMARK_DESC_A1S2D3 <2960 chars of filler> TAILMARK_DESC_P0O9I8

連上之後,請模型把這個工具描述的「結尾」原文引出來。回報者預期模型會說出 TAILMARK_DESC_P0O9I8,實際上模型引的是 HEADMARK_DESC_A1S2D3,尾巴它看不到,收到的文字剛好斷在第 2,048 字元。

這招好用的地方在於,它不去問監考老師手上那份,直接問拿考卷的那一方。要檢查自己的真實工具也一樣:挑描述最後面的一個參數名或一句話,問模型那句話在不在。

instructions 那邊,同一份 issue 貼了截斷時留下的 debug 紀錄:

1
2
{"debug":"Server instructions truncated from 9029 to 2048 chars",
"timestamp":"2026-07-25T13:43:41.185Z","sessionId":"...","cwd":"..."}

回報者說這類紀錄在 ~/Library/Caches/claude-cli-nodejs/*/mcp-logs-*/*.jsonl 找得到,那是他的 macOS 路徑,我沒有驗證。照他的說法,這行只會出現在 instructions 被截的時候,工具 description 被截不會留任何東西,所以 log 裡找不到,不代表描述沒被切。

3 月的解法是改二進位檔,9 月有了環境變數

#41593 的回報者當時怎麼辦?他直接去改編譯後的二進位檔,把常數 WoH=2048 改成 WoH=15e3,每次 Claude Code 更新都得重做一遍。這條路我不建議任何人走,放在這裡只是讓你知道,在 9 月之前,想拉高這個上限的人被逼到什麼程度。那份 issue 最後在 5 月 6 日被 stale bot 關掉,不是被修好。

9 月 22 日的 v2.1.280,changelog 多了一條:新增 CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH,用來調整這個 2,048 字元的上限,對 session 裡的每個 MCP server 都生效。截至 9 月 30 日,changelog 上最新的版本是 2.1.285(9 月 29 日)。

1
2
3
# 需要 Claude Code v2.1.280 以上;8000 是我隨手選的示範值,不是官方建議值
export CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH=8000
claude

文件沒有給完整的 shell 範例,上面這兩行是我照環境變數的寫法組出來的。環境變數表對這個值的規定只有一句要注意:Accepts a positive whole number in plain digits. Anything else is ignored and the default applies.

這句話的殺傷力在後半段。寫錯不會報錯,只會安靜地退回 2,048。照 plain digits 的字面,我會避開 4k、4,096 這種帶單位或千分位的寫法,還有 0 與負數;這幾個例子是我從字面推的,文件沒有逐一列出。設完之後,拿前面那組頭尾記號再測一次,才算真的確認上限有拉高。

還有幾件事文件沒寫:這個值有沒有最大值、能不能只對單一 server 設定(文件只說 for every MCP server in your session)。

先改描述,最後才動上限

我的順序是這樣:先照官方那句 put critical details near the start 改描述,把模型最常用、最不能猜錯的東西搬到最前面。像 #41593 那個工具,照字母排序放函式清單,等於把 pageNavigate、pageClick 這種主力排到後段。這個順序對人類讀者很友善,對一個只讀得到前 2,048 字元的讀者很不友善。

改完還是塞不下,就拆。一個工具背一份 9,000 多字元的規格,本來就很吃力,拆成幾個職責清楚的工具,每一段描述都各有自己的 2,048。#81268 留言區也有人分享過類似做法:在 server 端自己把 instructions 和每段 description 控制在預算內,那位留言者抓 1,800 字元當安全線。這是留言者自述,我沒有驗證。

環境變數排最後。調高之後,每次請求送進去的描述就跟著變長,instructions 又是常駐的,我推測這筆 context 的帳會一直算下去。

只有一種情況,我會直接調高:那段描述本身就是一份不能拆的契約,像程式碼執行工具的函式清單或介面定義,拆開之後模型反而拼不回全貌,而且頭尾記號已經證實它被切了。這時候硬要壓縮到 2,048 以內,等於逼自己刪掉規格的一部分,還不如把上限拉到剛好裝得下。

這篇只讀了官方文件(MCP 文件、環境變數表、changelog)和三份 GitHub issue,沒有實際跑過任何東西:我沒有寫過測試用的 MCP server,沒有重現頭尾記號實驗,沒有設過 CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH,也沒有驗證 /mcp 是否真的顯示完整描述、debug log 的路徑與內容。文中關於 /mcp 與模型收到不同版本、description 截斷不留 log 的部分,都是 issue 回報者的主張,不是官方保證。

另外兩件事我沒查證:一是文件寫的 2,048 characters 到底怎麼計算(位元組、UTF-16 還是字元),如果你的描述用中文寫,實際能放多少我不確定;二是 #87650 在 9 月 21 日被 stale bot 關閉,隔天 v2.1.280 就加了這個環境變數,兩者時間相鄰,有沒有因果關係我不知道。

那 60 個函式,現在會怎麼處理

同一個 code_executor,如果今天是我接手,第一步不會去翻 /mcp。在描述最尾巴塞一個記號,問模型看不看得到,先確定是不是截斷。看不到,就把函式清單從字母順序改成按重要性排,pageNavigate、pageClick、takeSnapshot 這幾個主力放最前面,讓它就算被切,丟掉的也是冷門的那幾個。清單還是太長,拆成導覽、操作、擷取幾個工具。這三步都做完,函式簽章還是一份拆不開的完整規格,才去設 CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH,然後用同一個記號再驗一次。

有一件事我到現在還想不通。照 #87650 的說法,截斷後會接上 "… [truncated]",模型其實拿得到「後面還有」的提示;可是回報者描述的模型,還是照著那個不完整的介面很有把握地往下寫。那 13 個字元在什麼情況下會讓模型停下來懷疑,我不知道。在知道之前,寫描述的人能掌握的,就只有前面那 2,048 字元裡放了什麼。

原文來源:Claude Code 官方文件的 MCP 頁(Scale with MCP tool search → For MCP server authors)、環境變數表、changelog;GitHub issue #41593 MCP tool descriptions truncated at 2KB breaks code execution tools、#81268 MCP truncation at 2048 chars is invisible、#87650(以 9 月 30 日的版本為準)