首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >MCP协议:如何构建大模型访问REST服务的统一通道

MCP协议:如何构建大模型访问REST服务的统一通道

作者头像
陶辉
发布2026-08-13 09:06:19
发布2026-08-13 09:06:19
1170
举报
文章被收录于专栏:陶辉笔记陶辉笔记

本文对应同名视频,建议配合视频观看效果更佳。视频从真实抓包出发,完整演示了握手、工具调用与 Swagger 自动映射三大核心流程。

就在 2026 年 7 月 28 号,MCP 发布了协议诞生以来最大的一次修订——握手机制和 Mcp-Session-Id 被正式砍掉,官方原话是 largest revision of the protocol since launch

但讽刺的是,Anthropic 今年 6 月才刚公布,MCP 的安装量已经 9700 万。这么大的存量,现网里绝大多数还跑着旧版机制。

有一份第三方基准测试的数字:让大模型直接照着 API 文档自己拼接调用后端接口,复杂任务成功率只有 92.31% ;换成 MCP 协议做中间层之后,成功率到 100% ,调用次数和耗时都少了近 20%。

今天从真实抓包出发,把这套刚被官方判”过时”、但现网还在大规模跑的 MCP 机制,拆给你看。

视频讲解

为什么需要 MCP

大模型调用外部接口,本来只有两条路,都不太舒服。

第一条路:让大模型直接读 API 文档、自己拼请求。但它本质上是个基于概率的文本预测引擎,没有严谨契约约束的时候,参数拼错、长上下文注意力分散引发的幻觉,出错率很难压下去——92.31% 的成功率就是这条路的现实写照。

第二条路:退回到各厂商私有的 Function Calling 格式——准是准了,但每换一种大模型,网关就得重写一遍适配层,陷入生态孤岛。

MCP 协议做的事,是在这两条路之间架一层标准化的桥——大模型只需要认一套协议,剩下的翻译和代理工作,交给网关。


握手:大模型和网关怎么”认识”彼此

JSON-RPC 2.0:MCP 的底层语言

MCP 协议底层就是 JSON-RPC 2.0——一种”动作导向”的轻量级协议,不像 REST 那样纠结 HTTP 动词和路由设计,所有交互都浓缩进一个 JSON 对象,认准四个字段就够:

字段

含义

jsonrpc

固定值 "2.0",标明协议版本

method

要执行什么动作,如 initialize、tools/call

params

传递给 method 的参数

id

请求唯一标识,用于异步场景下配对请求与响应

为什么 id 字段必须有

id 这个字段的设计不是偶然的。MCP 底层走的是 SSE 长连接,彻底打破了 HTTP 那种按顺序一问一答的模式——大模型可以连续无阻塞地发出请求1、请求2,但网关处理不同后端接口的耗时不一样,完全可能先推回响应2、再推响应1。客户端就是靠这个 id 字段,在乱序的异步流里把请求和响应精准对上号。

握手流程:initialize → Session-Id → initialized

第一步,大模型客户端发一个 initialize 请求:

代码语言:javascript
复制
curl -i -X POST http://10.1.9.21:11999/ \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{...},"id":1}'

网关返回响应,头部会带一个 Mcp-Session-Id,后面所有请求都要带着这个凭证:

代码语言:javascript
复制
Mcp-Session-Id: ajnoOA90SgAAAAAA

响应包体里还有个 capabilities 字段,宣告网关支持哪些能力:

代码语言:javascript
复制
{
  "capabilities": {
    "tools": {},
    "resources": {},
    "prompts": {}
  }
}

握手拿到 Session-Id 后,这个会话其实只是”半激活“状态——只有等大模型发完 notifications/initialized 这条确认通知,会话才正式生效,在这之前 tools 类的业务请求会被网关直接拒绝。之后如果长时间没有请求,网关也会按超时时间把会话淘汰掉,回收资源。

版本号为什么用日期

MCP 协议的版本号不是常见的 x.y.z,而是用日期,比如 2024-11-052025-03-26。设计本意是协议两端能快速、去中心化地演进,用日期做时间线交集比对,省得在次要版本号定义权上扯皮。

但现实是:从 2024 年 11 月发布到现在,一年多总共才出了 5 个正式版本,节奏并不算快。所以现网里大量中间件和网关,包括本文抓包用的矩尺 AI 网关,停留在更早的版本上——这也是为什么理解握手这套”旧”机制,现在依然有实际价值。


工具调用:一句 JSON 是怎么变成 REST 请求的

握手完成后,进入工具调用流程,这才是 MCP 协议的核心价值所在。

第一步:tools/list 发现工具

大模型先要知道网关背后挂了哪些工具,发起 tools/list 查询:

代码语言:javascript
复制
{"jsonrpc":"2.0","method":"tools/list","id":2}

如果后端接口太多,网关会分页返回,避免一次性把大模型的上下文撑爆:

代码语言:javascript
复制
{
  "tools": [...],
  "nextCursor": "page2_token"
}

第二步:tools/call 发起调用

