1. MCP
MCP
(Model Context Protocol
,模型上下文協議)是開發 Claude
模型的(Anthropic)公司推出的一個開放標準協議,就像是一個 “通用插頭” 或者 “USB 接口”,制定了統一的規范,不管是連接數據庫、第三方 API
,還是本地文件等各種外部資源,目的就是為了解決 AI
模型與外部數據源、工具交互的難題。
MCP(Model Context Protocol)
的工作機制大致如下:MCP Host(如 Claude Desktop、Cursor 等應用)在其內部集成了 MCP Client。該客戶端通過標準的 MCP 協議與 MCP Server 進行通信。MCP Server 通常由第三方開發者提供,負責實現與外部資源(如數據庫、瀏覽器、本地文件系統等)交互的具體邏輯。執行結果通過相同的 MCP 協議返回至 MCP Client,最終在 MCP Host 界面中呈現給用戶。
2. MCP Server 配置結構解析
以 Cherry Studio
為例,解析 MCP Server
配置為何這樣設計
2.1 通信協議
兩種類型:STDIO
和 SSE
MCP
協議中的 STDIO 和 SSE 其實就是是兩種不同的(MCP Server 與 MCP Client)通信模式:
- STDIO(標準輸入輸出,像面對面對話):客戶端和服務器通過本地進程的標準輸入和標準輸出直接通信。例如:本地開發時,你的代碼腳本通過命令行啟動,直接與 MCP 服務器交換數據,無需網絡連接。
- SSE(服務器推送事件,像電話熱線):客戶端通過 HTTP 協議連接到遠程服務器,服務器可以主動推送數據(如實時消息)。例如:AI 助手通過網頁請求調用遠程天氣 API,服務器持續推送最新的天氣信息。
通俗地說,STDIO 方式需要將 MCP Server 下載到本地運行并調用,而 SSE 方式則是通過 HTTP 服務遠程訪問托管在服務器上的 MCP Server。
SSE MCP Server 的配置示例,直接使用網絡協議和工具進行通信:
{"mcpServers": {"browser-use-mcp-server": {"url": "http://localhost:8000/sse"}}
}
FileSystem、Mongodb 典型的 STDIO 調用:
{"mcpServers": {"mongodb": {"command": "npx","args": ["-y","@modelcontextprotocol/server-filesystem","~/Downloads"]}}
}
STDIO 為程序的輸入輸出提供了一種統一的標準方式,無論是什么類型的程序,只要遵循 STDIO 協議,就可以方便地進行數據的輸入和輸出,并且可以很容易地與其他程序或系統組件進行交互。
在命令行中,使用 STDIO 通信是非常常見的,在 Linux 系統中的 cat
命令就是一個極為簡單且能體現 STDIO 通信的例子。cat
命令通常用于連接文件并打印到標準輸出。當你不指定任何文件時,它會從標準輸入讀取內容,并將其輸出到標準輸出。?在這個過程中,cat
命令從標準輸入讀取內容,接著將輸出重定向
到文件,這就是一個最簡單的 STDIO 通信案例。
2.2 命令和參數
對應 JSON 配置中的 command 參數,在沒有填寫時,這里默認推薦的是 uvx
和 npx
:
mongodb
的例子中, command 使用的就是 npx
。在一些文章中說,只要安裝了 Node.js 環境,就可以使用,那為什么這里不寫 node,而要用 npx
命令呢?
npx
是 Node.js 生態系統中的一個命令行工具,它本質上是 npm的一個擴展
。npx
的名字可以理解為“運行一個包”(npm execute package)的縮寫。
npm 是 Node.js 的包管理工具。通過將通用工具封裝為 npm 包發布,任何安裝了 Node.js 的環境都能輕松下載并使用這些功能。
npx 的主要功能就是幫助快速運行一些通過 npm 安裝的工具,而不需要手動去下載安裝這些工具到全局環境。
{"mcpServers": {"mongodb": {"command": "npx","args": ["-y","@modelcontextprotocol/server-filesystem","~/Downloads"]}}
}
在這個配置中,args
里第一個參數 "-y"
其實就等同于 --yes
,其作用是在執行命令時自動同意所有提示信息,可以避免交互式的確認步驟。
第二個參數其實就是這個 npm 包的名字
,比如 @modelcontextprotocol/server-filesystem 這個包:
args
里的第三個參數就是傳遞給這個包的一個必備參數:允許讀取的本機路徑。
這幾個信息,再加上大模型
分析用戶輸入后得出的參數,通過 STDIO
協議傳遞給這個包,就可以構成一條在終端直接可以運行的一條命令:
npx -y @modelcontextprotocol/server-filesystem ~/Downloads <<< '{"method":"tools/call","params":{"name":"list_directory","arguments":{"path":"~/Downloads"}},"jsonrpc":"2.0","id":1}'
把輸入內容格式化:
<<<
(Here 字符串操作符)的主要用途是將一個字符串作為標準輸入(STDIN)傳遞給前面的命令。
在這個命令中,通過 <<< 操作符
,把后面的字符串傳遞給前面的命令(也就是@modelcontextprotocol/server-filesystem
這個包)當作輸入數據。?后面的字符串中包含了需要調用的函數(list_directory
),以及傳遞給這個函數的參數(~/Downloads
),前面的部分都是在 MCP Server
中配置的內容,屬于固定的部分。而大模型做的,就是根據用戶當前的輸入,以及當前支持的 MCP
工具列表,判斷出要不要調用這個工具,如果要調用,生成結構化的工具參數,最后 MCP Client
通過 STDIO
協議將這個結構化的參數再傳遞給 MCP Server
。
在上面的命令中,還有一個選項是 uvx
,和 npx 類似,它也可以直接讓你臨時執行某個工具包,而無需全局安裝。不過 uvx
:是 uv 工具鏈的一部分
,主要聚焦于 Python 生態系統,它會創建一個臨時的隔離 Python 環境來運行 Python 工具包。
2.3 傳輸格式
請查看剛才命令的執行結果。
也是一段格式化好的內容,里面返回了當前目錄下的所有文件,而模型在接收到這段格式化的輸出后,會將其變成口語化的內容再返回到 MCP 客戶端。
這個輸入、輸出的參數格式,遵循的是 JSON-RPC 2.0
傳輸格式,它有一套自己的規則,規定了請求和響應的格式、如何處理錯誤等,官方文檔的中的描述:
2.4 Windows 配置
實際使用時,您可能會注意到該配置在Windows系統中可能無法正常生效。
{"mcpServers": {"mongodb": {"command": "npx","args": ["-y","@modelcontextprotocol/server-filesystem","~/Downloads"]}}
}
需要改成下面的方式:
{"mcpServers": {"mongodb": {"command": "cmd","args": ["/c","npx","-y","@modelcontextprotocol/server-filesystem","~/Downloads"]}}
}
這是因為在不同操作系統下 默認命令解釋器(Shell)的工作機制不同:
macOS
的終端(如 bash/zsh)是 Unix shell,支持直接執行可執行文件(如 npx)。Windows 的默認命令解釋器是 cmd.exe
,而非直接執行程序。即使 npx 已安裝(如通過全局 npm install -g npx),也需要通過 cmd.exe 來調用,因為:- Windows 不直接識別 Unix 風格的命令路徑(如 npx 本質是 Node.js 腳本,需通過 node 執行)。
- cmd.exe 需要明確的指令格式(如 /c 參數用于執行命令后退出)。
args
中的 /c 是 cmd.exe 的參數,表示“執行后續命令后關閉窗口”。完整的執行流程是:
cmd.exe /c npx -y @modelcontextprotocol/server-filesystem "~/Downloads"
這里 cmd.exe 先解析 /c,再將 npx … 作為子命令執行,確保 Windows 能正確調用 Node.js 腳本(npx)。
通過分析 MCP Server 的配置,了解了 MCP Clinet 和 MCP Server 的通信協議、執行的命令和參數,以及兩者數據傳輸的標準格式,這樣 MCP Clinet 和 MCP Server 的交互方式基本上就弄清楚了。
那執行 MCP Server 一定要通過 npx 或 uvx 運行一個包嗎?
當然不是,實際上任何能夠在命令行執行代碼的方式,都是可以的,比如可以直接把一個 MCP Server 的倉庫拉取到本地,然后通過 node 或 python 命令直接執行里面的代碼文件,這樣就可以實現完全斷網運行(前提是 MCP Server 中不會調用遠程 API)。
{"mcpServers": {"mongodb": {"command": "node","args": ["/path/mcp-server.js"]}}
}
3. MCP Server 開發與調試
3.1 基于 AI 輔助編寫 MCP Server
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";const server = new McpServer({name: "TimeServer", // 服務器名稱version: "1.0.0", // 服務器版本
});// 注冊工具:獲取當前時間
server.tool("getCurrentTime", // 工具名稱"根據時區(可選)獲取當前時間", // 工具描述{timezone: z.string().optional().describe("時區,例如 'Asia/Shanghai', 'America/New_York' 等(如不提供,則使用系統默認時區)"),},async ({ timezone }) => {try {const now = new Date();let timeString: string;if (timezone && Intl.supportedValuesOf("timeZone").includes(timezone)) {timeString = now.toLocaleString("zh-CN", {timeZone: timezone,timeZoneName: "short",});} else {timeString = now.toLocaleString("zh-CN");}return {result: {currentTime: now.toISOString(),formattedTime: timeString,timezone: timezone || Intl.DateTimeFormat().resolvedOptions().timeZone,},};} catch (err) {return {error: {message: `獲取時間失敗: ${err instanceof Error ? err.message : String(err)}`,code: "TIME_ERROR",},};}}
);/*** 啟動服務器,通過 STDIO 與 MCP Host 通信*/
async function startServer() {try {console.log("正在啟動 MCP 時間服務器...");const transport = new StdioServerTransport();await server.connect(transport);console.log("MCP 時間服務器已啟動,等待請求...");} catch (error) {console.error("啟動服務器時出錯:", error);process.exit(1);}
}// 啟動服務
startServer();
-
第一步:使用官方提供的 @modelcontextprotocol/sdk/server/mcp.js 包,創建一個
McpServer
實例:// ==================== 第一步:創建 McpServer 實例 ==================== import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod";// 創建 MCP 服務器實例,聲明服務名稱和版本 const server = new McpServer({name: "TimeServer", // 服務名稱,用于標識version: "1.0.0", // 版本號,便于管理更新 });
-
第二步:使用
server.tool
定義提供的工具方法,包括工具方法的名稱、工具方法的描述、工具方法的參數、工具方法的具體實現邏輯。?另外使用了"zod"
這個包定義了方法參數的類型以及描述。// ==================== 第二步:注冊工具方法 ==================== // 定義一個可被 LLM 調用的工具:獲取當前時間 server.tool("getCurrentTime", // 工具名稱"根據時區(可選)獲取當前時間", // 工具描述{// 使用 zod 定義參數結構和校驗規則timezone: z.string().optional().describe("時區,例如 'Asia/Shanghai', 'America/New_York'(不填則使用系統默認時區)"),},async ({ timezone }) => {try {const now = new Date();let formattedTime: string;// 如果提供了合法時區,則格式化為對應時區時間if (timezone && Intl.supportedValuesOf("timeZone").includes(timezone)) {formattedTime = now.toLocaleString("zh-CN", {timeZone: timezone,timeZoneName: "short",});} else {// 否則使用本地時區formattedTime = now.toLocaleString("zh-CN");}// 返回標準格式的結果return {result: {currentTime: now.toISOString(),formattedTime,timezone: timezone || Intl.DateTimeFormat().resolvedOptions().timeZone,},};} catch (err) {// 返回標準錯誤格式,避免拋出異常導致進程退出return {error: {message: `獲取時間失敗: ${err instanceof Error ? err.message : String(err)}`,code: "TIME_ERROR",},};}} )
-
第三步:啟動
Server
,并且使用SDK
中導出的StdioServerTransport
來定義工具使用STDIO
通信協議,等待外部的標準輸入,并且把工具的執行結果轉化為標準輸出反饋到外部。==================== 第三步:啟動服務器,使用 STDIO 通信 ==================== async function startServer() {try {console.log("正在啟動 MCP 時間服務器...");// 創 // 建基于標準輸入/輸出的傳輸層const transport = new StdioServerTransport();// 將服務器連接到 STDIO 傳輸,開始監聽 stdin 并向 stdout 輸出響應await server.connect(transport);console.log("MCP 時間服務器已啟動,等待來自 Host 的請求...");} catch (error) {console.error("啟動服務器失敗:", error);process.exit(1); // 啟動失敗時退出進程} }// 執行啟動函數 startServer();
操作非常簡單,只需按照這個模板添加更多工具功能即可。Resources
和Prompt
的編寫方法也基本一致,大家只要根據提示詞模板定義好需求,AI
(特別是Claude
的準確度最高)通常都能很好地完成任務。
3.2 使用 inspector 調試 MCP Server
開發完成后,可以直接使用官方提供的 MCP Server
調試工具(@modelcontextprotocol/inspector)
來進行調試。也可以直接通過 npx
運行 @modelcontextprotocol/inspector
:
npx @modelcontextprotocol/inspector <command> <arg1> <arg2>
調試剛剛開發好的工具,這里直接使用 node 運行本地構建好的代碼:
npx @modelcontextprotocol/inspector node dist/index.js
連接成功后,點擊 List Tools:
然后可以看到當前 MCP Server 定義的所有工具,這里定義了一個獲取當前時間的工具,點擊這個工具,可以對它進行調試:
然后可以看到當前 MCP Server 定義的所有工具,這里定義了一個獲取當前時間的工具,點擊這個工具,可以對它進行調試:
基于這樣的思路,可以使用 @modelcontextprotocol/inspector
調試任意的 MCP Server
, 在你想要使用,但是還不知道怎么使用一個 MCP Server 時,都可以使用它進行調試:
npx @modelcontextprotocol/inspector npx -y @modelcontextprotocol/server-filesystem ~/Downloads
3.3 在 Cline 中測試 MCP Server
下面在 Cline
中配置測試一下剛剛開發好的 MCP Server,這里直接使用 node 執行:
測試結果:
4. MCP Client 與 Server 的通信機制詳解
帶著疑問,MCP Clinet
是怎么知道 MCP Server
都提供了哪些工具列表的?模型又怎么從這些工具中選擇出合適的工具?在后續的問答中兩者又是如何配合的呢?
下面用抓包工具來分別對 Cherry Studio 、Cline
兩個工具進行抓包,使用剛剛開發好 MCP Server
,分析整個交互過程。
4.1 配置抓包工具
使用 Charles 這個工具來抓包。
在 Cherry Studio
中,僅有一部分模型支持 MCP
,這里選擇阿里云百煉的 qwen-max
,實測在 Cherry Studio
中工具調用是非常穩定的:
然后在 Charles
中過濾一下阿里云百煉的請求,就可以過濾出后續的請求包了:
在 Cline
中,所有模型都支持 MCP
,這里選擇的是 Openrouter
下免費的 DeepseekV3
。這里需要注意的是, Charles
并不能直接抓取到 VsCode
的請求,需要在 VsCode
下配置代理:
點擊 VsCode
左上角的 “文件” 菜單,選擇 “首選項 > 設置”,搜索 http.proxy
,然后在其中填寫 http://127.0.0.1:8888
,則可以將 vsCode
后續的請求都代理到 Charles
下:
然后在 Charles
中過濾一下 Openrouter
的請求,就可以過濾后續的請求包了:
還有一點需要注意,這些軟件一般是都采用的是流式輸出,所以在響應報文里不會展示完整的 JSON 內容,
可以借助 AI
幫助還原原始的響應報文
4.2 Cherry Studio 抓包分析
在 Cherry Studio
中開啟剛剛開發的 Time MCP Server
,然后詢問 “紐約時間” :
發現軟件實際調用了兩次 LLM API
:
下面直接來看我已經處理好的請求報文(省略了一些無關內容,只保留關鍵信息):
- 第一次請求: 客戶端 將從
MCP Server
獲取到的所有的工具列表,通過tools
參數傳遞給了模型,相當于告訴模型,我現在有這些工具,你可以根據用戶的輸入(messages.content)
判斷是否使用工具,以及使用哪個工具:
第一次響應:模型根據用戶輸入的內容,以及當前支持的工具列表,判斷需要使用getCurrentTime
工具(這里使用id
進行映射),并且拼接好了工具調用所需要的標準參數格式:{"timezone": "America/New_York"}:
- 第二次請求:客戶端將上次模型返回的工具調用參數,以及在本地執行工具調用后的結果都合并到 messages 里,傳遞給模型,讓模型基于這些信息生成最終回答:
第二次響應:模型根據輸入的信息產出最終回答給用戶的內容:
4.3 Cline 抓包分析
在 Cline
中配置好 Time MCP Server
,并且詢問同樣的問題:
然后發現 Charles
中同樣抓到兩條請求:
同樣的,把請求報文處理好,并保存到本地查看:
- 第一次請求:發現請求中并沒有像 Cherry Studio 一樣,包含
tools
字段,而是包含了一段超長的系統提示詞(統計了一下,居然長達 41695 個字符,可見Cline
真的挺費Token
的。):
然后,對這段系統提示詞進行了處理了分析,提取出了關鍵的部分,來具體分析一下:
提示詞第一部分:身份設定
提示詞第二部分:工具使用相關
- 使用原則:說明工具需用戶批準后執行,每條消息只能用一個工具,依據上次工具使用結果逐步完成任務。
- 格式規范:給出工具使用的類似
XML
標簽格式示例,如 <read_file><path>src/main.js</path></read_file>
具體工具介紹:以use_mcp_tool
為例,詳細說明其描述、參數(必填的server_name
、tool_name、arguments
)和用法,并給出使用示例。
使用指南:包括在<Think>
標簽中評估信息、選擇合適工具、迭代使用工具、按格式使用工具、依據用戶回復結果決策、等待用戶確認等內容。
提示詞第三部分:MCP Server
相關
- 協議作用:介紹模型上下文協議(
MCP
)允許系統與本地運行的MCP
服務器通信,擴展能力。? - 已連接服務器操作:說明連接服務器后可通過
use_mcp_tool
使用工具、access_mcp_resource
訪問資源。? - 可用工具:說明工具的描述、具體參數信息
提示詞第四部分:一些約束信息
提示詞第五部分:目標工作流程
- 任務分析與目標設定:分析任務設定可實現目標并排序。?
- 目標處理與工具使用:依次處理目標,每次用一個工具,調用工具前分析并確定參數。?
- 任務完成與結果展示:完成任務用
attempt_completion
工具展示結果,可提供CLI
命令,根據反饋改進,避免無意義對話。
這就是Cline
系統提示詞的關鍵部分,當前這里省略了一些和MCP
不相關的信息,比如Cline
本身提供的一些讀取文件、編寫代碼的工具等等。- 第一次響應:這里和
Cherry Studio
也不一樣,并沒有使用tools_call
字段,而是直接使用assistant
字段返回需要調用的工具信息
格式化一下,發現和系統提示詞里要求的工具調用格式是相同的
- 第二次請求:客戶端將上次模型返回的工具調用參數,以及在本地執行工具調用后的結果都合并到
messages
里,傳遞給模型,讓模型基于這些信息生成最終回答
第二次響應:模型根據輸入的信息產出最終回答給用戶的內容
這里依然按照系統提示詞中約定的標準格式返回
- 第一次響應:這里和
4.4 MCP 的核心流程總結
Cherry Studio
實際上是通過將 MCP Server
中提供的工具、響應結果,轉換為 Function Call
的標準格式來和模型進行交互。
Cline
將 MCP Server
中提供的工具、響應結果轉換未一套自己約定的輸入、輸出的標準數據格式,通過系統提示詞來聲明這種約定,再和模型進行交互。
這也解釋了,為什么在 Cherry Studio
中只有一部分模型支持 MCP
,前提是選擇的模型需要支持 Function Call
的調用,并且在客戶端進行了特殊適配;而 Cline
則使用的是系統提示詞,所以所有模型都支持。
初始化與工具列表獲取:
用戶首先對 MCP 客戶端進行初始化操作,隨后 MCP 客戶端向 MCP 服務器 發送請求以獲取可用的工具列表,MCP 服務器將工具列表返回給客戶端。
用戶輸入與提示詞構建:
用戶在客戶端完成初始化后,向 MCP 客戶端輸入具體請求。客戶端將此前獲取的工具列表與用戶輸入內容相結合,共同組成用于詢問 LLM 的提示詞。
工具傳遞方式選擇:
MCP 客戶端通過兩種方式之一將提示詞傳遞給 LLM :
- 方式1:使用 Function Call(函數調用)直接攜帶工具列表信息;?
- 方式2:在系統提示詞(System Prompt)中包含工具列表。
LLM判斷與響應:
LLM 接收到提示詞后,返回判斷結果:
- 無需工具:LLM直接將處理結果通過MCP客戶端回復給用戶;?
- 需要工具:LLM先向客戶端返回所需工具的參數格式要求。
工具命令生成與執行:
若需要工具,MCP 客戶端根據 LLM 提供的參數格式,以及 MCP Server 配置的命令模板進行拼接,生成完整的可執行命令,并在本地環境(Local_Env)中執行該命令。
結果處理與輸出:
本地環境執行命令后,將結果返回給 MCP 客戶端。客戶端將執行結果提交給 LLM,由 LLM 對技術化的執行結果進行處理,最終以人性化的語言形式輸出給用戶。
5. 基于 mcp-client-nodejs 的 MCP 交互流程
GitHub源碼
:https://github.com/ConardLi/mcp-client-nodejs
使用 Node.js 開發了一個基礎版的 MCP Clinet(基于 Function Call 實現)
5.1 基于 LLM 構建 MCP Client
提示詞:
## 需求?
我想開發一個 Node.js 版的 MCP Clinet ,下面有一些參考材料,包括 MCP 基礎介紹、MCP 核心架構介紹、MCP Clinet 開發教程,請你根據這些參考材料幫我開發一個 MCP Client,注意增加完善的中文注釋,以及在開發完成后編寫一個完善的中文 Readme 說明文檔。?
?
## MCP 基礎介紹?
粘貼 https://modelcontextprotocol.io/introduction 的內容。?
?
## MCP 核心架構介紹?
粘貼 https://modelcontextprotocol.io/docs/concepts/architecture 的內容。?
?
## MCP Client 開發教程?
粘貼 https://modelcontextprotocol.io/quickstart/client 的內容。?
?
## 注意點?
- 使用 openai 的 SDK 替換 @anthropic-ai/sdk ,這樣可以支持更多的模型,兼容性更好?
- 你不要指定依賴的版本,如果遇到安裝依賴讓我自己來安裝,你只負責編寫代碼
5.2 項目介紹
1. 核心技術優勢:
- 支持連接任何符合 MCP 標準的服務器?
- 支持兼容 OpenAI API 格式的 LLM 能力?
- 自動發現和使用服務器提供的工具?
- 完善的日志記錄系統,包括 API 請求和工具調用?
- 交互式命令行界面?
- 支持工具調用和結果處理
2. 安裝和配置:
git clone https://github.com/ConardLi/mcp-client-nodejs.git
cd mcp-client-nodejs
3. 安裝依賴:
npm install
- 所需依賴項:
- @modelcontextprotocol/sdk
- openai
- dotenv
- typescript(開發依賴)
- @types/node(開發依賴)
4. 配置環境變量:
復制示例環境變量文件并設置您的 LLM API
密鑰:
cp .env.example .env
然后編輯 .env
文件,填入您的 LLM API
密鑰、模型提供商 API
地址、以及模型名稱:
OPENAI_API_KEY=your_api_key_here
MODEL_NAME=xxx
BASE_URL=xxx
5. 編譯項目:
npm run build
6. 使用方法:
要啟動 MCP 客戶端,您可以使用以下幾種方式:
-
直接指定服務器腳本路徑
node build/index.js <服務器腳本路徑> # 其中 <服務器腳本路徑> 是指向 MCP 服務器腳本的路徑,可以是 JavaScript (.js) 或 Python (.py) 文件。
-
使用配置文件
node build/index.js <服務器標識符> <配置文件路徑>
其中
<服務器標識符>
是配置文件中定義的服務器名稱,<配置文件路徑>
是包含服務器定義的 JSON 文件的路徑。{"mcpServers": {"time": {"command": "node","args": ["/Users/xxx/mcp/dist/index.js"],"description": "自定義 Node.js MCP服務器"},"mongodb": {"command": "npx","args": ["mcp-mongo-server","mongodb://localhost:27017/studentManagement?authSource=admin"]}},"defaultServer": "mongodb","system": "自定義系統提示詞" }
7. 使用 npm 包(npx):
您可以直接通過 npx
運行這個包,無需本地克隆和構建:
# 直接連接腳本
$ npx mcp-client-nodejs /path/to/mcp-server.js# 通過配置文件連接
$ npx mcp-client-nodejs mongodb ./mcp-servers.json
注意:需要在當前運行目錄的 .env 配置模型相關信息
5.3 分析 MCP 詳細交互流程
MCP Client 包含一個全面的日志系統,詳細記錄所有關鍵操作和通信。日志文件保存在 logs/
目錄中,以 JSON
格式存儲,方便查詢和分析。
- LLM 的請求和響應 - 記錄與 LLM API 的所有通信?
- 工具調用和結果 - 記錄所有工具調用參數和返回結果?
- 錯誤信息 - 記錄系統運行期間的任何錯誤
日志文件連統命名為 [index] [log_type] YYYY-MM-DD HH:MM:SS.json
,包含序號、日志類型和時間戳,方便按時間順序查看整個會話。
下面使用 mcp-mongo-server
來演示整個流程,首先在項目目錄新建 mcp-servers.json
,并填寫下面的配置:
{"mcpServers": {"mongodb": {"command": "npx","args": ["mcp-mongo-server","mongodb://localhost:27017/studentManagement?authSource=admin"]}},"system": "使用中文回復。\n\n當用戶提問中涉及學生、教師、成績、班級、課程等實體時,需要使用 MongoDB MCP 進行數據查詢和操作,表結構說明如下:xxx"
}
然后執行 node build/index.js mongodb ./mcp-servers.json
,客戶端成功啟動:
逐個來看一下:
[0] [GET Tools]
:在客戶端初始化時,拉取當前配置的 MCP Server 下提供的所有工具列表
[1] [LLM Request]
:向大模型發送 用戶問題,并將所有工具列表(包含函數+參數的具體定義)通過 tools 字段傳遞過去
[2] [LLM Response]
:模型根據用戶輸入 + 支持的參數列表判斷需要使用的工具,并通過 tool_calls 字段返回
[3] [Tool Call]
:客戶端根據模型返回的函數+參數+MCP 服務器的配置,拼接成一條可執行的命令,執行第一次工具調用:從 teachers 表中檢索姓張的老師的信息:
[9] [Tool Call]
:客戶端執行工具調用,查詢課程信息
[10] [Tool Call Response]
:工具返回班級信息
[11] [LLM Request]
:客戶端將之前工具調用的所有信息再次返回給模型
[12] [LLM Response]
:模型最終給出人性化輸出
5.4 最終流程總結
一、初始化階段
- 客戶端啟動與工具列表獲取?
- 用戶首先啟動 MCPClient,完成初始化操作。?
- MCPClient 向 MCPServer 發送 GET /tools/list 請求,獲取可用工具的元數據。?
- MCPServer 返回包含工具名稱、功能描述、參數要求等信息的 工具列表JSON,供客戶端后續構建提示詞使用。
二、交互階段
- 用戶輸入與提示詞構建?
- 用戶通過 MCPClient 輸入自然語言請求(如“查詢服務器狀態”“生成文件報告”等)。?
- MCPClient 將用戶請求與初始化階段獲取的 工具列表 結合,生成包含任務目標和工具能力的提示詞(Prompt),傳遞給LLMService(大語言模型服務層)。?
- 工具描述傳遞方式(二選一)?
- 方式1(Function Call):?
LLMService 通過 LLM_API 調用大語言模型時,在請求中直接攜帶 工具schema(結構化工具定義,如參數格式、調用格式),告知模型可用工具的調用方式。?- 方式2(系統提示詞嵌入):?
LLMService 將工具列表以自然語言描述形式嵌入 系統提示詞(System Prompt),讓模型在理解用戶需求時知曉可用工具的功能邊界。?- 模型決策與響應解析?
- LLM_API 返回包含 tool_decision(工具調用決策)的響應:?
- 若判定 無需工具(如簡單文本回復),響應直接包含最終答案;?
- 若判定 需要工具(如需要執行本地命令、調用外部接口),響應中包含所需工具的參數要求(如工具名稱、入參格式)。- LLMService 解析決策結果,將信息傳遞給 MCPClient。
- 工具調用分支(需要工具時)
?
- 獲取命令模板: MCPClient 根據模型指定的工具名稱,在初始化時保存的工具配置中取出對應的命令模板(如Shell命令格式、API調用參數模板)。?
- 生成與執行命令: MCPClient 將用戶輸入參數與命令模板結合,通過 ToolService(工具執行服務)生成完整可執行命令,并提交給 本地系統 執行。?
- 結果處理:本地系統 返回原始執行結果(如命令輸出文本、API返回數據),ToolService 將其轉換為結構化結果(如JSON格式),反饋給 MCPClient。?- 二次調用模型生成最終回復:MCPClient 將結構化結果與用戶原始問題一并提交給 LLMService,通過 LLM_API調用模型,將技術化的執行結果轉化為自然語言描述(如將“服務器CPU使用率80%”轉化為“當前服務器CPU負載較高,建議檢查進程”)。?
- 直接回復分支(無需工具時)?
- 若模型判定無需工具,MCPClient 直接將模型響應顯示給用戶(如簡單的文本問答、信息總結)。
三、最終輸出?
無論是否經過工具調用,MCPClient 最終將處理后的 自然語言結果 呈現給用戶,完成整個交互流程。