狩猎区:射击2026
165.2MB · 2026-04-06
在上一篇文章中,我们解析了一个关于天气实时预报的MCP server,相信大家对这一块应该有不错的体感了。那么我们这一篇就会来讲解一下MCP 客户端的一些问题和配置,如果篇幅合适的话还会讲MCP的一些高级特性
如果你对前面的内容感兴趣,可以点击这里跳转
MCP (Model Context Protocol) 技术理解 - 第一篇
MCP (Model Context Protocol) 技术理解 - 第二篇
MCP (Model Context Protocol) 技术理解 - 第三篇
MCP (Model Context Protocol) 技术理解 - 第四篇
MCP (Model Context Protocol) 技术理解 - 第五篇
很多人可能有这个误区,应该是LLM直接发出指令来调用对应的MCP server的吧,但是实际上这个想法是错误的,根本原因在于LLM没有外调的能力,即不能直接调用接口。
那么一般调用MCP server会有两种情况,但是无论是什么情况,我们都是AI应用通过MCP client来调用MCP server,LLM只负责推理输入和输出,下面我们来讲讲这两种情况,然后我们再仔细地讲讲MCP client配置。
安全隔离: 这意味着你可以在 Client 层前做拦截。如果 LLM 发疯了,想执行 rm -rf /,你的 Java/Go 代码可以在发送给 Server 之前检测并拦截这个请求。
协议转换: LLM 输出的是文本/Token,MCP Server 需要的是 JSON-RPC 消息。你的 Client 就是这个 Adapter (适配器) 。
如果你只是想让 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 为例)
npx -y @modelcontextprotocol/server-filesystem)作为子进程。initialize 请求,协商协议版本和能力。tools/list, tools/call, resources/read 等 JSON-RPC 消息所以在这种场景下,你需要自己编写MCP client进行初始化链接,维护相关协议和连接,发送消息和处理响应等等。
那么大家在看完上面的示例可能还有疑惑,那么LLM到底是干嘛的?别急,我们上面说了,AI应用通过MCP client来调用MCP server,LLM只负责推理输入和输出,下面我来给大家解析一遍完整的调用链,大家一看便知!
我们先强调各个角色吧:
AI应用:负责管控全局,协调各个请求和负载均衡
MCP client:负责连接 Server,管理进程,维护对话上下文
MCP server:它是无状态的 Worker。它不知道上下文,不知道是谁在问,只负责接收指令 -> 干活 -> 返回结果
LLM:它没有手脚(不能联网、不能读文件)。它负责分析用户的自然语言,对比 AI应用 给它的“Tools list”,然后生成一个结构化的 JSON 文本,告诉 AI应用:“请帮我调用这个函数,参数是 X 和 Y”
以下是一次完整的交互流程:
初始化 (Handshake) :
fs.read),我会查数据库 (db.query)。"用户提问:
user_id=101 的订单。"Prompt 组装 (AI应用 内部逻辑) :
LLM 决策:
LLM 经过推理,发现 db.query 工具能解决这个问题。
LLM 返回给 AI应用 (而不是直接给 Server):
{
"tool_use": "db.query",
"params": {
"sql": "SELECT * FROM orders WHERE user_id=101"
}
}
执行 (真正的 MCP 调用发生在这里) :
tools/call 请求。Server 响应:
回环 (Loop Back) :
[Order A, Order B],请生成给用户的最终回复。"最终输出:
ok,我相信通过上面的解析,大家已经对整个调用过程是非常清晰的了,接下来我再按场景逐渐解析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-serveruv 切换到特定目录并运行该项目。filesystem 示例分析:
npx -y @modelcontextprotocol/server-filesystem /Users/username/Documents-y: 自动确认安装。/Users/...: 这是传给 Server 程序内部的参数,告知它允许访问哪个文件夹(白名单机制)。env (环境变量)这是子进程启动时注入的 Environment Variables。
ENV 或在本地 .env 文件中定义变量一样。GITHUB_PERSONAL_ACCESS_TOKEN 会被注入到该进程的上下文中,Server 代码中通过 os.Getenv("GITHUB_PERSONAL_ACCESS_TOKEN") (Go) 或 System.getenv(...) (Java) 获取。这就是我们上面说的场景二,在自己构建的AI应用中,我们需要使用官方提供的SDK来编写MCP client的相关代码。
这里多说一句,官方提供了许多SDK,其中后端开发常用的Go是由Google和Go官方来维护,Java则是Spring AI官方维护,而Python则是MCP官方进行维护
下面是使用Python SDK来编写MCP client相关代码
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
# 配置服务器参数
server_params = StdioServerParameters(
command="uv",
args=["--directory", "/path/to/weather", "run", "weather-server"],
)
async def main():
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# 初始化连接
await session.initialize()
# 列出可用工具
tools = await session.list_tools()
print("Available tools:", tools)
# 调用工具
result = await session.call_tool(
"get_forecast",
arguments={"latitude": 37.7749, "longitude": -122.4194}
)
print("Forecast:", result)
# 列出资源
resources = await session.list_resources()
print("Available resources:", resources)
# 读取资源
config = await session.read_resource("weather://config")
print("Config:", config)
if __name__ == "__main__":
import asyncio
asyncio.run(main())
这一篇我们解答了MCP client的一些问题,包括client如何调用server,还有不同场景下我们该如何调用server等等,我相信通过这一篇和前面的文章,大家也已经对MCP比较了解了,下一篇我们再讲讲MCP的高级特性和一些需要注意的点。