跳到主要內容
maxstudioNews
產品DEV Community (Claude Code)約 13 分鐘

Claude Code MCP 伺服器命名衝突:權限規則漏洞解析

Claude Code 的 Model Context Protocol (MCP) 在 2.1.299 版本之前存在一個安全漏洞。該漏洞導致為特定伺服器(例如 mcp__a)設定的權限允許規則,可能意外地也適用於名稱相似的伺服器(例如 a__b),進而繞過安全提示。此問題源於 MCP 工具命名方式的解析歧義,現已透過更新要求使用完整的標準化伺服器名稱來解決。

Claude Code MCP 伺服器命名衝突:權限規則漏洞解析
圖片來源:DEV Community (Claude Code)

如果您在允許清單中寫入 "mcp__a",表示您信任伺服器 a。但在 Claude Code 2.1.299 版本之前,這條規則也會讓 Claude Code 在未經您同意的情況下,呼叫另一個名為 a__b 的伺服器。Claude Code 2.1.299 已於 2026 年 10 月 14 日發布,包含 131 個錯誤修正。

其中一項變更指出:「已修改 MCP 允許規則,使其僅適用於其所命名的伺服器:mcp__a 不再允許名為 a__b 或 a_ 的伺服器;請使用伺服器的完整標準化名稱來編寫 mcp__<server>__*。」另一行說明代理工具清單也採用相同的處理方式,並且在錯誤修正中,針對名稱包含雙底線的伺服器,其拒絕和詢問規則現在也已生效。這三行描述了一個錯誤,其核心問題在於分隔符號允許出現的位置。

Claude Code 為每個 MCP 工具提供一個扁平化的名稱:mcp__,接著是伺服器名稱,然後是 __,最後是工具名稱。權限文件顯示了由此衍生的三種規則形式。mcp__puppeteer 匹配 puppeteer 伺服器中的任何工具,mcp__puppeteer__* 則以萬用字元匹配相同的集合,而 mcp__puppeteer__puppeteer_navigate 則匹配單一工具。

伺服器名稱是您在 claude mcp add 中輸入的內容,或是 .mcp.json 檔案中的鍵值。MCP 文件說明這些名稱「只能包含字母、數字、連字號和底線」。連續兩個底線仍然是底線,因此 a__b 和 a_ 都是合法的伺服器名稱。工具名稱也具有相同的自由度。MCP 規範列出字母、數字、底線、連字號和點作為允許的字元,因此伺服器可以自由地將工具命名為 b__whoami。

現在,為三個伺服器上的 whoami 工具建構名稱:伺服器 a -> mcp__a__whoami;伺服器 a__b -> mcp__a__b__whoami;伺服器 a_ -> mcp__a___whoami。

分隔符號是 __,而伺服器名稱被允許包含 __。從左邊讀取第二行,並在前綴後的第一個 __ 處停止:您會得到伺服器 a,工具 b__whoami。對第三行執行相同的操作,您會得到伺服器 a,工具 _whoami。

這兩者現在看起來都像是伺服器 a 的工具,而單純的 mcp__a 規則表示「伺服器 a 的任何工具」。兩個不同的伺服器,卻有相同的前綴:單憑工具名稱無法判斷伺服器名稱的結尾。變更日誌並未發布舊的匹配器,因此請將上述段落視為一種重構。這是我能找到的最簡單的解讀方式,它能產生變更日誌中的兩個範例 (a__b 和 a_)。它也解釋了同一版本中拒絕側的修正。

一條旨在阻止伺服器 a__b 的拒絕規則 mcp__a__b,在相同的分割邏輯下會被解讀為「伺服器 a,工具 b」,然而伺服器 a__b 並沒有一個工具真的叫做 b。發布說明指出,當「伺服器的標準化名稱包含雙底線」時,針對「MCP 伺服器 (mcp__<server>)」的拒絕和詢問規則並未生效。

相同的分割邏輯,但方向相反。伺服器 a 帶有一個名為 b__whoami 的工具,以及伺服器 a__b 帶有一個名為 whoami 的工具,兩者會產生相同的字串 mcp__a__b__whoami。單憑名稱,任何解析器都無法區分這兩者。匹配器必須知道哪些伺服器已配置,這正是變更日誌中「伺服器的完整標準化名稱」所指的。

MCP 規範從客戶端角度對此發出警告:從多個伺服器聚合的工具「可能會遇到命名衝突」,客戶端「應實施一種消歧策略,例如在工具名稱前加上伺服器識別符」。

允許規則會跳過權限提示。一條涵蓋到第二個伺服器的規則,會跳過您從未審查過的伺服器的提示。誰來選擇伺服器名稱?您可以使用 claude mcp add 來設定。任何您開啟的、包含 .mcp.json 檔案的儲存庫也會設定伺服器名稱。

