news 2026/10/14 2:37:05

Higress REST-to-MCP 实战:一份声明式 YAML 把现成 REST API 变成 3 个 MCP 工具,全程零 Go 代码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Higress REST-to-MCP 实战:一份声明式 YAML 把现成 REST API 变成 3 个 MCP 工具,全程零 Go 代码

Higress REST-to-MCP 实战:一份声明式 YAML 把现成 REST API 变成 3 个 MCP 工具,全程零 Go 代码

【免费下载链接】higress🤖 AI Gateway | AI Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/hi/higress

想让大模型把你手里现成的 REST API 直接当 MCP 工具调用,又不想碰一行 Go 代码?在 Higress 里,REST-to-MCP就是干这个的:你只需要写一份 MCP Server 配置(mcp-server.yaml),声明好工具、参数和请求模板,网关负责把工具注册成 MCP、构造 HTTP 请求、渲染响应。本文拿阿里云云市场的"全国停车场数据实时查询"API 当案例——整个目录里没有一行 Go 源码,就靠一份 OpenAPI 规范和一份 YAML,变成了 3 个可被大模型调用的工具。读完这篇,你可以照同样的套路为任意 REST API 编写声明式 MCP 接入配置。

一、不想写代码接 REST API 当 MCP 工具,怎么办?

先把场景摆出来:你有一个已经能跑的 REST 服务(比如查停车场的接口),现在想把它暴露给 AI 应用。传统做法是在 Higress 的 MCP Server 框架里写 Go 代码、编译成 WASM,流程不短。

但 Higress 的 MCP Server 插件其实内置了一个"声明式模式":REST-to-MCP。它把"写一个工具"这件事降级成"填一张表"——工具叫什么、参数放哪、请求长什么样、响应怎么包装,全部用 YAML 写死,REST Server 源码 里的框架代码负责剩下的事。

本文的落地案例就藏在 mcp-servers 目录 下:mcp-parking-lot-query 这个目录,就是"零代码接 REST"的完整样本。

二、一份 api.json 如何"长"出 3 个 MCP 工具

先看结论:这个 MCP Server 目录里只有 4 个文件,没有.go:

  • api.json——上游 API 的 OpenAPI 3.0.1 规范,含字段示例值
  • mcp-server.yaml——REST-to-MCP 声明式配置,服务的核心载体
  • README_ZH.md/README.md——从 YAML 转换/翻译出来的文档

它们不是各自手写的,而是一条单向流水线的产物。打开 create_api_directories.sh 就能看到这个链路:

  1. openapi-to-mcp工具读取api.json,套用云市场模板yunmarket-tmpl.yaml,生成mcp-server.yaml;
  2. yaml_to_markdown.py再把 YAML 里的工具、参数说明转成中文文档,拼进README_ZH.md;
  3. translate_readme.py把中文版翻成README.md。

换句话说,规范是唯一的事实来源:改了api.json重新跑一遍脚本,配置和文档同步刷新。这也是你以后给自己项目做 REST API 转 MCP 时可以照抄的工程结构。

三、先拿凭证:AppCode 怎么来、有什么坑

这个停车场 API 走的是云市场AppCode 认证——凭证本身不复杂,但订阅流程里有几个点得记牢:

  1. 在云市场 API 详情页订阅服务,优先选免费试用;
  2. 用阿里云账号登录云市场用户控制台,查看已订阅服务的 AppCode,填进 MCP Server 配置;
  3. 控制台会实时展示预付费服务的可用额度,免费试用额度用完后可以重新订阅恢复额度。

这里有个省心的约束:订阅多个 API 服务拿到的是同一个 AppCode,一个凭证就能访问你订阅过的全部云市场 API 服务。所以配置里只需要留一个全局占位,给每个工具的请求模板引用:

server: name: parking-lot-query config: appCode: ""

server.name是插件路由 MCP 请求时认的"服务器身份",加载配置时必须保持为parking-lot-query;appCode留空即可,部署时再填真实值。

四、解剖一个工具:args、requestTemplate、responseTemplate 三段式

3 个工具里挑最典型的"经纬度查询"(parking-lat-lng-query)完整拆开看,另外两个一句话带过:

  • parking-city-query:按城市名查列表,必传city,外加page/size分页,打POST /parking/query/city;
  • parking-detail-query:只收一个参数id(就是列表返回的pid),打POST /parking/query/detail。

经纬度查询的完整条目长这样:

