MCP (Model Context Protocol) 技术理解 - 第六篇

📅 发布时间:2026/7/15 15:22:33 👁️ 浏览次数:
MCP (Model Context Protocol) 技术理解 - 第六篇
文章目录引言如何调用MCP server场景一作为用户在现有host中调用场景二作为开发者通过代码调用一次MCP调用示例在AI应用里面配置MCP server通过代码来调用MCP server总结引言在上一篇文章中我们解析了一个关于天气实时预报的MCP server相信大家对这一块应该有不错的体感了。那么我们这一篇就会来讲解一下MCP 客户端的一些问题和配置如果篇幅合适的话还会讲MCP的一些高级特性如果你对前面的内容感兴趣可以点击这里跳转MCP (Model Context Protocol) 技术理解 - 第一篇MCP (Model Context Protocol) 技术理解 - 第二篇MCP (Model Context Protocol) 技术理解 - 第三篇MCP (Model Context Protocol) 技术理解 - 第四篇MCP (Model Context Protocol) 技术理解 - 第五篇如何调用MCP server很多人可能有这个误区应该是LLM直接发出指令来调用对应的MCP server的吧但是实际上这个想法是错误的根本原因在于LLM没有外调的能力即不能直接调用接口。那么一般调用MCP server会有两种情况但是无论是什么情况我们都是AI应用通过MCP client来调用MCP serverLLM只负责推理输入和输出下面我们来讲讲这两种情况然后我们再仔细地讲讲MCP client配置。安全隔离: 这意味着你可以在 Client 层前做拦截。如果 LLM 发疯了想执行rm -rf /你的 Java/Go 代码可以在发送给 Server 之前检测并拦截这个请求。协议转换: LLM 输出的是文本/TokenMCP Server 需要的是 JSON-RPC 消息。你的 Client 就是这个Adapter (适配器)。场景一作为用户在现有host中调用如果你只是想让 Claude code 或 Cursor 等AI应用调用一个现有的 MCP Server或者你自己编写的MCP server你不需要写MCP client代码只需要修改配置文件。在这种情况host就是AI应用已经内置写好的MCP client代码了你配置好MCP server即可调用会自动维护连接。场景二作为开发者通过代码调用如果你想在自己的 Java 或 Go 程序中调用一个 MCP Server例如构建一个能调用本地工具的 AI Agent你需要实现一个 MCP Client。核心交互流程 (以 Stdio 为例)启动进程: 你的程序Client启动 MCP Server如npx -y modelcontextprotocol/server-filesystem作为子进程。握手 (Initialization): 发送initialize请求协商协议版本和能力。发送指令: 发送tools/list,tools/call,resources/read等 JSON-RPC 消息所以在这种场景下你需要自己编写MCP client进行初始化链接维护相关协议和连接发送消息和处理响应等等。一次MCP调用示例那么大家在看完上面的示例可能还有疑惑那么LLM到底是干嘛的别急我们上面说了AI应用通过MCP client来调用MCP serverLLM只负责推理输入和输出下面我来给大家解析一遍完整的调用链大家一看便知我们先强调各个角色吧AI应用负责管控全局协调各个请求和负载均衡MCP client负责连接 Server管理进程维护对话上下文MCP server它是无状态的 Worker。它不知道上下文不知道是谁在问只负责接收指令 - 干活 - 返回结果LLM它没有手脚不能联网、不能读文件。它负责分析用户的自然语言对比 AI应用 给它的“Tools list”然后生成一个结构化的 JSON 文本告诉 AI应用“请帮我调用这个函数参数是 X 和 Y”以下是一次完整的交互流程初始化 (Handshake):Client启动Server。Client询问Server: “你有什么本事(Tools List)”Server回答: “我会读文件 (fs.read)我会查数据库 (db.query)。”用户提问:用户对Client说: “帮我查一下user_id101的订单。”Prompt 组装 (AI应用 内部逻辑):AI应用将用户的 System Prompt Server 提供的工具定义 (Schema) 用户问题打包发给LLM。LLM 决策:LLM经过推理发现db.query工具能解决这个问题。LLM返回给AI应用(而不是直接给 Server):{ tool_use: db.query, params: { sql: SELECT * FROM orders WHERE user_id101 } }执行 (真正的 MCP 调用发生在这里):AI应用解析 LLM 的响应发现它想调用工具控制MCP client发送相关请求和数据。Client通过 JSON-RPC (Stdio/SSE) 向MCP Server发送tools/call请求。Server 响应:Server执行 SQL返回 JSON 数据给Client。回环 (Loop Back):AI应用接收到client返回的数据将 Server 的执行结果再次喂给LLM。AI应用说: “刚才你让我调用的工具结果是[Order A, Order B]请生成给用户的最终回复。”最终输出:LLM生成自然语言: “用户你好ID 为 101 的用户有两笔订单…”在AI应用里面配置MCP serverok我相信通过上面的解析大家已经对整个调用过程是非常清晰的了接下来我再按场景逐渐解析MCP client的问题。在上面的分析中我们已经分析了在Claude code里面我们只需要进行MCP server的配置即可而不需要编写MCP client的相关代码下面我们以Claude code为例子讲讲如何配置MCP server。我们可以在claude_desktop_config.json的文件中进行server的配置// ~/Library/Application Support/Claude/claude_desktop_config.json{mcpServers:{weather:{command:uv,args:[--directory,/absolute/path/to/weather,run,weather-server]},filesystem:{command:npx,args:[-y,modelcontextprotocol/server-filesystem,/Users/username/Documents]},github:{command:npx,args:[-y,modelcontextprotocol/server-github],env:{GITHUB_PERSONAL_ACCESS_TOKEN:ghp_your_token_here}}}}你可以把每一项配置看作是在终端执行一个长连接的子进程。以下是详细的参数拆解1.mcpServers:根节点是一个 Map。Key如weather,github是该 Server 的唯一标识符用于在 AI 界面显示和内部隔离。2.command(可执行文件)这是 Client 尝试启动的二进制文件或脚本解释器。作用: 指定入口程序。常见值:npx(Node.js),python,uv(Python 包管理器), 或者你编译好的 Go/Java 二进制文件如/usr/local/bin/my-go-server。args(启动参数)这是一个字符串数组会被追加在command后面形成完整的 shell 启动命令。weather示例分析:uv --directory /path/to/weather run weather-server这告诉uv切换到特定目录并运行该项目。filesystem示例分析:npx -y modelcontextprotocol/server-filesystem /Users/username/Documents-y: 自动确认安装。最后一个参数/Users/...: 这是传给 Server 程序内部的参数告知它允许访问哪个文件夹白名单机制。env(环境变量)这是子进程启动时注入的Environment Variables。作用: 用于传递敏感信息API Keys或配置参数而不需要将其硬编码在代码或命令行参数中。后端视角: 就像你在 Docker 中配置ENV或在本地.env文件中定义变量一样。GitHub 示例:GITHUB_PERSONAL_ACCESS_TOKEN会被注入到该进程的上下文中Server 代码中通过os.Getenv(GITHUB_PERSONAL_ACCESS_TOKEN)(Go) 或System.getenv(...)(Java) 获取。通过代码来调用MCP server这就是我们上面说的场景二在自己构建的AI应用中我们需要使用官方提供的SDK来编写MCP client的相关代码。这里多说一句官方提供了许多SDK其中后端开发常用的Go是由Google和Go官方来维护Java则是Spring AI官方维护而Python则是MCP官方进行维护下面是使用Python SDK来编写MCP client相关代码frommcpimportClientSession,StdioServerParametersfrommcp.client.stdioimportstdio_client# 配置服务器参数server_paramsStdioServerParameters(commanduv,args[--directory,/path/to/weather,run,weather-server],)asyncdefmain():asyncwithstdio_client(server_params)as(read,write):asyncwithClientSession(read,write)assession:# 初始化连接awaitsession.initialize()# 列出可用工具toolsawaitsession.list_tools()print(Available tools:,tools)# 调用工具resultawaitsession.call_tool(get_forecast,arguments{latitude:37.7749,longitude:-122.4194})print(Forecast:,result)# 列出资源resourcesawaitsession.list_resources()print(Available resources:,resources)# 读取资源configawaitsession.read_resource(weather://config)print(Config:,config)if__name____main__:importasyncio asyncio.run(main())总结这一篇我们解答了MCP client的一些问题包括client如何调用server还有不同场景下我们该如何调用server等等我相信通过这一篇和前面的文章大家也已经对MCP比较了解了下一篇我们再讲讲MCP的高级特性和一些需要注意的点