当前位置: 首页 > web >正文

MCP 协议原理与系统架构详解—从 Server 配置到 Client 应用

1. MCP

MCPModel 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 通信协议

两种类型:STDIOSSE

在这里插入图片描述
MCP 协议中的 STDIOSSE 其实就是是两种不同的(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 参数,在没有填写时,这里默认推荐的是 uvxnpx

在这里插入图片描述
mongodb 的例子中, command 使用的就是 npx 。在一些文章中说,只要安装了 Node.js 环境,就可以使用,那为什么这里不写 node,而要用 npx 命令呢?

npxNode.js 生态系统中的一个命令行工具,它本质上是 npm的一个扩展npx 的名字可以理解为“运行一个包”(npm execute package)的缩写

npmNode.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 中的 /ccmd.exe 的参数,表示“执行后续命令后关闭窗口”。完整的执行流程是:

cmd.exe /c npx -y @modelcontextprotocol/server-filesystem "~/Downloads"

这里 cmd.exe 先解析 /c,再将 npx … 作为子命令执行,确保 Windows 能正确调用 Node.js 脚本(npx)。

通过分析 MCP Server 的配置,了解了 MCP ClinetMCP Server 的通信协议、执行的命令和参数,以及两者数据传输的标准格式,这样 MCP ClinetMCP Server 的交互方式基本上就弄清楚了。

那执行 MCP Server 一定要通过 npx 或 uvx 运行一个包吗?

当然不是,实际上任何能够在命令行执行代码的方式,都是可以的,比如可以直接把一个 MCP Server 的仓库拉取到本地,然后通过 nodepython 命令直接执行里面的代码文件,这样就可以实现完全断网运行(前提是 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();
    

操作非常简单,只需按照这个模板添加更多工具功能即可。ResourcesPrompt的编写方法也基本一致,大家只要根据提示词模板定义好需求,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_nametool_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 的标准格式来和模型进行交互。

ClineMCP 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 最终流程总结

一、初始化阶段

  1. 客户端启动与工具列表获取​
    • 用户首先启动 MCPClient,完成初始化操作。​
    • MCPClientMCPServer 发送 GET /tools/list 请求,获取可用工具的元数据。​
    • MCPServer 返回包含工具名称、功能描述、参数要求等信息的 工具列表JSON,供客户端后续构建提示词使用。

二、交互阶段

  1. 用户输入与提示词构建​
    • 用户通过 MCPClient 输入自然语言请求(如“查询服务器状态”“生成文件报告”等)。​
    • MCPClient 将用户请求与初始化阶段获取的 工具列表 结合,生成包含任务目标和工具能力的提示词(Prompt),传递给LLMService(大语言模型服务层)。​
  2. 工具描述传递方式(二选一)​
    • 方式1(Function Call):​
      LLMService 通过 LLM_API 调用大语言模型时,在请求中直接携带 工具schema(结构化工具定义,如参数格式、调用格式),告知模型可用工具的调用方式。​
    • 方式2(系统提示词嵌入):​
      LLMService 将工具列表以自然语言描述形式嵌入 系统提示词(System Prompt),让模型在理解用户需求时知晓可用工具的功能边界。​
  3. 模型决策与响应解析​
    • LLM_API 返回包含 tool_decision(工具调用决策)的响应:​
      - 若判定 无需工具(如简单文本回复),响应直接包含最终答案;​
      - 若判定 需要工具(如需要执行本地命令、调用外部接口),响应中包含所需工具的参数要求(如工具名称、入参格式)。
    • LLMService 解析决策结果,将信息传递给 MCPClient
  4. 工具调用分支(需要工具时)
  • 获取命令模板MCPClient 根据模型指定的工具名称,在初始化时保存的工具配置中取出对应的命令模板(如Shell命令格式、API调用参数模板)。​
  • 生成与执行命令MCPClient 将用户输入参数与命令模板结合,通过 ToolService(工具执行服务)生成完整可执行命令,并提交给 本地系统 执行。​
    - 结果处理本地系统 返回原始执行结果(如命令输出文本、API返回数据),ToolService 将其转换为结构化结果(如JSON格式),反馈给 MCPClient。​
  • 二次调用模型生成最终回复:MCPClient 将结构化结果与用户原始问题一并提交给 LLMService,通过 LLM_API调用模型,将技术化的执行结果转化为自然语言描述(如将“服务器CPU使用率80%”转化为“当前服务器CPU负载较高,建议检查进程”)。​
  1. 直接回复分支(无需工具时)​
  • 若模型判定无需工具,MCPClient 直接将模型响应显示给用户(如简单的文本问答、信息总结)。

三、最终输出​
无论是否经过工具调用,MCPClient 最终将处理后的 自然语言结果 呈现给用户,完成整个交互流程。

在这里插入图片描述

http://www.xdnf.cn/news/18859.html

相关文章:

  • SSM从入门到实战:3.1 SpringMVC框架概述与工作原理
  • AI 应用开发:从 Prompt 工程到实战应用开发
  • 基于Flask和AI的智能简历分析系统开发全流程
  • golang 基础类 八股文400题
  • 数据赋能(406)——大数据——数据系统安全性原则
  • k8s笔记04-常用部署命令
  • Matlab高光谱遥感、数据处理与混合像元分解实践技术应用
  • 从Java全栈到前端框架的深度探索
  • Android进入Activity时闪黑生命周期销毁并重建
  • 波音787项目:AR技术重塑航空制造的数字化转型
  • 如何用DeepSeek让Excel数据处理自动化:告别重复劳动的智能助手
  • EXCEL自动调整列宽适应A4 A3 A2
  • 云手机挂机掉线是由哪些因素造成的?
  • SQL语法指南
  • Maven下载历史版本
  • AI测试工具midsence和browse_use的使用场景和差异
  • 行向量和列向量在神经网络应用中的选择
  • CPTS-Pressed复现(XML-RPC)
  • 【沉浸式解决问题】NVIDIA 显示设置不可用。 您当前未使用连接到NVIDIA GPU 的显示器。
  • 智能电视MaxHub恢复系统
  • 了解一下大模型微调
  • 基于SpringBoot的物资管理系统【2026最新】
  • pikachu之Over permission
  • 从零到一:现代化充电桩App的React前端参考
  • 自动修改excel 自动统计文件名称插入 excel辅助工具
  • 【基础-单选】向服务器提交表单数据,以下哪种请求方式比较合适
  • 处理端口和 IP 地址
  • 基于Java企业商城网站
  • 彻底解决PyCharm中Matplotlib无法显示图形及中文乱码问题
  • C-JSON接口的使用