9.5.2 MCP 协议概述

- 理解为什么单独写工具接入代码很快会变乱
- 理解 MCP 想解决的核心问题
- 分清 client、server、tool、transport 的角色
- 看懂一个最小 MCP 风格消息示例
- 建立对 MCP 适用场景和边界的正确直觉
为什么会需要 MCP?
Section titled “为什么会需要 MCP?”先看“没有协议”时会发生什么
Section titled “先看“没有协议”时会发生什么”如果你给一个 Agent 系统接 3 个工具:
- 搜索
- 文件系统
- 数据库
最容易出现的情况是:
- 每个工具接口格式都不一样
- 每个工具的参数描述方式不一样
- 错误处理也各写各的
- 换个客户端就要重写适配层
一开始你可能觉得还能忍,但工具一多,系统很快会变成:
每加一个工具,就多一堆胶水代码。
协议的意义是什么?
Section titled “协议的意义是什么?”协议的意义不是“让名字更高级”,而是:
让不同系统能按一套共同规则交换信息。
你可以把它类比成:
- USB 之于外设
- HTTP 之于网页请求
- SQL 之于数据库查询
MCP 想做的,正是:
工具接入世界里的“统一插口”。
MCP 在回答什么问题?
Section titled “MCP 在回答什么问题?”可以先把它浓缩成三个问题:
- 客户端怎么知道服务器上有哪些工具?
- 客户端怎么用统一格式调用这些工具?
- 工具调用结果和上下文怎么返回?
也就是说,MCP 关心的不是某个具体工具,而是:
客户端和工具服务器之间怎样稳定沟通。
MCP 最核心的几个角色
Section titled “MCP 最核心的几个角色”客户端(Client)
Section titled “客户端(Client)”客户端是发起方。 它通常负责:
- 发现工具
- 选择工具
- 发起调用
- 接收结果
在实际系统里,客户端常常是:
- 一个 Agent 框架
- 一个聊天客户端
- 一个 IDE 插件
服务器(Server)
Section titled “服务器(Server)”服务器是能力提供方。 它通常负责:
- 暴露工具
- 接收调用请求
- 执行工具逻辑
- 返回结果
工具(Tool)
Section titled “工具(Tool)”工具是服务器暴露出来的具体能力,比如:
search_docsread_filerun_sql
传输层(Transport)
Section titled “传输层(Transport)”传输层决定客户端和服务器怎么把消息传来传去。 例如:
- 标准输入输出
- 本地进程通信
- 网络连接
一句话先记住:
client 决定要不要用工具,server 负责把工具提供出来。
先看一个最小 MCP 风格消息
Section titled “先看一个最小 MCP 风格消息”MCP 风格的交互通常会有很明确的结构。 这里先用一个简化版 JSON-RPC 风格消息帮助你建立直觉。
request = { "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}
response = { "jsonrpc": "2.0", "id": 1, "result": { "tools": [ {"name": "search_docs", "description": "检索课程文档"}, {"name": "get_weather", "description": "查询天气"} ] }}
print(request)print(response)预期输出:
{'jsonrpc': '2.0', 'id': 1, 'method': 'tools/list', 'params': {}}{'jsonrpc': '2.0', 'id': 1, 'result': {'tools': [{'name': 'search_docs', 'description': '检索课程文档'}, {'name': 'get_weather', 'description': '查询天气'}]}}这个例子最重要的不是字段名,而是结构感
Section titled “这个例子最重要的不是字段名,而是结构感”它在教你:
- 请求和响应是成对的
- 每条消息都有明确的方法名
- 结果字段不是随意文本,而是结构化数据
这就是协议带来的稳定性。
为什么“工具发现”是个大问题?
Section titled “为什么“工具发现”是个大问题?”如果没有协议,客户端通常得提前写死:
- 工具名
- 参数格式
- 返回格式
这会导致:
- 客户端和服务端强耦合
- 一换工具集就得改代码
而 MCP 的一个重要价值是:
先发现,再调用。
也就是说,客户端不用事先把所有工具细节都写死,它可以通过协议去问:
- 你有哪些工具?
- 每个工具怎么描述?
这让工具生态更灵活。
MCP 和 函数调用 有什么关系?
Section titled “MCP 和 函数调用 有什么关系?”这两个概念很容易混在一起。
函数调用 更像“模型层的结构化调用能力”
Section titled “函数调用 更像“模型层的结构化调用能力””它关注的是:
- 模型能不能产出一个结构化调用意图
例如:
{ "name": "search_docs", "arguments": {"query": "退款政策"}}MCP 更像“系统层的工具接入协议”
Section titled “MCP 更像“系统层的工具接入协议””它关注的是:
- client 和 server 怎么发现工具
- 怎么描述工具
- 怎么调用工具
- 怎么返回结果
所以更准确地说:
函数调用 解决“模型怎样发出结构化调用”,MCP 解决“系统怎样标准化接工具”。
它们可以一起用,但不等价。
MCP 适合什么场景?
Section titled “MCP 适合什么场景?”- 工具种类很多
- 客户端种类很多
- 希望工具接入方式统一
- 希望后续工具生态能扩展
例如:
- IDE 助手
- 桌面 Agent
- 企业内部工具平台
不一定非要上 MCP 的情况
Section titled “不一定非要上 MCP 的情况”如果你只是:
- 一个小脚本
- 两三个内置工具
- 没有多客户端接入需求
那直接写本地工具调用层也许已经够了。
所以不要把 MCP 理解成“必须上”的东西,而要理解成:
当工具生态和接入复杂度上来时,协议化会越来越值钱。
一个更接地气的类比:MCP 像“工具插排”
Section titled “一个更接地气的类比:MCP 像“工具插排””可以这样理解:
- tool 是一个个电器
- client 是来用这些电器的人
- MCP 像统一插排和接口标准
如果没有统一插排:
- 每个电器接口都不一样
- 每次接一个都要重新适配
有了统一插排以后:
- 新电器更容易接入
- 使用方不必每次重新学一套规则
这就是协议的工程价值。
初学者最常踩的坑
Section titled “初学者最常踩的坑”以为 MCP 是某个具体工具库
Section titled “以为 MCP 是某个具体工具库”不是。 它首先是协议和交互约定。
以为有了 MCP 就自动会用工具
Section titled “以为有了 MCP 就自动会用工具”不会。 协议解决的是接入层,调用策略、权限、评估仍然要你自己做。
把 MCP 和 函数调用 混成一个概念
Section titled “把 MCP 和 函数调用 混成一个概念”两者相关,但层次不同。
学完这一页,至少保留这张证据卡:
- 能力
- 服务器暴露的资源、Prompt 或工具
- 契约
- schema、传输、权限和错误形式
- 调用轨迹
- 发现、调用、响应和失败处理
- 失败检查
- 架构不兼容、缺少认证、不安全工具或服务器错误
- 集成动作
- 在加入自主能力前先验证服务端契约
这一节最重要的不是记住“协议”两个字,而是理解:
MCP 的核心价值,是把客户端和工具服务器之间的发现、描述、调用和结果交换变成更统一的系统契约。
只要这个直觉建立起来,后面你学架构、server、client 和生态时,就不会只觉得是在看一堆接口名。
- 用自己的话解释 client、server、tool、transport 分别在扮演什么角色。
- 想一想:为什么“工具发现”这件事本身就值得被协议化?
- 如果你的系统只有 2 个固定工具,为什么暂时不一定要上 MCP?
- 用自己的话说明:MCP 和 函数调用 的区别是什么?
解题思路与讲解
- 一个合理回答是:client 负责承接用户目标并决定何时调用能力;server 负责以契约形式暴露能力;tool 是某个可执行能力;transport 是承载发现、调用、响应的通信通道。
- “工具发现”值得协议化,是因为 client 在安全调用前必须知道有哪些能力、参数是否合法、错误长什么样、权限边界在哪里。
- 如果只有两个固定工具,手写接入可能更简单、更容易调试,也更少维护成本。只有当工具会变化、变多、来自不同团队,或需要复用发现与契约时,MCP 的收益才会明显。
- 函数调用通常是面向模型的结构化调用选择机制;MCP 是更大的 client-server 协议,负责发现和调用外部能力。二者可以配合,但所在层次不同。