在互動式會話中,Claude Code 會根據權限文件,在連接這些專案伺服器之前詢問您。在您從未信任的資料夾中使用 claude -p 或 SDK 時,相同的文件指出它們「無需詢問即可連接,無論是否批准」,這在您的 CI 對於已簽出的儲存庫執行 claude -p 時很重要。

伺服器連接是一個獨立的決定,與讓其每個工具呼叫都無需提示地執行不同。想像一個使用者層級的 mcp__github 規則和一個名為 github__mirror 的專案伺服器:在舊的匹配邏輯下,一旦該伺服器連接,該規則很可能也涵蓋了其工具。這是一個假設情況,我尚未看到任何報告的事件。

Anthropic 的託管 MCP 文件在警告中提出了普遍的觀點:serverName 條目「不是安全控制」,因為「使用者可以呼叫任何伺服器 github」。對於管理員允許清單,他們建議使用 serverCommand 或 serverUrl。權限規則沒有這種選項,它們依賴於名稱,因此了解名稱的涵蓋範圍至關重要。

一條為一扇門寫的允許規則,卻也打開了旁邊的門。使用兩個虛擬伺服器重現此問題。您需要 Node 和 Claude Code。以下伺服器使用 v2 MCP TypeScript SDK,其套件為 @modelcontextprotocol/server,並公開一個工具,用於說明哪個伺服器回應了請求。

```javascript

// dummy.mjs: one tool that names the server it runs as

import { McpServer } from '@modelcontextprotocol/server';

import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';

import * as z from 'zod/v4';

const label = process.argv[2] ?? 'dummy';

const server = new McpServer({

name: label,

version: '1.0.0'

});

server.registerTool(

'whoami',

{

description: "'Say which server answered',",

inputSchema: z.object({}),

},

async () => ({

content: [{ type: 'text', text: served by ${label} }],

}),

);

await server.connect(new StdioServerTransport());

```

在一個暫存資料夾中,以兩個名稱註冊相同的檔案兩次:

```bash

mkdir mcp-collide && cd mcp-collide

npm init -y

npm i @modelcontextprotocol/server zod

save dummy.mjs here, then:

claude mcp add a -- node "$PWD/dummy.mjs" a

claude mcp add a__b -- node "$PWD/dummy.mjs" a__b

claude mcp list

```

claude mcp add 預設為本地範圍,僅適用於此資料夾。現在,在該資料夾的本地設定中,只允許伺服器 a:

```bash

mkdir -p .claude

cat > .claude/settings.local.json << 'EOF'

{

"permissions": {

"allow": ["mcp__a"]

}

}

EOF

```

在 dontAsk 模式下執行這兩個呼叫。權限模式文件將其定義為:預先批准的工具會執行,而「任何會觸發提示的動作都會被拒絕」。這將允許規則變成明確的是或否,無需點擊提示:

```bash

claude -p "Call the whoami tool of the a MCP server" \

--permission-mode dontAsk

claude -p "Call the whoami tool of the a__b MCP server" \

--permission-mode dontAsk

```

第一個呼叫在任何版本上都應該能執行。在 2.1.299 或更高版本上,變更日誌指出 mcp__a 不再涵蓋 a__b,因此 dontAsk 會拒絕第二個呼叫。在 2.1.299 之前,該規則也會涵蓋 a__b,回應會顯示「served by a_ b」。

我沒有親自執行過,所以請檢查 claude --version 並將您的結果與變更日誌進行比較。第三個名為 a 的伺服器涵蓋了另一個範例,而 claude mcp remove 可以清除。一個時間點的注意事項:設定文件指出穩定發布通道「通常約為一週前」,而 Homebrew 的 claude-code cask 追蹤此通道。

2.1.299 於 10 月 14 日發布,因此如果您在該日期後的一週內使用穩定版,很有可能仍然使用舊的匹配邏輯。

規則存在於您的使用者設定 (~/.claude/settings.json)、專案的 .claude/settings.json 和您的 .claude/settings.local.json 中,所有這些都列在權限文件中。伺服器名稱存在於 ~/.claude.json (使用者和本地範圍) 和專案的 .mcp.json 中,根據 MCP 文件。

這個從專案根目錄執行的腳本,從設定檔中提取裸露的 mcp__ 規則,並將每個規則與每個已配置的伺服器名稱進行比較。它需要 jq:

