跳转到内容

第 43 章 MCP:互操作的稳定概念与版本边界

43.1 查询已经能用了,每个应用还要重写适配器吗?

Section titled “43.1 查询已经能用了,每个应用还要重写适配器吗?”

一个助手调用 get_order(order_id),另一个要求 URL 和 JSON 消息体,第三个则要先取得可用操作清单。如果应用与服务都各自规定描述和通信格式,三个应用接四个服务,最多可能需要 3×4=123\times4=12 份逐对适配。

统一接口后,可以让每个应用实现兼容客户端,每个服务提供兼容服务端。在这个理想化例子中,边界数量变为三加四,共七个。这是作者给定的接口数量对比,不是开发工时测量;不同的身份认证规则和业务含义仍然要处理。

模型上下文协议(Model Context Protocol,MCP)针对的就是互操作问题:约定应用怎样与服务器交换能力信息、请求和结果。它既不是语言模型,也不是读取订单的函数,还不会替用户决定下一步该做什么。

43.2 找到宿主、客户端和服务器的位置

Section titled “43.2 找到宿主、客户端和服务器的位置”

例 43.1:给现有执行器接一层接口。 知识助手应用是宿主(host),负责用户交互、模型接入和权限规则。宿主内部的 MCP 客户端(client)负责与服务器说同一种协议。MCP 服务器(server)对外提供订单工具,把实际读取交给第 42 章的执行器。“服务器”指接口角色,进程完全可以就在本机。

请求路径
  1. 模型之外宿主:权限规则
  2. 文本片段客户端:协议请求
  3. 处理步骤服务器:解码与分发
  4. 模型之外同一个读取执行器

协议兼容不会增加取消操作。

返回路径
  1. 模型之外记录或 forbidden
  2. 文本片段对应请求的协议结果
  3. 处理步骤宿主校验并装配

完成的协议结果可以携带业务失败。

图 43.1:统一协议仍保留业务权限边界。 原创教学图示 · CC BY-SA 4.0

图 43.1 将协议处理与业务访问分开。应用中的用户是 mira,因为可信的样例配置这样规定。请求里自报的客户端名称只是诊断信息,不是身份证明。服务器自称“可信订单服务”,也不会因此获得读取他人订单的权限。

表 43.1:三类可以对外提供的信息。

概念在本项目中可以对应什么收到它不等于什么
Tool,工具带参数 Schema 的订单查询操作获得权限,或证明已经执行
Resource,资源带 URI 和内容、可以定位的制度文本自动选出最佳段落,或自动进入模型输入
Prompt,提示模板可以填参数、重复使用的消息模板因为来自服务器就成为高优先级可信指令

这三类分别面向操作、资料和模板。服务器不必全部实现,本书最小服务器只提供工具。第 40 章的模板可以通过 Prompt 分发,第 45 章的文档可以作为 Resource 提供,但这些都属于额外实现,不能说当前适配器已经具备。发现能力让宿主知道服务器提供什么,宿主仍须决定哪些能力可以展示和使用。

传输(transport)负责运送消息。本地实践使用标准输入输出,即 stdio:宿主启动子进程,每行写入一条 JSON-RPC 消息,再读取回复。JSON-RPC 通过请求 ID 把响应与请求对应起来。诊断日志应写入标准错误,不能混入协议消息流。

远程部署可以使用协议规定的 HTTP 传输。HTTP Primer已经解释底层请求、响应和流式传输。身份认证确认凭证对应谁,授权决定可以操作什么、读取哪些记录。HTTP 授权框架处理通信边界上的权限,具体订单归属仍由应用或服务核对。本地 stdio 样例不实现远程 OAuth,也不声称验证了真实身份。

协议成功和工具成功也要区分。服务器可以完全理解请求,却报告用户无权访问。反过来,协议错误可能让请求根本到不了工具。即便工具成功返回,结果也只是交给宿主的数据;宿主要校验它,并按第 40 章的信任规则决定如何放进上下文。

本节和 docs/part-vii-online.md 固定采用正式规范 2026-07-28,核验日期为 2026-09-14。这些是有版本的实现事实,不是 MCP 永久不变的定义。当前基础协议要求每个请求携带版本和客户端能力,不再要求旧的初始化握手。客户端先查询服务器信息,再列出和调用工具,便于观察;在此版本中,客户端可以不先发现,服务器则必须实现发现能力。

例 43.2:一组完整的协议消息。 为便于阅读,下面展开了空白,实际 stdio 消息各占一行。ID 3 把本次响应与请求对应起来,不代表订单 A-104,也不是批准编号。空的能力对象表示没有声明可选客户端能力。