- name: parking-lat-lng-query description: 根据经纬度查询停车场信息 args: - name: lat description: 纬度 type: string required: true position: body # lng 同为必填;distance(默认1000米)、page(默认1)、size(默认10)为可选 requestTemplate: url: https://jumparking.market.alicloudapi.com/parking/query/nearby method: POST headers: - key: Content-Type value: application/x-www-form-urlencoded - key: Authorization value: APPCODE {{.config.appCode}} - key: X-Ca-Nonce value: '{{uuidv4}}' responseTemplate: prependBody: |+ # API Response Information ...(字段结构说明,末尾接 ## Original Response 原始响应)

三段各自管一件事:

  • args:告诉 MCP 客户端这个工具收哪些参数、哪些必填。position: body表示参数不进 URL,而是按 form 表单序列化进请求体——正好对上上游要求的application/x-www-form-urlencoded;
  • requestTemplate:声明式地拼出完整 HTTP 请求。url+method定骨架,headers里塞认证和防重放头(下一节细讲);
  • responseTemplate.prependBody:在原始响应前面插一段"字段说明书",这个设计的动机第五节专门说。

三个接口的基地址统一来自api.json的servers字段:https://jumparking.market.alicloudapi.com。

五、模板语法与 AppCode 认证:这几个{{ }}是怎么被渲染的

先给一句大白话:YAML 里所有{{ }}都是模板占位符,框架在真正发请求那一刻才把它们替换成实际值。

渲染引擎是 GJSON Template 库(REST Server 源码 头部 import 的github.com/higress-group/gjson_template),它把 Go 模板语法和 GJSON 路径语法揉在一起,还内置了 70 多个 Sprig 函数。本例实际用到三个语法点:

写法含义
{{.config.appCode}}取server.config下的字段,即你填的云市场凭证
{{.args.argName}}取某个工具参数(本例参数走 body 自动序列化,模板里没显式引用)
{{uuidv4}}Sprig 的 UUID 函数,每次调用生成一个随机值

对应到认证细节上,三个请求头各司其职:

  • Authorization: APPCODE {{.config.appCode}}——把全局凭证注入认证头,完成 AppCode 认证;
  • X-Ca-Nonce: {{uuidv4}}——每次请求换一个一次性随机值,做请求去重/防重放;
  • Content-Type: application/x-www-form-urlencoded——声明表单编码,和position: body配套。

再说序列化。args[].position的合法取值有五种:query、path、header、cookie、body(见 REST Server 源码 中RestToolArg.Position的注释)。而参数具体怎么进请求体,框架还留了argsToFormBody、argsToJsonBody、argsToUrlParam这几个开关(定义在RestToolRequestTemplate结构体上),上游是表单接口就选 form,是 JSON 接口就选 JSON,不用自己拼 body。

prependBody为什么要注入"字段说明书"?这是原文档没讲透、但值得补上的设计动机。看停车场返回的字段:leftnum、canbook、bookprice、taskNo……这些命名对 LLM 来说自解释性很差,靠猜很容易把"剩余车位"和"总车位"弄反。而 REST-to-MCP 场景下响应并没有强 outputSchema 约束兜底,所以云市场系模板(yunmarket-tmpl.yaml)的做法是:在原始 JSON 前面先铺一段"每个字段的类型 + 中文语义",再在## Original Response之后接原始数据。相当于把 schema 提示手写进了 prompt,让大模型在没有结构约束时也能稳定解析返回值。

六、响应长什么样:列表、详情,还有一个坐标系的坑

数据形态分两种,对照 api.json 的示例值一目了然:

  • 列表接口(周边/城市查询):data.list是停车场对象数组,data.total给总数;
  • 详情接口:data下直接就是单个停车场对象,没有list包裹层。

外层统一包三个字段:code(返回码,200 表示成功)、msg(返回码描述)、taskNo(本次请求号)。

核心字段挑重点列一下:

字段类型含义示例值
pidinteger停车场 ID,详情查询的id就传它112
namestring停车场名称交通银行大厦停车场
province/city/area/addressstring省 / 市 / 区 / 详细地址浙江省 / 杭州市 / 上城区 / 庆春路175号
lng/latnumber经度 / 纬度(百度坐标系)120.173981 / 30.263525
price/priceunit/pricedescinteger / string / string价格、价格单位、收费描述10 / 元/首小时 / 首小时10元,后每小时6元
num/leftnuminteger总车位数 / 剩余车位数20 / 1
canbook/bookpricestring是否可预订 / 预定价格"2" / 空
piclistarray of string停车场图片列表-

⚠️ 这里有个坑:lng/lat是百度坐标系(api.json里字段描述写得很明确)。如果你的下游业务要做导航跳转、地图标注,而业务侧用的是 GCJ-02 或 WGS-84,记得先做坐标转换——这是接这个数据源时的隐含约束,配置里看不出来。