假设列表里有个叫 list_vs 的工具,能查虚拟服务信息。大模型基于用户的自然语言意图,推理出要调用这个工具,传入参数 name: mcp

代码语言:javascript
复制
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "list_vs",
    "arguments": {
      "name": "mcp"
    }
  },
  "id": 3
}

第三步:网关翻译成 REST 请求

这条 JSON-RPC 请求到了网关这里,会被翻译成一个真正的 REST 请求——网关把 arguments 里的参数提取出来,重组成 URL 查询参数:

代码语言:javascript
复制
GET /slb/virtual_service/?name=mcp HTTP/1.1

后端服务处理完,返回标准的 200 和 JSON 结果,网关再把它包装回 JSON-RPC 的 result 字段,通过同一个会话推回给大模型。

一句自然语言,就这样变成了一次精确的 REST 调用,再原路带着结果回来。


谁来维护工具清单:Swagger → MCP 的自动转换

后端接口天天在变,如果这份工具列表要靠人工维护,运维成本高,还容易滞后出错——接口一改参数,大模型感知不到,调用就会出错。

网关的做法是直接读后端现成的 Swagger 文档,自动生成映射

tools/list 的数据结构

工具列表返回的结构很规整——一个 tools 数组,加一个分页用的 nextCursor。每个工具描述包含以下字段:

字段

用途

name

工具名,供大模型调用时引用

description / title

给大模型读的提示词,说明这个工具做什么

inputSchema

遵循 JSON Schema 规范,定义工具能接受什么参数

outputSchema

定义工具返回哪些字段,方便大模型预判后续处理

Swagger parameters → inputSchema

inputSchema 的源头是 Swagger 文档里的 parameters 数组。比如 list_vs 工具,在 Swagger 里对应的定义是:GET 方法、/slb/virtual_service/ 路径,参数里声明了一个叫 name 的查询参数。

网关要做的,是把这种扁平的参数列表,重新组装成 JSON Schema 要求的带 properties 的树状结构,同时把参数类型也对齐转换过去:

代码语言:javascript
复制
// Swagger parameters(扁平)
[{"name": "name", "in": "query", "type": "string"}]

// inputSchema(树状 JSON Schema)
{
  "type": "object",
  "properties": {
    "name": {"type": "string"}
  }
}

命名细节:中划线 → 下划线

顺带提一句命名细节——Swagger 里 operationIdlist-vs,带中划线;网关会把它转成 list_vs,下划线,这是照顾大模型的命名偏好做的转换。

Swagger responses → outputSchema

Swagger 用 responses 字段,按不同 HTTP 状态码分别声明返回格式;网关会取出 200 成功状态码对应的结构,逆向重组成 outputSchema,让大模型不只知道怎么调用,还能提前预判返回结果里有哪些字段,方便规划后续处理逻辑。

$ref 展开:防止大模型推理幻觉

复杂后端服务里,很多参数和返回结构会被多个接口反复复用,统一定义在 Swagger 的 definitions 里,用 $ref 指针互相引用,有的结构内部还嵌套引用着另一个结构。

为了不让大模型在理解深层嵌套关系时产生推理幻觉,网关通常要把这些分散的引用,在转换时完全展开铺平,直接写进最终的工具描述里。

这也导致了一个直观的现象——网关转换后生成的工具列表,体积往往比原始的 Swagger 文档大得多,具体膨胀多少,取决于网关配置的引用展开层数。


总结

回到开头那组数字——92.31% 到 100%,靠的就是这一整条链路:

代码语言:javascript
复制
握手建立信任
  → Mcp-Session-Id 追踪身份
    → JSON-RPC ↔ REST 互相翻译
      → Swagger 自动维护契约,无需人工同步

这也是这一年 Agent 能大规模接入真实业务系统的底层原因之一。

就在 9 天前,2026 年 7 月 28 号,MCP 发布了协议诞生以来最大的一次修订——握手和 Session-Id 被正式砍掉,改成了无状态架构。讽刺的是,这才是”用日期做版本号是为了快速迭代”这句话,第一次真正兑现。

MCP 协议里的另外两大能力——resources 资源读取、prompts 提示词模板,这次没展开讲,下期接着聊。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-08-12,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 视频讲解
  • 为什么需要 MCP
  • 握手:大模型和网关怎么”认识”彼此
    • JSON-RPC 2.0:MCP 的底层语言
    • 为什么 id 字段必须有
    • 握手流程:initialize → Session-Id → initialized
    • 版本号为什么用日期
  • 工具调用:一句 JSON 是怎么变成 REST 请求的
    • 第一步:tools/list 发现工具
    • 第二步:tools/call 发起调用
    • 第三步:网关翻译成 REST 请求
  • 谁来维护工具清单:Swagger → MCP 的自动转换
    • tools/list 的数据结构
    • Swagger parameters → inputSchema
    • 命名细节:中划线 → 下划线
    • Swagger responses → outputSchema
    • $ref 展开:防止大模型推理幻觉
  • 总结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档