MCP(Model Context Protocol) 的理解和快速實(shí)踐 精華
一、背景
此前筆者對(duì) AI Agent 研究的涉獵比較少,也基本沒有系統(tǒng)介紹過與 Agent 相關(guān)的內(nèi)容。然而,最近由 Anthropic 提出的 MCP(Model Context Protocol [1],模型上下文協(xié)議)在社區(qū)中引發(fā)廣泛關(guān)注,筆者也趁此機(jī)會(huì)“蹭蹭熱度”,了解下 MCP 到底是什么,了解一下 MCP 的基本概念和工作機(jī)制。
在最初接觸 MCP 時(shí),也曾對(duì)其一些設(shè)計(jì)感到困惑。于是帶著這些疑問進(jìn)行了進(jìn)一步的調(diào)研,逐漸對(duì) MCP 的組成及運(yùn)作方式有了初步的認(rèn)識(shí),比如:
- MCP 中的 Resource、Prompt、Tool、Sampling、Root 是什么,有什么用。
- 誰來決定是否調(diào)用 Client。
- 如何判斷調(diào)用哪些 Client。
- Client 和 Server 之間如何傳輸,協(xié)議是什么。
- 怎么使用 Prompt。
本文將嘗試基于這些問題,對(duì) MCP 進(jìn)行一番介紹和解析。
二、MCP 架構(gòu)
2.1 引言
Anthropic 的 MCP 是一種開放標(biāo)準(zhǔn)協(xié)議,旨在簡(jiǎn)化 Agent/LLM 與外部數(shù)據(jù)源和工具之間的集成過程。它提供了一種統(tǒng)一的方式,使 AI 模型能夠高效、安全地訪問和利用各種資源。
如下圖所示,可以將 MCP 理解為一個(gè) “AI 的 USB 接口”,提供了一個(gè)連接標(biāo)準(zhǔn),使 Agent/LLM(如 Claude、ChatGPT、Qwen)能夠方便、安全的訪問各種外部工具和數(shù)據(jù)(比如 Gmai、Slack、本地文件等):
- 傳統(tǒng)方式的問題:每個(gè)服務(wù)(Gmail、Slack、Calendar)都有自己獨(dú)特的 API,每一個(gè) Agent(LLM)都需要各自去適配。如果有 M 個(gè) Agent、N 個(gè)服務(wù),則相應(yīng)的復(fù)雜度為 M x N。
- MCP 的優(yōu)勢(shì):MCP 對(duì)各個(gè)服務(wù)的接口進(jìn)行了統(tǒng)一,這樣 M 個(gè) Agent 可以直接使用這 N 個(gè)服務(wù),大幅降低重復(fù)開發(fā)和適配的成本。隨著更多組織或者開發(fā)者開始采用 MCP,其有望成為 AI 應(yīng)用集成的主流協(xié)議。
2.2 MCP 架構(gòu)概覽
如下圖所示(來自:Visual Guide to Model Context Protocol (MCP) [2])為 MCP 的關(guān)鍵架構(gòu),受到 Language Server Protocol(LSP)的啟發(fā),旨在標(biāo)準(zhǔn)化 AI 與外部系統(tǒng)的交互方式,包括 3 個(gè)關(guān)鍵組件:
- Host:通常是 AI 應(yīng)用(Agent),比如 Anthropic Claude Desktop、Cursor、Cline 等,負(fù)責(zé)選擇并調(diào)用 MCP Client,以便使用各種 MCP Server 提供的能力。
- Client:Host 內(nèi)的連接器,負(fù)責(zé)與 Server 建立 1 對(duì) 1 的連接,以便使用 Server。
- Server:提供資源、工具或 Prompts 的服務(wù),如文件系統(tǒng)、數(shù)據(jù)庫、API 等。
如上圖所示,Client 和 Server 之間使用雙向的 JSON-RPC 2.0 進(jìn)行通信。當(dāng)前支持 stdio 和 Streamable HTTP 兩種傳輸機(jī)制。
- stdio:Client 以子進(jìn)程方式啟動(dòng) MCP Server,并通過標(biāo)準(zhǔn)輸入輸出建立通信管道。Server 從 stdin 中讀取 JSON-RPC 消息(可以是 Request、Response 或 Notification),并將消息發(fā)送到 stdout。 (PS:Server 不能往 stdin 寫,Client 不能往 stdout 寫)
- Streamable HTTP + SSE:Client 發(fā)起 HTTP GET 并在 Accept: text/event-stream 下打開 SSE 流;Server 在該流上通過 SSE 推送 JSON?RPC Request 和 Notification,Client 監(jiān)聽并處理。Client 再通過 HTTP POST 將對(duì)應(yīng)的 JSON?RPC 響應(yīng)提交至同一 MCP 端點(diǎn),實(shí)現(xiàn)完整的雙向交互。
- WebSocket:Transport Layer 也支持自定義的傳輸機(jī)制,比如常見的 WebSocket。Server 和 Client 均可充當(dāng) JSON?RPC 請(qǐng)求的發(fā)起者和接收者;Client 在連接時(shí)注冊(cè)自己支持的 method,Server 即可通過同一通道調(diào)用這些方法。
2.3 MCP 關(guān)鍵概念
2.3.1 Resources
Resources 在 MCP 中指的是 AI 可以訪問和讀取的數(shù)據(jù)來源。這些數(shù)據(jù)包括但不限于文件內(nèi)容、數(shù)據(jù)庫記錄、屏幕截圖、圖像、日志文件、API 響應(yīng)等。每一個(gè) resource 都有一個(gè)獨(dú)立的 URI,包含文本或者二進(jìn)制數(shù)據(jù),其可以為 AI 提供所需的上下文信息。如下所示為使用 MCP 的 Python SDK(The official Python SDK for Model Context Protocol servers and clients [3]) 在 MCP Server 中實(shí)現(xiàn) Resource 的簡(jiǎn)單示例:
- list_resources():用于列出所有 resource(列表),以便后續(xù)選擇、訪問。resource 對(duì)應(yīng)的數(shù)據(jù)類型為 types.Resource,其包含唯一的 uri,也有對(duì)應(yīng)的 mimeType。
- read_resource():根據(jù) uri 訪問對(duì)應(yīng)的 resource。
2.3.2 Prompts
Prompts 是預(yù)定義的模板或指令,旨在指導(dǎo) AI 生成響應(yīng)或執(zhí)行特定任務(wù)。它們是 MCP 擴(kuò)展性的一部分,允許開發(fā)者根據(jù)具體需求創(chuàng)建新的 Prompt 模板,以增強(qiáng) AI 與數(shù)據(jù)源的交互。如下所示為使用 MCP Python SDK 在 MCP Server 中實(shí)現(xiàn) Prompt 的簡(jiǎn)單示例:
- list_prompts():列出所有可用的 Prompt(列表)。prompt 對(duì)應(yīng)的類型為 types.Prompt,包含唯一的 name,必要的 description 以及一個(gè) arguments 列表。
- get_prompt():根據(jù) name 獲取對(duì)應(yīng)的 Prompt,返回的是 GetPromptResult,包含 description 和 messages 屬性。
Prompts 在 Anthropic 的分類中屬于“用戶控制”(user?controlled)級(jí)別,意味著最終由用戶在客戶端界面中主動(dòng)選擇并執(zhí)行,具有以下特性:
- 動(dòng)態(tài)參數(shù):支持在調(diào)用時(shí)傳入變量,生成個(gè)性化提示。
- 資源上下文:可將文件、日志等資源內(nèi)容嵌入到提示中。
- 流程編排:可鏈?zhǔn)浇M合多輪交互,實(shí)現(xiàn)復(fù)雜工作流。
2.3.3 Tools
Tools 是 MCP Server 提供的功能(PS:也是當(dāng)前使用最多,支持最好的功能),AI 可以調(diào)用這些功能執(zhí)行具體操作,如運(yùn)行代碼、訪問外部 API 或自動(dòng)化任務(wù)。這些工具需要用戶批準(zhǔn),確保安全性和可控性。和 Resources 類似,工具也需要包含唯一的 name,并且包含相應(yīng)的描述(description),以便引導(dǎo)更好的使用該工具。如下所示為使用 MCP 的 Python SDK 在 MCP Server 中實(shí)現(xiàn) Tools 的簡(jiǎn)單示例:
- list_tools():列出所有可用 Tools(列表)。tool 對(duì)應(yīng)的類型為 types.Tool,同樣包含唯一的 name,必要的 description,以及相應(yīng)的 inputSchema(對(duì)應(yīng) Anthropic Claude function call 中的 input_schema)。
- call_tool():根據(jù) name 以及對(duì)應(yīng)的 arguments 調(diào)用相應(yīng)的 tool,比如這里是執(zhí)行相應(yīng)的求和計(jì)算。
2.3.4 Sampling
Sampling 允許 Server 通過 Client 請(qǐng)求 LLM 完成生成,支持復(fù)雜的代理行為,同時(shí)保持安全性和隱私。 不過當(dāng)前 Sampling 特性在 Claude Desktop client 中還未支持。Sampling 擴(kuò)展了 MCP 的 Client-Server 架構(gòu),使得 Server 無需自行承載或調(diào)用遠(yuǎn)端模型,就能通過 Client 訪問預(yù)制的 LLM 能力,實(shí)現(xiàn)更強(qiáng)的交互能力。典型的流程包含如下 5 個(gè)步驟:
- Server 調(diào)用 sampling/createMessage 向 Client 發(fā)送請(qǐng)求(PS:可以雙向通信)。
- Client 接收后,可根據(jù)策略或人工審核,對(duì)請(qǐng)求進(jìn)行修改或拒絕。
- Client 在本地或受信任環(huán)境中調(diào)用 LLM 執(zhí)行生成采樣。
- Client 可再次審核生成的 completion,并對(duì)結(jié)果進(jìn)行過濾或調(diào)整。
- Client 將最終的 completion 通過 JSON-RPC 響應(yīng)返回給 Server。
2.3.5 Roots
Roots 定義了 Server 可以操作的邊界。root 可以作為 URI,當(dāng) Client 連接 Server 時(shí),聲明 Server 需要關(guān)注的范圍。主要是用于文件系統(tǒng)路徑(如file:///home/user/projects/myapp)或 HTTP URL(如 ??https://api.example.com/v1??),幫助服務(wù)器了解相關(guān)資源和位置,明確工作空間資源,并支持同時(shí)處理多個(gè)資源。如下圖所示為 MCP Client 聲明 roots 的典型方式,此配置表明 Server 同時(shí)聚焦于本地倉庫與遠(yuǎn)程 API 端點(diǎn),且在邏輯上保持二者獨(dú)立。
2.4 能力協(xié)商機(jī)制
MCP 采用基于能力的協(xié)商機(jī)制,Client 和 Server 需要在初始階段聲明各自支持的“能力”特性?!澳芰Α甭暶鳑Q定了會(huì)話階段可使用的協(xié)議特征和基本操作。
- 初始階段:
Server 需要聲明:可用 Resource、支持的 Tool、Prompt 模板。
Client 需要聲明:Sampling 支持,Notification 處理。
- 會(huì)話階段:Client 和 Server 需要嚴(yán)格遵守已聲明的能力范圍。
如下圖所示展示初始階段和會(huì)話階段的幾個(gè)過程:
- 紅框:初始階段,Host 調(diào)用 Client,Client 訪問 Server 獲取 Server 可支持的資源和能力(list_resources(),list_tools())。
- 藍(lán)框:會(huì)話階段(Host 發(fā)起),Host 中用戶或模型發(fā)起 Action,調(diào)用 Client,Client 請(qǐng)求 Server 來獲取資源或執(zhí)行工具(read_resource(),call_tool())。
- 綠框:會(huì)話階段(Server 發(fā)起),Server 調(diào)用 Client 獲得 Sampling 支持,Client 轉(zhuǎn)發(fā)給 Host 并獲取響應(yīng),然后返回給 Server。
三、實(shí)現(xiàn)細(xì)節(jié)
3.1 Tools 和 Resources 管理
在 Python SDK 中,Server 側(cè)使用 ToolManager 管理當(dāng)前 Server 的所有 Tool,并提供 list_tools() 和 call_tool() 方法:
Host 端會(huì)管理所有的 Client,通過這些 Client 可以管理所有 Server 的所有 Tools。如下圖所示,OpenAI 的 Agents 庫中提供了 get_all_function_tools() 來獲取所有 Server 的所有 Tools(openai-agents-python/src/agents/mcp/util.py [4]),并且不允許 Tool name 有重復(fù)(即使在不同的 Server):
PS:不同的 Host 可以實(shí)現(xiàn)不同的管理方式,但是最終將這些 Tools 傳入 LLM 的方式都類似。此外,管理 Resources 的機(jī)制也類似。
3.2 與 LLM 的結(jié)合
3.2.1 Function Call
有了 Tools 和 Resources,Host 是怎么判斷使用哪個(gè) Server 的哪個(gè) tool/resource 呢?其實(shí)和之前的 AI Agent 沒有什么本質(zhì)區(qū)別。依然是將可用的 tool 和 resource 傳入 LLM,依賴 LLM 的 Function Call 能力來智能選擇。
如下圖所示為 OpenAI 的 Function Call(Function calling - OpenAI API [5]) 調(diào)用方式及 Anthropic Claude 的 Function Call(Tool use with Claude - Anthropic [6])調(diào)用方式,整體基本一致,只是一個(gè)是 “parameters”,一個(gè)是“input_schema”。Qwen (Function Calling - Qwen [7])也基本類似,替換使用的 LLM 的成本也相對(duì)比較低。
3.2.2 Server & Tool 選擇
當(dāng)前常見的 Host 中不會(huì)特意選擇 Server,而是將所有 Server 的 Tools 匯總,一起交由 LLM 來選擇。而 Tools 越多,就會(huì)導(dǎo)致 LLM 的 Input Token 數(shù)越多,造成 LLM 調(diào)用成本的增加,也可能導(dǎo)致效果的降低。如下所示,OpenAI Function Call 的文檔中建議 Tools 的數(shù)量不超過 20 個(gè)(Function calling - OpenAI API [5])
除此之外,有些場(chǎng)景并不需要使用 Tools,為此 OpenAI 中也提供 tool_choice 選項(xiàng):
- Auto:表示由 LLM 判斷是否使用 tool,以及使用哪些 tool。
- Required:表示必須使用至少一個(gè) tool。
- Forced Function:表示強(qiáng)制使用某個(gè) tool。
當(dāng)然,上述有個(gè)潛在的問題,無論是否使用 tool,都需要把全量 Tools 傳入 LLM,必然造成輸入 Token 數(shù)的增加,也就是成本的增加(PS:也可以通過 Prefix Cache 緩解)。隨著 MCP 的發(fā)展,Tools 的數(shù)量會(huì)越來越多,此時(shí)就會(huì)需要一種低成本的機(jī)制,調(diào)用 LLM 之前對(duì) Tools 進(jìn)行粗篩,然后再供 LLM 選擇。
3.3 MCP Prompt 的使用
在 MCP 中,Prompts 是服務(wù)器向客戶端暴露的“用戶可控”模板,用于標(biāo)準(zhǔn)化和復(fù)用與大模型交互的常見流程。Client 可以通過 JSON?RPC 調(diào)用 prompts/list 發(fā)現(xiàn)可用模板,再通過 prompts/get 獲取具體的消息序列(messages),并可傳入動(dòng)態(tài)參數(shù)或嵌入資源上下文,從而自動(dòng)化地生成用戶與模型之間的交互內(nèi)容。相應(yīng)的過程如下圖所示:
- Discovery:調(diào)用 prompts/list 方法,獲得所有可用 Prompts,對(duì)應(yīng)我們前面介紹的 list_prompts()。
- Usage:調(diào)用 prompts/get 方法,并傳入必要的參數(shù),以便組裝 Prompt 或者嵌入資源(Resource)上下文,對(duì)應(yīng)我們前面介紹的 get_prompt()。
- Changes:Server 也可以更新 Prompt 并通知 Client(notifications/prompts/list_changed) 相應(yīng)的變更,Client 需要重新獲取 Prompts。
四、示例
4.1 MCP Server 開發(fā)和驗(yàn)證
可以參考 The official Python SDK for Model Context Protocol servers and clients [3] 中的示例快速實(shí)現(xiàn)一些 Demo。如下圖所示,我們?cè)?Demo Server 中提供兩個(gè) Tool:
- pack:給定兩個(gè)整數(shù),返回的是打包過程,這里我們求和并額外加了 1000000,以便區(qū)分 LLM 自己生成的結(jié)果。
- get_paper_abstract:給定一個(gè) Arxiv 論文的 ID,返回對(duì)應(yīng)論文的摘要。
開發(fā)完可以先使用 mcp 的 Inspector 工具(Inspector - Model Context Protocol [8])對(duì) Server 進(jìn)行調(diào)試,使用 “Tools” 中的 “List Tools” 可以列出所有可用工具,有對(duì)應(yīng)的 name 和 description。選中對(duì)應(yīng)工具并輸入相關(guān)參數(shù)即可以 “Run Tool” 并獲得結(jié)果:
4.2 Claude Desktop 集成 MCP Server
驗(yàn)證完 Server 的正確性即可以將其集成到 Claude Desktop 中使用。首次使用可以創(chuàng)建一個(gè)空的 “~/Library/Application\ Support/Claude/claude_desktop_config.json” 文件并編輯,即可激活 Claude Desktop 的 MCP 支持。如下所示,可以在 claude_desktop_config.json 中配置相應(yīng)的 McpServers,這里是一個(gè) Dict,可以配置多個(gè) Server。這里用 uv 管理 Python 環(huán)境,command 中最好寫上絕對(duì)路徑,不然在 Mac 中可能異常:
配置完之后重啟 Claude Desktop 會(huì)發(fā)現(xiàn)多了如下的工具選項(xiàng)(PS:如果 Server 有問題,啟動(dòng)時(shí)會(huì)有相應(yīng)報(bào)錯(cuò),可以查看對(duì)應(yīng)日志文件):
展開工具選項(xiàng)可以看到剛才配置的 Server 中的兩個(gè)工具(PS:當(dāng)前 Claude Desktop 支持的還不完善,比如,配置了 Resource Template 沒有生效),如下所示:
4.3 Tool 驗(yàn)證
集成之后就可以在 Claude Desktop 中使用相應(yīng)的工具。
如下圖所示為 pack 工具的驗(yàn)證:
- 問題:“請(qǐng)打包 321 和 654 兩個(gè)數(shù)?!?/li>
- 紅框:執(zhí)行了對(duì)應(yīng)的 pack 工具,并輸出 “321 + 654 = 1000975”。
- 藍(lán)框:LLM 將工具返回的內(nèi)容 “321 + 654 = 1000975” 再次輸入 LLM,獲得對(duì)應(yīng)的文本輸出。
如下圖所示為 get_paper_abstract 工具的驗(yàn)證:
- 問題:“請(qǐng)給我提供論文 2504.02263 的摘要”。
- 紅框:執(zhí)行了對(duì)應(yīng)的 get_paper_abstract 工具,并輸出論文的英文摘要。
- 藍(lán)框:LLM 將工具返回的英文摘要重新輸入 LLM,由于我們用中文提問,因此 LLM 自動(dòng)進(jìn)行了中文翻譯,并輸出翻譯后的摘要。
五、參考鏈接
- ??https://modelcontextprotocol.io/introduction??
- ??https://www.dailydoseofds.com/p/visual-guide-to-model-context-protocol-mcp/??
- ??https://github.com/modelcontextprotocol/python-sdk??
- ??https://github.com/openai/openai-agents-python/blob/main/src/agents/mcp/util.py??
- ??https://platform.openai.com/docs/guides/function-calling/function-calling?api-mode=responses??
- ??https://docs.anthropic.com/en/docs/build-with-claude/tool-use/overview??
- ??https://qwen.readthedocs.io/en/latest/framework/function_call.html??
- ??https://modelcontextprotocol.io/docs/tools/inspector??
本文轉(zhuǎn)載自?????AI閑談?????,作者:AI閑談
