- 首頁
- Documentation
- MCP
- MCP 伺服器與工具撰寫
MCP 伺服器與工具撰寫
本文件說明 MCP 伺服器定義如何成為 coding-agent 中可呼叫的 mcp_* 工具,以及當設定無效、重複、停用或受認證閘控時,操作者應預期的行為。
Config sources (.xcsh/.claude/.cursor/.vscode/mcp.json, mcp.json, etc.) -> discovery providers normalize to canonical MCPServer -> capability loader dedupes by server name (higher provider priority wins) -> loadAllMCPConfigs converts to MCPServerConfig + skips enabled:false -> MCPManager connects/listTools (with auth/header/env resolution) -> MCPTool/DeferredMCPTool bridge exposes tools as mcp_<server>_<tool> -> AgentSession.refreshMCPTools replaces live MCP tools immediately1) 伺服器設定模型與驗證
Section titled “1) 伺服器設定模型與驗證”src/mcp/types.ts 定義了 MCP 設定撰寫者和執行階段使用的撰寫格式:
stdio(當type缺失時的預設值):需要command,可選args、env、cwdhttp:需要url,可選headerssse:需要url,可選headers(保留以維持相容性)- 共用欄位:
enabled、timeout、auth
validateServerConfig()(src/mcp/config.ts)強制執行傳輸基本規則:
- 拒絕同時設定
command和url的設定 - stdio 需要
command - http/sse 需要
url - 拒絕未知的
type
config-writer.ts 在新增/更新操作時套用此驗證,並且也會驗證伺服器名稱:
- 不可為空
- 最多 100 個字元
- 僅允許
[a-zA-Z0-9_.-]
傳輸常見陷阱
Section titled “傳輸常見陷阱”- 省略
type表示 stdio。如果您原本想使用 HTTP/SSE 但省略了type,command就會變成必填。 sse仍然被接受,但在內部被視為 HTTP 傳輸處理(createHttpTransport)。- 驗證是結構性的,不是可達性的:語法正確的 URL 仍然可能在連線時失敗。
2) 探索、正規化與優先順序
Section titled “2) 探索、正規化與優先順序”基於能力的探索
Section titled “基於能力的探索”loadAllMCPConfigs()(src/mcp/config.ts)透過 loadCapability(mcpCapability.id) 載入標準化的 MCPServer 項目。
能力層(src/capability/index.ts)接著會:
- 按優先順序載入提供者
- 依
server.name去除重複(先出現者獲勝 = 最高優先順序) - 驗證去重後的項目
結果:跨來源的重複伺服器名稱不會被合併。一個定義獲勝;較低優先順序的重複項會被遮蔽。
.mcp.json 與相關檔案
Section titled “.mcp.json 與相關檔案”src/discovery/mcp-json.ts 中的專用備援提供者會讀取專案根目錄的 mcp.json 和 .mcp.json(低優先順序)。
實務上 MCP 伺服器也會來自更高優先順序的提供者(例如原生 .xcsh/... 和工具專屬設定目錄)。撰寫指引:
- 優先使用
.xcsh/mcp.json(專案)或~/.xcsh/mcp.json(使用者)以獲得明確控制。 - 當需要備援相容性時使用根目錄的
mcp.json/.mcp.json。 - 在多個來源中重複使用相同的伺服器名稱會導致優先順序遮蔽,而非合併。
convertToLegacyConfig()(src/mcp/config.ts)將標準化的 MCPServer 對應至執行階段的 MCPServerConfig。
關鍵行為:
- 傳輸推斷為
server.transport ?? (command ? "stdio" : url ? "http" : "stdio") - 停用的伺服器(
enabled === false)在連線前就被丟棄 - 可選欄位存在時會被保留
探索期間的環境變數展開
Section titled “探索期間的環境變數展開”mcp-json.ts 使用 expandEnvVarsDeep() 展開字串欄位中的環境變數佔位符:
- 支援
${VAR}和${VAR:-default} - 未解析的值會保持為字面字串
${VAR}
mcp-json.ts 也會對使用者 JSON 執行執行階段型別檢查,並對無效的 enabled/timeout 值記錄警告,而非使整個檔案載入失敗。
3) 認證與執行階段值解析
Section titled “3) 認證與執行階段值解析”MCPManager.prepareConfig()/#resolveAuthConfig()(src/mcp/manager.ts)是連線前的最終處理步驟。
OAuth 憑證注入
Section titled “OAuth 憑證注入”如果設定包含:
auth: { type: "oauth", credentialId: "..." }且認證儲存中存在該憑證:
http/sse:注入Authorization: Bearer <access_token>標頭stdio:注入OAUTH_ACCESS_TOKEN環境變數
如果憑證查詢失敗,管理器會記錄警告並以未解析的認證狀態繼續。
標頭/環境變數值解析
Section titled “標頭/環境變數值解析”在連線前,管理器透過 resolveConfigValue()(src/config/resolve-config-value.ts)解析每個標頭/環境變數值:
- 以
!開頭的值 => 執行 shell 命令,使用修剪後的 stdout(已快取) - 否則,先將值視為環境變數名稱(
process.env[name]),退而使用字面值 - 未解析的命令/環境變數值會從最終的標頭/環境變數對應中省略
操作注意事項:這意味著打字錯誤的密鑰命令/環境變數名稱可能會靜默地移除該標頭/環境變數項目,導致下游 401/403 或伺服器啟動失敗。
4) 工具橋接:MCP -> 代理可呼叫工具
Section titled “4) 工具橋接:MCP -> 代理可呼叫工具”src/mcp/tool-bridge.ts 將 MCP 工具定義轉換為 CustomTool。
命名與碰撞範圍
Section titled “命名與碰撞範圍”工具名稱的產生方式為:
mcp_<sanitized_server_name>_<sanitized_tool_name>規則:
- 轉為小寫
- 非
[a-z_]字元變為_ - 重複的底線會合併
- 工具名稱中多餘的
<server>_前綴會被移除一次
這避免了許多碰撞,但並非全部。不同的原始名稱仍可能經過清理後產生相同的識別符(例如 my-server 和 my.server 清理後相似),而註冊表插入採用後寫者獲勝。
Schema 對應
Section titled “Schema 對應”convertSchema() 大致保持 MCP JSON Schema 不變,但會為缺少 properties 的物件 schema 補上 {} 以維持提供者相容性。
MCPTool.execute() / DeferredMCPTool.execute():
- 呼叫 MCP
tools/call - 將 MCP 內容展平為可顯示的文字
- 回傳結構化詳細資訊(
serverName、mcpToolName、提供者中繼資料) - 將伺服器回報的
isError對應為Error: ...文字結果 - 將拋出的傳輸/執行階段失敗對應為
MCP error: ... - 透過將 AbortError 轉換為
ToolAbortError來保留中止語意
5) 操作者生命週期:新增/編輯/移除與即時更新
Section titled “5) 操作者生命週期:新增/編輯/移除與即時更新”互動模式在 src/modes/controllers/mcp-command-controller.ts 中公開 /mcp。
支援的操作:
add(精靈或快速新增)remove/rmenable/disabletestreauth/unauthreload
設定寫入是原子性的(writeMCPConfigFile:暫存檔 + 重新命名)。
變更後,控制器呼叫 #reloadMCP():
mcpManager.disconnectAll()mcpManager.discoverAndConnect()session.refreshMCPTools(mcpManager.getTools())
refreshMCPTools() 取代所有 mcp_ 註冊表條目並立即重新啟用最新的 MCP 工具集,因此變更無需重新啟動工作階段即可生效。
- 互動/TUI 模式:
/mcp提供應用程式內的使用者體驗(精靈、OAuth 流程、連線狀態文字、立即的執行階段重新繫結)。 - SDK/無頭整合:
discoverAndLoadMCPTools()(src/mcp/loader.ts)回傳已載入的工具 + 各伺服器的錯誤;無/mcp命令使用者體驗。
6) 使用者可見的錯誤表面
Section titled “6) 使用者可見的錯誤表面”使用者/操作者常見的錯誤字串:
- 新增/更新驗證失敗:
Invalid server config: ...Server "<name>" already exists in <path>
- 快速新增引數問題:
Use either --url or -- <command...>, not both.--token requires --url (HTTP/SSE transport).
- 連線/測試失敗:
Failed to connect to "<name>": <message>- 逾時說明文字建議增加逾時時間
401/403的認證說明文字
- 認證/OAuth 流程:
Authentication required ... OAuth endpoints could not be discoveredOAuth flow timed out. Please try again.OAuth authentication failed: ...
- 停用伺服器的使用:
Server "<name>" is disabled. Run /mcp enable <name> first.
探索中錯誤的來源 JSON 通常以警告/日誌方式處理;config-writer 路徑會拋出明確的錯誤。
7) 實務撰寫指引
Section titled “7) 實務撰寫指引”在此程式碼庫中進行穩健的 MCP 撰寫:
- 在所有支援 MCP 的設定來源中保持伺服器名稱全域唯一。
- 優先使用英數字元/底線名稱,以避免在產生的
mcp_*工具名稱中發生清理後的名稱碰撞。 - 使用明確的
type以避免意外的 stdio 預設值。 - 將
enabled: false視為硬關閉:伺服器會從執行階段連線集合中省略。 - 對於 OAuth 設定,儲存有效的
credentialId;否則認證注入會被跳過。 - 如果使用基於命令的密鑰解析(
!cmd),請驗證命令輸出是穩定且非空的。