MCP技术理解第六篇:深度解析与实战指南

2026-05-29阅读 0热度 0
Protocol

引言

上一篇文章拆解了一个天气实时预报的MCP Server,大家应该对MCP的基本形态有了直观感受。本篇聚焦MCP客户端在实际使用中的配置痛点与调用逻辑,篇幅允许的话,会顺带介绍几个高级特性。

开始前快速回顾系列脉络:前五篇文章从协议基础、工作原理、Server实现等维度层层递进。本篇深入Client端,解决“如何调用”“如何配置”这类落地问题,保持知识连贯性。

如何调用MCP server

一个常见误区:让LLM直接发出指令就能调用MCP Server?并非如此。根本原因在于LLM本身不具备外调能力——它无法发起HTTP请求或执行系统命令。

实际上,MCP Server的调用场景分两类。无论哪种情况,真正的调用方都是AI应用通过MCP Client完成,LLM只负责推理输入与输出。厘清这两类场景后,MCP Client的配置细节就清晰了。

先铺垫两个关键认知:

  • 安全隔离:你可以在Client层做前置拦截。若LLM“发疯”想执行rm -rf /这类危险操作,你的Java或Go代码完全能在发送给Server前检测并阻止。
  • 协议转换:LLM输出文本/Token,MCP Server需要JSON-RPC消息。Client作为适配器(Adapter),负责完成两种格式的互转。

场景一:作为用户在现有host中调用

如果你只想让Claude Code或Cursor这类现成AI应用调用一个MCP Server(包括自建的),完全不需要写MCP Client代码,只需修改配置文件。此时host就是AI应用本身,它已内置MCP Client代码。你配置好Server后,它会自动维护连接并完成后续所有操作。

场景二:作为开发者通过代码调用

如果你想在自己开发的Java、Go或Python程序中调用MCP Server——比如构建一个能调用本地工具的AI Agent——就需要自行实现MCP Client。

以Stdio传输方式为例,核心交互流程简化为三步:

  1. 启动进程:你的程序(Client)启动MCP Server作为子进程,例如执行npx -y @modelcontextprotocol/server-filesystem
  2. 握手(Initialization):发送initialize请求,协商协议版本与能力。
  3. 发送指令:发送tools/listtools/callresources/read等JSON-RPC消息。

该场景下,你需要自己编写MCP Client代码来处理初始化链接、维护协议和连接、发送消息以及处理响应。

一次MCP调用示例

看完流程,可能有人疑惑:LLM在整个过程中到底扮演什么角色?其实前面已说明——AI应用通过MCP Client调用Server,LLM只负责推理输入和输出。下面用完整调用链演示,一看便知。

先明确各角色职责:

  • 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_id=101的订单。”
  • 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_id=101" } }
  • 执行(真正的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 server

通过上述解析,调用过程已清晰。接下来按场景逐步拆解MCP Client配置问题。

前面提到,在Claude Code这类现成AI应用里,只需配置MCP Server,无需编写MCP Client代码。下面以Claude Code为例,具体演示配置方法。

配置信息写在claude_desktop_config.json文件中:

// ~/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(如weathergithub)是该Server的唯一标识符,用于AI界面显示与内部隔离。

2. command(可执行文件)
Client尝试启动的二进制文件或脚本解释器,指定入口程序。常见值包括npx(Node.js)、pythonuv(Python包管理器),或编译好的Go/Java二进制文件。

3. args(启动参数)
字符串数组,追加在command后,形成完整shell启动命令。

  • weather示例uv --directory /path/to/weather run weather-server,告诉uv切换到特定目录并运行项目。
  • filesystem示例npx -y @modelcontextprotocol/server-filesystem /Users/username/Documents-y自动确认安装,最后一个参数是传给Server程序内部的参数,指明允许访问的文件夹——这是一种白名单机制。

4. env(环境变量)
子进程启动时注入的环境变量,用于传递敏感信息(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 SDK由Google和Go官方维护,Java SDK由Spring AI官方维护,Python SDK由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("A vailable 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("A vailable resources:", resources) # 读取资源 config = await session.read_resource("weather://config") print("Config:", config) if __name__ == "__main__": import asyncio asyncio.run(main())

总结

本篇解答了MCP Client的核心问题:Client如何调用Server?不同场景下如何配置或编写客户端代码?结合系列前文,大家对MCP的整体理解已比较完整。下一篇将深入MCP高级特性及需要特别注意的细节——这些点在实际落地中尤为关键。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策