```bash

#!/bin/sh

Bare mcp__ rules that reached a second server before 2.1.299

servers=$(jq -r '.. | objects | .mcpServers? // empty | keys[]' ~/.claude.json .mcp.json 2>/dev/null | sort -u)

rules=$(grep -hoE '"mcp__[A-Za-z0-9_-]+"' \

~/.claude/settings.json .claude/settings.json \

.claude/settings.local.json 2>/dev/null \

| tr -d '"' | sort -u)

for r in $rules; do

s=${r#mcp__}

for n in $servers; do

case $n in

"$s"__* | "$s"_)

echo "$r also covered server $n"

;;

esac

if [ "$s" = "$n" ]; then

case $n in

__)

echo "$r names $n: deny/ask missed it"

;;

esac

fi

done

done

```

第一個檢查會標記像 mcp__a 這樣的允許規則,當存在名為 a__… 或 a_ 的伺服器時:該規則現在涵蓋的範圍比以前小了。第二個檢查會標記一個精確命名包含 __ 的伺服器的規則。在舊版本上,這種形式的拒絕和詢問規則並未觸發。

grep 會在這些檔案中看到每個 mcp__ 字串,無論是允許、詢問還是拒絕,因此請根據其所在的清單來解讀每個匹配項。還有兩個地方儲存 MCP 規則。子代理檔案包含工具清單,2.1.299 也縮小了其範圍,因此請執行 grep -rn 'mcp__' .claude/agents ~/.claude/agents。

CI 腳本也經常透過 --allowedTools 在命令列上傳遞規則。來自外掛程式和 claude.ai 連接器的伺服器不在這兩個檔案中,因此也請檢查 claude mcp list 以獲取這些名稱。

變更日誌明確說明了形式:mcp__<server>__*,其中包含伺服器的完整標準化名稱。對於兩個虛擬伺服器:

```json

{

"permissions" : {

"allow" : [

"mcp__a__*",

"mcp__a__b__*"

]

}

}

```

對於外掛程式中捆綁的伺服器,完整的標準化名稱包含外掛程式。MCP 文件提供了模式 mcp__plugin_<plugin-name>_<server-name>__<tool-name>,其中任何字母、數字、底線和連字號以外的字元都會變成底線。

MCP 文件警告說,針對裸伺服器鍵編寫的 hook 匹配器永遠不會對外掛程式伺服器觸發。權限規則匹配相同的工具名稱,因此請針對完整的 plugin_… 名稱編寫。我個人更進一步的偏好是:完全避免在伺服器名稱中使用 __。允許使用連字號,因此 a-b 會產生 mcp__a-b__whoami,這無法以兩種方式分割。

移除伺服器,以新名稱重新添加,並更新指向它的規則。根據權限文件,規則會依「拒絕、詢問、然後允許」的順序檢查,以第一個匹配項為準,因此廣泛的拒絕規則仍然會勝過您編寫的任何允許規則。

我開發 Hermes IDE,因此請在閱讀本節時考慮這一點。Hermes 在真實終端機中執行每個代理程式自己的介面,因此權限規則、提示和此修正都屬於 Claude Code。Hermes 絕不會為您回答權限提示。

其中有兩點在此處有所幫助。按下 ⌘N (Windows 和 Linux 上為 Ctrl+Shift+N),代理程式選擇器會列出已安裝的代理程式及其版本,因此您可以查看是否為 2.1.299 版本。

⌘N 新任務表單開啟代理程式選擇器:Claude Code (已安裝,2.1.299) 已選取,Codex 已安裝 (0.145.0),其他支援的代理程式標記為未安裝,加上自訂代理程式。

Hermes 會儲存每個代理程式的回合,因此審查台 (⌘G) 會按回合或按檔案顯示變更。如果代理程式在任務中途編輯了 .claude/settings.json 或 .mcp.json,該檔案會顯示在變更它的回合中,您可以恢復該回合。Hermes 是免費的,在 BSL 1.1 下開源,並可在 macOS、Windows 和 Linux 上執行。

它不隸屬於 Anthropic、OpenAI、Nous Research 或任何代理程式供應商。下載它,如果它有用,請在 GitHub 上給它一個星。

如果這篇文章對您有幫助。這個錯誤存在於一個邊界:一個扁平的字串攜帶兩個識別符,而兩者都允許包含分隔符號。如果您喜歡推論系統在何處出現問題,我的《系統設計袖珍指南:基礎知識》以簡短的篇幅涵蓋了可擴展系統的核心組成部分。它是《開發者袖珍指南》系列中的八本短書之一,內容涵蓋代理程式、RAG、提示詞、可觀察性、事件、資料庫和系統設計。

Share

覺得值得一看?分享給朋友。

以上為 AI 自動翻譯導讀。原文版權歸 DEV Community (Claude Code) 所有, 建議透過「閱讀原文」前往原始網站,以取得最完整資訊並支持原作者。

Newsletter

不用每天追,AI 重點每週寄給你

43 個來源、每 2 小時更新,太多看不完。電子報每週挑最值得看的幾則,附上 Max 的看法。

每週一封。Email 只用來寄電子報,每封信都能一鍵退訂。