七、上线与复制:从验证到"照方抓药"

部署三步走

  1. 版本门槛:MCP Server 插件要求 Higress 2.1.0 或更高版本(见 MCP 服务器实现指南);
  2. 加载配置:REST-to-MCP 是内置能力,可以直接基于all-in-one插件使用——它把多个 MCP Server 打包进同一个 WASM 二进制,降低网关上挂一堆插件的开销。把mcp-server.yaml的内容贴进 MCP 插件配置即可,server.name保持parking-lot-query,appCode填入控制台拿到的凭证;
  3. 收敛暴露面:不想全量开放工具时,用allowTools白名单点名,比如只留parking-city-query。注意它只对挂载了mcp-server插件的路由生效,管不到绕过插件的其他路由。

顺带区分一下两类 MCP Server 的上线方式:Go 代码实现的(如 amap-tools)走 Makefile 里的make SERVER_NAME=xxx build(编译为GOOS=wasip1 GOARCH=wasm的 WASM),还有build-image、build-push等目标;而本例这种纯声明式 Server无需任何编译,配置即上线。

一套可复用的接入方法清单

把案例抽象掉,任何带 OpenAPI 规范的 REST 服务都能照下面五步接入 Higress:

  1. 备齐契约:拿到(或手写)上游的 OpenAPI 规范,paths、servers、参数 schema 越全越好,它决定了配置和文档的自动生成质量;
  2. 生成或手声明:用openapi-to-mcp配一套自己的模板批量产出mcp-server.yaml,或者参照云市场模板手写——工具名、args的position、请求模板三要素是必须想清楚的;
  3. 凭证走全局配置:把 AppCode、Token 之类放进server.config,请求头里用{{.config.xxx}}引用,敏感值不进模板正文;
  4. 防重放加随机头:上游有 nonce 要求时,{{uuidv4}}一行解决;
  5. 响应加说明书:字段命名不直观的 API,务必用responseTemplate.prependBody注入"字段结构 + 原始响应",这是 LLM 稳定解析返回值的保险;
  6. 上线控面:all-in-one 插件加载,allowTools按需收敛暴露的工具集。

配置即服务、规范即文档——这就是 REST-to-MCP 声明式配置的完整闭环。

【免费下载链接】higress🤖 AI Gateway | AI Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/hi/higress

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 2:37:01

Flutter跨平台鸿蒙落地:星座运势App全流程实战与踩坑指南

这套“Flutter跨平台 鸿蒙落地”的组合拳,近期被我拿来做了一个星座运势查询应用。从环境搭建、业务编码,到真机调试,整个过程踩坑不少,但最后三端(Android/iOS/HarmonyOS)跑通的那一刻,确实值…

作者头像 李华
网站建设 2026/10/14 2:36:57

全志T153 SDIO 3.0与USB 2.0双通道嵌入式通信方案解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 2:36:49

代价函数:模型训练中那把最关键的尺子

聊一个最基础但最容易被人忽略的概念:代价函数。做机器学习的朋友应该都有这种经历:模型结构搭好了,数据也喂进去了,结果训练半天,loss 曲线像个心电图,要么降不下去,要么直接飞到 NaN。这时候大…

作者头像 李华
网站建设 2026/10/14 2:35:31

西地那非普通片 vs 口崩片,剂型差异体现在哪里?

西地那非普通片 vs 口崩片,剂型差异体现在哪里?枸橼酸西地那非是勃起功能障碍治疗的一线用药,很多人只关注药物有效成分,却忽略剂型带来的使用差别。同样的活性成分,普通片与口崩片,在服用方式、吸收路径、…

作者头像 李华
网站建设 2026/10/14 2:34:49

AI生成HTML课件如何转成可编辑PPTX?语义解析与版式重建实战

1. 为什么AI生成的HTML课件总让人又爱又恨用AI生成HTML格式的PPT,这件事我前前后后折腾了大半年。最开始是图省事——把课程大纲往对话框里一贴,几秒钟就能吐出一份带翻页效果的HTML演示文稿,浏览器里全屏一放,动画、渐变、卡片布…

作者头像 李华
网站建设 2026/10/14 2:34:21

Codex CLI 0.157.0 自动启动守护进程引发用户争议

OpenAI 的 Codex CLI 从 0.157.0 版本起默认启动一个守护进程,该进程在启动 5 分钟后自动检查更新并在后台保持运行。这一变化引发了用户对资源占用、透明度和控制权的争议,部分用户在 GitHub issue 48195 中直接将其行为与恶意软件类比。 守护进程的工作…

作者头像 李华