{
"jsonrpc":"2.0",
"id":3,
"method":"tools/call",
"params":{
"name":"get_order",
"arguments":{"order_id":"A-104"},
"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{},
"io.modelcontextprotocol/clientInfo":{"name":"book-host","version":"1.0.0"}
}
}
}
{
"jsonrpc":"2.0",
"id":3,
"result":{
"resultType":"complete",
"_meta":{"io.modelcontextprotocol/serverInfo":{"name":"book-orders","version":"1.0.0"}},
"content":[{"type":"text","text":"{\"order_id\":\"A-104\",\"status\":\"processing\",\"as_of\":\"2026-09-14T00:00:00Z\",\"source_version\":\"ka3-orders-v1\"}"}],
"structuredContent":{"order_id":"A-104","status":"processing","as_of":"2026-09-14T00:00:00Z","source_version":"ka3-orders-v1"},
"isError":false
}
}

结构化内容由服务器代码产生,不是 LLM 在 Schema 约束下生成的结果。文本块把同一个对象序列化,供使用文本内容的接收方读取。宿主要检查两份表示是否一致、响应是否对应原请求,以及业务字段是否符合约定,不能只看工具名称熟悉就接受。

表 43.2:实际子进程通信的结果。

请求 ID请求响应及解释
1发现服务器支持版本 2026-07-28,提供工具,名称 book-orders,程序版本 1.0.0
2列出工具只有 get_order;必填参数 order_id;带只读标注
3读取 A-104协议结果完成;返回处理中快照;工具未报错
4以 mira 身份读取 B-205协议结果完成,但携带 forbidden 工具错误
5提议 cancel_order参数错误,协议代码 -32602;没有这个工具

data/part-vii/mcp-run.json 保存真实子进程产生的全部请求和响应。宿主关闭输入后等待进程退出,实践设定五秒进程期限。这里没有使用 SDK,只声称完成了已测试的同步只读子集,不声称完整协议符合性,也没有实现订阅或远程部署。

43.5 版本边界让“兼容”成为可以核查的判断

Section titled “43.5 版本边界让“兼容”成为可以核查的判断”

旧教程可能从 initialize 和 initialized 开始,那属于更早的协议版本。固定版本的服务器会拒绝缺少必填请求元数据的消息,并按正式错误结构拒绝不支持的版本。若要支持旧客户端,需要单独实现、测试兼容路径;把旧握手无条件加到每次新通信前,并不是无害的修补。

官方弃用登记还区分了已弃用(deprecated)和已移除。本次固定版本中的 Roots、Sampling、Logging 和 Dynamic Client Registration 已被弃用,并规定了迁移方向与最早移除日期。因此,稳定正文不以这些机制作为核心定义。旧 HTTP+SSE 传输有独立的弃用历史,也不表示所有服务器发送事件都消失了。在线实现资料保留这些确切区别和范围。

无状态协议仍然可以访问有状态的订单数据库。这里“无状态”针对的是解释本次请求所需的协议信息,不是说订单永远不变,更不是说一条连接就等于用户的对话记忆。

43.6 KA-3:统一接口,不增加权限

Section titled “43.6 KA-3:统一接口,不增加权限”

mcp_readonly.py 包装的仍是 Tool 和 HTTP 样例共用的 execute、lookup。可以运行演示程序或 Notebook 对应单元格。测试核对发现结果、响应 ID、请求元数据、未知方法、错误参数、版本拒绝、订单归属拒绝,以及文本结果与结构化结果一致。快照保持不变。

MCP 不会自动增加检索排序、有据生成、多步规划或业务批准。它可以把检索器作为工具运送过来,但检索器仍然需要排序规则和评测集。因此,下一步要解决的是:在允许读取的制度文档中,哪些真的有助于回答当前问题?

MCP 让宿主通过客户端与服务器使用统一接口。工具、资源和提示模板提供不同东西,传输与授权解决不同问题。本地版本化适配器证明了一次只读通信,不代表拥有模型、RAG 系统或自主 Agent。兼容性必须对应经过核验的版本和测试范围。

  1. 请求自报客户端名称为 administrator,服务器是否应该让它读取 B-205?缺少什么证据?
  2. 宿主列出一个制度资源后,模型是否已经收到制度,最佳段落是否已经选好?还需要哪些工作?
  3. ID 4 返回完成状态,同时报告 forbidden 工具错误。这与 ID 5 的未知工具错误相同吗?分别在哪一层发生?
  4. 工程师说“MCP 无状态,所以不能支持变化中的订单状态”,错在哪里?另一人说“装好了 MCP,就有 RAG 了”,又错在哪里?
  1. 不应该。自报名称既不是身份认证,也不是归属证明。服务器需要可信用户身份及其读取目标记录的权限。本地样例的身份始终是 mira,不随客户端名称改变。
  2. 都不能据此判断。列出只说明资源存在,读取才能取得内容;检索器选择相关段落,宿主再把证据装进实际模型输入。这些都需要应用明确实现。
  3. 不同。ID 4 请求的是已知操作,但业务授权失败,协议把失败作为工具结果传回。ID 5 请求了没有提供的工具,停在协议和接口边界。两者都没有执行取消。
  4. 每次请求携带协议信息,只是不依赖此前的协议会话,应用记录仍然可以改变。同样,协议互操作不提供索引、排序、证据装配或回答支持检查,RAG 仍需要这些组件。