MCP协议:智能体的标准化工具接口
1. 引言:MCP解决了什么问题
在前面几章中,我们反复使用了一个关键能力——Function Calling(函数调用)。无论是查数据库、调API,还是操作文件系统,智能体都需要通过"函数"这一抽象来触达外部世界。然而,当工具数量膨胀、应用场景复杂化时,一个令人头疼的问题浮现出来:
工具集成碎片化(Tool Integration Fragmentation)。
具体表现为:
- 协议不统一:每家大模型厂商都定义了自己的Function Calling格式。OpenAI、Anthropic、Google、阿里通义各有各的工具描述规范,同一份工具定义要写好几遍。
- 上下文割裂:工具本身没有"资源"概念。Agent要读取一份文件、一段数据库Schema,都得靠开发者手动拼接到Prompt里,缺乏统一的资源访问接口。
- 生态重复造轮子:搜数据库、查天气、读GitHub,每个Agent项目都在重复封装相同的工具。A项目写的工具,B项目无法直接复用。
- 运维耦合:工具进程和Agent进程常常绑死在一起,工具升级、权限管理、多工具编排都很难解耦。
这就好比每个Agent都自带一个"私有的工具箱",彼此不通,每次都要从零打造。2024年11月,Anthropic发布了Model Context Protocol(MCP,模型上下文协议),给出了一个令人眼前一亮的解法:
把工具、资源、提示模板从Agent中解耦出来,变成可独立部署、可被任意支持MCP的客户端发现的"Server",Agent则作为"Client"按需连接,即插即用。
用一个生活比喻来理解:MCP之于AI工具生态,就像USB-C接口之于数码设备。在USB-C统一之前,键盘是PS/2口、打印机是并口、老手机是Micro-USB、相机是Mini-USB,出门得带一整包转接头;USB-C一统天下后,一根线就能给笔记本、手机、平板充电传数据,即插即用、正反都能插。MCP正是希望成为"AI Agent的USB-C接口"——你写一个MCP工具,任何支持MCP的Agent都能直接用,不用改一行代码。
💡 小贴士:什么是MCP? MCP(Model Context Protocol,模型上下文协议)是Anthropic开源的一套通信标准,规定了"AI模型如何发现并调用外部工具"的统一格式。它不绑定任何一家模型厂商,谁都可以免费使用。你可以把它理解成"工具界的HTTP"——HTTP统一了网页传输,MCP统一了AI调工具。
本章将从协议原理讲到Server/Client开发,最后用一个天气查询Agent串起完整链路。
2. MCP协议概述
2.1 协议的诞生与定位
MCP(Model Context Protocol)由Anthropic于2024年11月开源发布,是一个开放、基于JSON-RPC 2.0的应用层协议。其设计目标有四:
- 标准化:任何MCP Server都能被任何兼容MCP的Host(如Claude Desktop、Cursor、各类Agent框架)发现并调用。
- 解耦:Server与Client通过协议而非代码耦合,可独立部署、独立升级。
- 可组合:一个Host可同时连接多个Server,工具数量线性扩展。
- 安全:Server运行在本地或受控环境,Host控制权限边界。
💡 小贴士:什么是JSON-RPC 2.0? JSON-RPC是一种用JSON格式进行"远程过程调用"的轻量协议。简单说,就是"我用JSON给你发一条消息,告诉你调用哪个方法、传什么参数,你也用JSON回我结果"。2.0版本规定了
jsonrpc、id、method、params这几个字段。MCP所有通信都套这个格式,所以任何语言都能轻松实现。
2.2 三大组件:Host / Client / Server
MCP架构由三个核心角色构成。再用USB-C的比喻串一下:
- Host(宿主应用):最终用户使用的应用,比如Claude Desktop、Cursor IDE,或我们自己开发的Agent程序。Host就像你的笔记本电脑——它有多个USB-C口,负责管理外设、汇总能力、向用户暴露交互入口。
- Client(协议客户端):Host内部的一个连接器,每个Client与一个Server保持1:1的会话。Client就像笔记本里那个"USB-C控制器芯片",负责协议握手、能力协商、消息路由。
- Server(服务提供方):独立运行的进程,向Client暴露三类能力:Tools(工具)、Resources(资源)、Prompts(提示模板)。Server就像你插上的U盘、键盘、显示器——各自提供不同功能。
它们的关系如下:
|
|
💡 小贴士:Server和Client到底谁是谁? 记住一条线:提供能力的是Server,使用能力的是Client。文件系统Server提供"读文件"能力,Agent端的Client来调用它。Host里可以同时挂很多个Client,每个Client连一个Server,于是Agent就能用上所有Server的工具。
2.3 与传统Function Calling的区别
| 维度 | Function Calling | MCP |
|---|---|---|
| 工具定义位置 | 写死在Agent代码或Prompt中 | 独立Server,运行时动态发现 |
| 复用性 | 每个项目重写 | 一次开发,多方复用 |
| 上下文资源 | 无统一抽象,手动拼接 | 内置Resources概念,按URI访问 |
| 提示模板 | 无 | 内置Prompts,可被Host列出并调用 |
| 多模型兼容 | 各厂商格式不同 | 协议中立,与具体模型解耦 |
| 部署形态 | 与Agent同进程 | 可独立进程,本地或远程 |
一个直观的差异:在Function Calling模式下,你换一个模型厂商,工具描述格式可能就要改一遍;而在MCP下,Server完全不用动,Host换底层模型即可。这就像USB-C口不变,你换什么牌子的电脑都能用同一个U盘。
2.4 2026年生态状态
截至2026年中,MCP已被主流Agent框架广泛采纳:
- 官方/社区MCP Server数量已突破5000+,覆盖文件系统、Git、数据库(PostgreSQL/MySQL/SQLite)、Slack、GitHub、Notion、Linear、Sentry、Brave Search、Puppeteer等场景。
- 主流Host支持:Claude Desktop、Cursor、Windsurf、Zed、Cline等均原生支持MCP;LangChain、LlamaIndex、AutoGen也提供了MCP适配层。
- 多语言SDK:官方提供了TypeScript、Python SDK,社区贡献了Go、Rust、Java、C#等实现。
- 远程MCP:基于HTTP+SSE的远程Server部署模式逐渐成熟,出现了MCP Gateway、MCP Hub等托管平台。
可以说,MCP已经从"Anthropic的提案"成长为事实标准。
3. MCP架构详解
3.1 Host:宿主应用
Host是用户视角的"Agent应用"。它的职责:
- 创建并管理多个Client实例(一个Server对应一个Client)。
- 汇总所有Server暴露的Tools/Resources/Prompts,统一呈现给LLM或用户。
- 在LLM决定调用某个工具时,路由请求到对应Client,再把结果回传给LLM。
- 控制权限边界:是否允许某个Server读取某资源、是否允许某工具执行,由Host把关。
Claude Desktop就是典型Host:用户可以在配置文件中声明若干MCP Server,应用启动时拉起这些Server进程,并把工具接入对话。
3.2 Client:协议客户端
Client是Host内部维护的"会话管理器"。每个Client对应一个Server,负责:
- 初始化握手:发送
initialize请求,交换协议版本与能力声明。 - 能力协商:Server声明自己支持哪些Tools/Resources/Prompts,Client声明自己支持哪些回调(如采样
sampling、根目录roots)。 - 消息收发:所有调用基于JSON-RPC 2.0,Client既是请求方,也接收Server发起的通知与反向请求。
- 生命周期管理:维持会话、处理断连、优雅关闭。
3.3 Server:服务提供方
Server是能力提供者,可暴露三类原语(primitive):
| 原语 | 语义 | 谁主导 | 典型例子 |
|---|---|---|---|
| Tools | 可执行的函数,有副作用 | LLM主动调用 | 发邮件、查数据库、运行Shell |
| Resources | 可读取的数据,无副作用 | 应用/用户主动拉取 | 文件内容、DB Schema、日志 |
| Prompts | 预制的提示模板 | 用户主动选择 | “代码审查"模板、“周报"模板 |
注意三者的控制权差异:Tools是模型自主决定调用;Resources和Prompts更多是应用层主动获取后注入上下文。这种分工避免了LLM滥用只读资源,也让权限管理更清晰。
💡 小贴士:为什么要分Tools和Resources? Tools会"动手”(可能发邮件、删文件),必须由LLM慎重决策后调用;Resources只"读不动”(看一份文档、查一段Schema),由应用层按需取用即可。把"读"和"做"分开,权限审批就能区别对待——读操作可以放行,写操作必须人工确认。
3.4 通信协议:JSON-RPC over stdio/SSE
MCP传输层支持两种主流模式:
- stdio(标准输入输出):本地进程间通信。Host以子进程方式拉起Server,通过stdin/stdout交换JSON-RPC消息。延迟低、部署简单,是本地集成的主流方式。
- HTTP + SSE(Server-Sent Events):远程通信。Server作为HTTP服务暴露,Client通过POST发请求、SSE接收推送。适合跨机器、云托管场景。新版本也支持Streamable HTTP,简化了SSE的双向通道。
💡 小贴士:stdio和SSE各是啥?
- stdio 就是程序的标准输入输出流。你在终端敲
python xxx.py,键盘输入走stdin,屏幕打印走stdout。MCP本地模式下,Host和Server就是靠这两个流互发JSON消息,省去了开网络端口的麻烦。- SSE(Server-Sent Events) 是一种服务器单向推消息给浏览器的HTTP技术。MCP远程模式下,Client发请求用普通POST,Server推结果用SSE,省去轮询。
消息格式示例(Client调用工具):
|
|
Server响应:
|
|
可以看到,每条消息都有一个id用于配对请求与响应,method指明调用哪个方法,params携带参数。这就是JSON-RPC的全部精髓。
3.5 生命周期:初始化→能力交换→工具调用→关闭
一次完整的Client-Server会话:
- Initialize:Client发送
initialize,携带本端支持的协议版本和能力。Server回应当前版本及自身能力。 - Initialized 通知:Client发送
notifications/initialized,握手完成。 - 能力列举:Client调用
tools/list、resources/list、prompts/list获取清单。 - 运行期调用:Client按需调用
tools/call、resources/read、prompts/get;Server也可反向发起sampling/createMessage让Host代为调用LLM。 - 关闭:Client发送关闭信号或直接结束stdio通道,Server清理资源退出。
理解这一生命周期对调试MCP连接问题非常重要——多数"工具不出现"的故障都源于握手或能力交换阶段出错。
4. 开发MCP Server
4.1 安装Python SDK
|
|
mcp是官方维护的Python SDK,同时支持stdio与SSE两种传输方式。它提供两层API:
- 高层FastMCP:声明式,用类型注解和装饰器自动生成Schema,代码极简,推荐日常使用。
- 低层Server:手动实现每个JSON-RPC方法的handler,控制力强,适合需要精细定制的场景。
💡 小贴士:本节用哪层API? 本章代码采用高层FastMCP。它会把你的函数签名自动转成
tools/list、tools/call这些JSON-RPC消息,底层细节全被封装。理解原理看第3节,动手写代码看FastMCP即可。
下面我们用它开发一个文件系统MCP Server,暴露读取文件、列出目录两个工具,并演示Resources和Prompts。
4.2 三类原语速览
在写代码前,先记住三类原语的FastMCP写法:
- Tool(工具):用
@mcp.tool()装饰一个函数,函数名即工具名,类型注解自动生成参数Schema,docstring自动变成给LLM看的描述。 - Resource(资源):用
@mcp.resource("uri模板")装饰一个函数,按URI暴露只读数据。 - Prompt(提示模板):用
@mcp.prompt()装饰一个函数,返回一段预制提示词。
4.3 完整示例:文件系统MCP Server
下面是完整可运行的Server代码。注意看注释——它解释了每一块对应MCP的哪个概念:
|
|
几个值得注意的细节:
- 类型注解即Schema:
path: str会被FastMCP自动转成{"type": "string"}的JSON Schema,再也不用手写inputSchema字典了。 - docstring即描述:函数下方的三引号文档字符串,会原样成为工具的
description,直接给LLM看。所以写好docstring等于写好工具说明书。 - 错误处理风格:MCP推荐"返回文本错误"而非抛异常,这样LLM能看到错误描述并自行决定是否重试或换工具。
- Resource的URI:必须符合
协议://路径形式,file://是最常用的,也可以自定义如db://users/42。 mcp.run()默认stdio:本地集成时Host以子进程拉起本脚本,通过stdin/stdout收发消息,无需开端口。
💡 小贴士:FastMCP背后发生了什么? 当Client发来
tools/list时,FastMCP会扫描所有@mcp.tool()装饰的函数,自动生成工具清单返回;当Client发来tools/call并指定name="read_file",FastMCP会调用对应函数、把返回值包成TextContent回传。你写的只是普通Python函数,协议细节全自动。
5. 开发MCP Client
5.1 Client的职责
一个完整的MCP Client需要做四件事:
- 连接:通过stdio或SSE与Server建立会话。
- 初始化:发送
initialize、接收能力声明、发送initialized通知。 - 发现:调用
tools/list等列举能力。 - 调用:按需调用
tools/call,解析返回的content数组。
5.2 完整示例:MCP Client集成到Agent
下面这段代码启动上一节的文件系统Server,并把它的工具接入一个简易Agent循环。代码分六步,每步都有注释说明在做什么:
|
|
注意我们做了协议桥接:MCP工具的inputSchema正好就是OpenAI Function Calling所需的JSON Schema,所以转换几乎零成本——直接把t.inputSchema塞进parameters字段即可。这也是MCP设计中"协议中立"红利的体现:你可以用任意LLM厂商的API,工具层完全复用。
💡 小贴士:为什么说MCP是"协议中立"的? MCP Server只懂JSON-RPC,根本不知道调用它的是GPT、Claude还是通义。Client这边把MCP工具格式转成各家API需要的格式(OpenAI用
function字段、Anthropic用tools字段),转换层很薄。换模型只动Client,Server一行不改。
6. MCP实战:构建天气查询Agent
理论清楚了,下面用一个更贴近真实场景的例子把全流程串起来。我们将:
- 开发一个天气MCP Server,封装开放天气API。
- 用MCP Client把它接入Agent,让用户用自然语言问天气。
6.1 天气MCP Server
这个Server只暴露一个get_weather工具,背后调用免费的wttr.in服务(无需API Key,便于演示)。同样用FastMCP,几十行搞定:
|
|
💡 小贴士:为什么用
httpx.AsyncClient而不是requests? MCP的Python SDK基于asyncio异步框架。如果工具内部用同步的requests发请求,会阻塞整个事件循环,导致Server卡住无法响应其他调用。httpx的异步客户端与asyncio天然兼容,不会阻塞。同理,访问数据库应该用aiosqlite、asyncpg等异步驱动。
6.2 Agent通过MCP调用天气工具
我们复用上一节的Client骨架,只换Server脚本与System Prompt。注意StdioServerParameters的args改成了weather_mcp_server.py:
|
|
运行效果(示意):
|
|
可以看到,LLM自主决定调用两次工具(一次问北京、一次问上海),再把结果综合成自然语言回答。整个过程Server完全不知道用的是哪个模型,模型也不关心Server用什么语言写——这就是MCP带来的解耦价值,也是它"USB-C即插即用"的真正含义。
7. MCP最佳实践
7.1 Server设计原则
- 工具粒度适中:太细(每个SQL一个工具)会让LLM选择困难;太粗(一个"do_anything"工具)又失去可组合性。建议按"一个完整用户意图"为粒度。
- 描述写给LLM看:docstring不仅是文档,更是模型决策依据。写清楚"何时用、不用、输入输出含义",比堆砌功能列表更有效。
- Schema严格:尽量用具体的类型注解(
int而非str装数字),必要时配合Literal、枚举约束取值,能显著降低模型传错参数的概率。 - 幂等优先:读类工具尽量幂等;写类工具应在描述中明确副作用,便于Host做权限审批。
7.2 安全与权限
- 最小权限:Server只暴露必要能力。文件系统Server应限制在指定根目录,避免暴露
/etc/passwd。 - 路径校验:对路径参数做规范化与越权检查,防止
../穿越。 - Host审批:生产环境Host应实现"工具调用确认"机制,敏感操作需用户点击确认后再下发。
- 远程Server鉴权:基于HTTP的远程MCP应使用Token、mTLS等手段鉴权,避免裸暴露。
- 审计日志:记录每一次
tools/call的入参出参,便于事后追溯。
7.3 错误处理
- 返回而非抛出:工具失败时返回文本描述错误,让LLM有机会重试或换策略;只在协议层错误(如序列化失败)才抛异常。
- 结构化错误码:可在文本中嵌入
[ERR_TYPE]前缀,便于Host做策略化处理(如配额耗尽自动切换Server)。 - 超时与重试:网络类工具设置合理超时;Client层可对瞬时错误做有限次重试。
7.4 性能优化
- 异步IO:Python SDK基于asyncio,工具内部应使用
httpx、aiosqlite等异步库,避免阻塞事件循环。 - 批量接口:若工具常被连续调用多次(如批量查天气),可设计
get_weather_batch减少往返。 - 缓存:对慢且少变的资源(如DB Schema)在Server端缓存,减少
resources/read延迟。 - 连接复用:远程MCP Client应复用HTTP连接,避免每次调用都重建TLS。
- 冷启动:stdio模式下Server是子进程,启动慢会拖慢Host首屏;可在Server启动时预加载模型/连接池。
8. 小结
本章我们从"工具集成碎片化"这一痛点出发,完整走过了MCP协议的理论与实践:
- MCP是什么:Anthropic提出的开放协议,用Host/Client/Server三段式架构,把工具、资源、提示模板从Agent中解耦。
- 为什么重要:它让工具像USB-C外设一样即插即用,2026年已有5000+ Server、主流框架原生支持,正在成为AI工具生态的事实标准。
- 怎么开发:用Python
mcpSDK的FastMCP高层API,函数加个@mcp.tool()装饰器、配好类型注解和docstring,就是一个完整工具;Client侧通过stdio连接,几行代码就能把工具接入任意LLM的Function Calling循环。 - 怎么用对:注意工具粒度、Schema严格性、安全权限与异步性能,才能让MCP真正成为"可生产"的集成层。
一句话总结:MCP把"Agent怎么用工具"这件事从代码层升级到了协议层。掌握MCP,你写的工具就不再属于某一个项目,而属于整个生态。
9. 预告:第11章 评估与可观测性
当Agent接入了越来越多的工具(无论通过Function Calling还是MCP),一个新的问题随之浮现——怎么知道它干得好不好? 一个跑偏的工具调用、一次幻觉的回答、一段静默失败的任务,都可能让整个Agent失去可信度。
第11章我们将聚焦评估与可观测性:
- 评估(Evaluation):如何用基准任务集、LLM-as-a-Judge、人工评分等手段量化Agent能力,避免"看着像对的"幻觉。
- 可观测性(Observability):如何用Trace、Span、指标体系把Agent的一次完整运行"切片"展现,定位到底是Prompt、工具还是模型的问题。
- 工具链:介绍LangSmith、Langfuse、Phoenix、OpenTelemetry等在Agent场景的应用。
从"能跑"到"可信",评估与可观测性是Agent走向生产不可绕过的一关。我们下一章见。