跳到主要内容

openapi-to-mcp

openapi-to-mcp 插件使网关能够充当 OpenAPI 规范与模型上下文协议(MCP)服务器之间的桥梁。通过此插件,你可以通过 MCP 接口暴露现有的基于 OpenAPI 的服务,使其可供 AI 模型和客户端访问。

该插件会将 OpenAPI 规范转换为 MCP 格式,并通过 MCP 服务器接口提供服务。随后,来自 AI 客户端的请求会被代理到上游服务。插件支持自定义请求头,并支持两种用于流式响应的传输方式:Streamable HTTP 和服务器发送事件(SSE),从而实现灵活、可靠的实时通信。

下图展示了 MCP 客户端、API7 网关与上游 OpenAPI 服务之间的交互。图中的路径和数据仅为演示示例。


演示

以下示例演示如何启用对 Petstore API 的 MCP 访问,使 AI 模型和客户端能够与 Petstore 服务交互。正确配置后,AI 客户端应立即显示可用的 Petstore 工具;如果工具未显示,请确认 OpenAPI 规范 URL 可访问,且 AI 客户端环境能够连接网关地址。


部署与兼容性

部署前置条件

从 API7 企业版 3.9.10 起,OpenAPI-to-MCP 服务不再内置于网关镜像中,必须与网关一起部署在同一网络命名空间中。

  • Kubernetes(Helm):在网关 Chart values 中设置 openapiToMcp.enabled: true,以边车方式运行该服务。
  • Docker / 裸机:将 api7/openapi-to-mcp 镜像作为独立容器运行,并与网关共享网络命名空间(例如使用 --network=container:<gateway> 或主机网络),使插件可以通过 127.0.0.1:<port>(默认端口为 3000)访问该服务。插件将 127.0.0.1 硬编码为目标地址,因此两个容器必须共享网络命名空间;仅共享 Docker bridge 网络并不足够。

如果无法访问该服务,插件将返回 503 错误。mcp-tools-acl 插件同样如此。若要让服务在其他端口运行,请参阅静态配置

边车镜像标签与网关版本兼容性

插件与 OpenAPI-to-MCP 服务通过很少变更的稳定内部契约进行通信,因此一个边车镜像标签可兼容多个网关版本。下表列出了各网关版本范围应使用的边车标签。仅当两者之间的协议发生变化(即下表新增一行)时,才需要更新边车。

此指南适用于需要自行选择边车镜像标签的 Docker 和裸机部署。Helm Chart 已为配套的网关版本固定经过验证的边车标签,因此 Helm 用户无需参考此表。

网关版本边车镜像标签(api7/openapi-to-mcp
3.9.10 及更高版本1.0.1

使用 Docker Compose 部署

以下 docker-compose.yaml 会同时运行 API7 企业版网关和 OpenAPI-to-MCP 服务。MCP 服务会加入网关的网络命名空间,使插件可以通过 127.0.0.1:3000 访问它。

在控制台中添加网关实例时,系统会自动生成可直接使用的 docker-compose.yaml。若要启用 openapi-to-mcp 插件,请将下方所示的 openapi-to-mcp 服务添加到该文件中:

docker-compose.yaml
services:
gateway:
image: api7/api7-ee-3-gateway:3.9.12
container_name: gateway
hostname: gateway
restart: always
ports:
- "9080:9080"
- "9443:9443"
environment:
API7_DP_MANAGER_ENDPOINTS: '["https://<DP_MANAGER_HOST>:7943"]'
API7_GATEWAY_GROUP_SHORT_ID: "<GATEWAY_GROUP_SHORT_ID>"
API7_DP_MANAGER_CERT: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
API7_DP_MANAGER_KEY: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
API7_CONTROL_PLANE_CA: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

openapi-to-mcp:
image: api7/openapi-to-mcp:1.0.1
network_mode: "service:gateway"
restart: always

❶ DP Manager 端点,请替换为控制台中提供的地址。

❷ 网关组短 ID,请替换为控制台中显示的值。

❸ TLS 客户端证书、私钥和 CA 证书。从控制台复制生成的 Compose 文件时,系统会自动填充这些值。

network_mode: "service:gateway" 让 MCP 容器共享网关的网络栈,使插件可以通过 127.0.0.1:3000 访问 MCP 服务。仅共享 Docker bridge 网络并不足够,因为插件将 127.0.0.1 硬编码为目标地址。

启动服务:

docker compose up -d

示例

以下示例演示了如何在不同场景下配置 openapi-to-mcp 插件。

启用对 Petstore API 的 MCP 访问

以下示例演示了如何通过 MCP 协议暴露 Petstore API,允许 AI 模型和客户端与 Petstore 服务进行交互。

创建一个使用 openapi-to-mcp 插件的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "openapi-to-mcp-route",
"uri": "/mcp",
"methods": ["GET", "POST"],
"plugins": {
"openapi-to-mcp": {
"transport": "streamable_http",
"base_url": "https://petstore3.swagger.io/api/v3",
"headers": {
"Authorization": "special-key"
},
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json"
}
}
}'

❶ 配置路由允许 GET 和 POST 方法。GET 方法用于工具发现和响应流式传输(SSE),POST 方法用于执行和操作能力(messages)。

❷ 将传输方式配置为 streamable_http(建议用于生产环境)。

❸ 配置 Petstore API 地址。

❹ 配置 Petstore API 凭证。

❺ 配置 Petstore OpenAPI 文档 URL。

应用 Admin API、ADC 或 APISIX CRD 配置后,在 MCP 设置中填写 API7 网关地址,并追加之前创建的路由路径。例如:

mcp.json
{
"mcpServers": {
"api7-petstore-mcp": {
"url": "http://123.123.123.123:9080/mcp"
}
}
}

如果配置成功,你应该会看到可用工具,即通过 MCP 向 AI 客户端公开的外部函数或服务。

现在,你可以直接在 AI 客户端的聊天窗口中与 Petstore 服务交互。例如,可以尝试询问:“显示 Petstore 中编号为 1 的宠物。”

AI 客户端与 Petstore 交互

为 MCP 路由配置身份验证

以下示例演示了当路由受到身份验证方法(如 key-auth)保护时,如何通过 MCP 协议暴露 Petstore API。

创建一个消费者 johndoe

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "johndoe"
}'

johndoe 配置 key-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'

创建一个包含 openapi-to-mcpkey-auth 插件的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "openapi-to-mcp-route",
"uri": "/mcp",
"methods": ["GET", "POST"],
"plugins": {
"openapi-to-mcp": {
"transport": "streamable_http",
"base_url": "https://petstore3.swagger.io/api/v3",
"headers": {
"Authorization": "special-key"
},
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json"
},
"key-auth": {
"header": "apikey"
}
}
}'

当 MCP 服务器需要身份验证时,你可以在 mcp.json 配置中指定请求头。请参阅你的 AI 客户端文档以确认是否支持请求头。

如果支持请求头

例如,在应用 Admin API、ADC 或 APISIX CRD 配置后,可以在 Cursor 的 MCP 设置中填写 API7 网关地址、追加之前创建的路由路径,并添加 key-auth 所需的请求头:

mcp.json
{
"mcpServers": {
"api7-petstore-mcp": {
"url": "http://123.123.123.123:9080/mcp",
"headers": {
"apikey": "john-key"
}
}
}
}

配置的请求头将被添加到 GET 和 POST 请求中。

如果配置成功,你应该会看到可用工具,即通过 MCP 向 AI 客户端公开的外部函数或服务。随后便可直接在 AI 客户端的聊天窗口中与 Petstore 交互。

如果未在 mcp.json 中配置身份验证头,AI 客户端将无法从 MCP 服务器加载工具。

如果不支持请求头

如果你的 AI 客户端不支持在 mcp.json 中配置请求头,你可以将身份验证凭证包含在 MCP URL 查询参数中,因为 key-auth 支持从 URL 查询中获取凭证。

更新路由上的 key-auth 配置如下:

curl "http://127.0.0.1:9180/apisix/admin/routes/openapi-to-mcp-route" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"key-auth": {
"_meta": {
"filter": [
[
"request_method",
"==",
"GET"
]
]
},
"query": "apikey"
}
}
}'

❶ 仅将 key-auth 应用于 GET 请求。这是因为查询参数中配置的 apikey 仅随 GET 请求发送到 SSE 端点,而不会包含在后续的 POST 消息请求中。因此,如果未应用过滤器,消息请求将被 key-auth 插件阻止。

❷ 配置插件从查询参数中获取身份验证密钥。

应用 Admin API、ADC 或 APISIX CRD 配置后,在 API7 网关地址的查询参数中包含凭证:

mcp.json
{
"mcpServers": {
"api7-petstore-mcp": {
"url": "http://123.123.123.123:9080/mcp?apikey=john-key"
}
}
}

如果配置成功,你应该会看到可用工具,即通过 MCP 向 AI 客户端公开的外部函数或服务。随后便可直接在 AI 客户端的聊天窗口中与 Petstore 交互。

如果未在 MCP 服务器 URL 的查询参数中配置身份认证凭证,AI 客户端将无法从 MCP 服务器加载工具。

将动态请求头传递到上游

当上游 API 需要随请求和 MCP 客户端变化的凭证或上下文(例如用户专属 API Token、租户标识符或会话 ID)时,可以使用 x-openapi2mcp-header-* 约定,将这些值从 MCP 客户端动态传递到上游。

发送到网关且匹配 x-openapi2mcp-header-{name} 模式的 HTTP 请求头会由 OpenAPI-to-MCP 边车提取并移除前缀,再以 {name} 请求头的形式转发到上游 API。

例如,客户端请求中的 x-openapi2mcp-header-my-token: abc123 请求头会转换为上游 API 请求中的 my-token: abc123

工作原理

网关插件与 OpenAPI-to-MCP 边车协同转发请求头:

  1. 插件级请求头:在插件 headers 字段中配置的请求头会在网关中解析,并以 x-openapi2mcp-header-{name} 的形式转发给边车。这些请求头由所有客户端共享;使用内置变量时,其值可以随请求变化。
  2. 客户端级请求头(动态):MCP 客户端在 mcp.json 中使用 x-openapi2mcp-header-* 前缀设置的请求头会经网关传递到边车,再转发到上游。这些值可以随客户端变化。

静态插件请求头与动态客户端请求头同时存在时,系统会合并两者。如果客户端请求头与插件请求头同名,则插件请求头优先,客户端提供的值会被忽略。

不同传输方式的行为

动态请求头的行为取决于插件中配置的传输方式:

  • streamable_http(推荐):每个 MCP 请求都相互独立且无状态。边车会在每次请求时读取 x-openapi2mcp-header-* 请求头,因此动态请求头真正按请求生效。建议使用此传输方式透传动态请求头。
  • sse:仅在建立 SSE 连接的初始 GET 请求期间读取 x-openapi2mcp-header-* 请求头。同一会话中的后续 POST 请求不会重新读取这些请求头。因此,动态请求头在整个会话期间保持不变,无法在会话中途更改。

如果用例要求请求之间使用不同的请求头值(例如会变化的用户专属 Token),请使用 streamable_http 传输方式。

配置客户端请求头

如果 MCP 客户端支持自定义请求头(例如 Cursor 或 Claude Desktop),请在 mcp.jsonheaders 字段中添加 x-openapi2mcp-header-* 条目:

mcp.json
{
"mcpServers": {
"my-api-mcp": {
"url": "http://123.123.123.123:9080/mcp",
"headers": {
"x-openapi2mcp-header-authorization": "Bearer <user-token>",
"x-openapi2mcp-header-x-tenant-id": "tenant-42"
}
}
}
}

MCP 客户端发送 tools/call 请求时,边车会提取这些请求头,并按如下形式转发到上游 API:

authorization: Bearer <user-token>
x-tenant-id: tenant-42

请求头名称映射

HTTP 基础设施(例如 Nginx 和 Fastify)会将请求头名称规范化为小写。因此,从 x-openapi2mcp-header- 前缀后提取的请求头名称在上游请求中始终为小写。下表汇总了映射关系:

客户端请求头上游请求头
x-openapi2mcp-header-authorizationauthorization
x-openapi2mcp-header-x-api-keyx-api-key
x-openapi2mcp-header-my-tokenmy-token
备注

x-openapi2mcp-header-* 请求头由边车处理,不会原样转发到上游。只有提取后的请求头名称和值会发送到上游。

安全注意事项

MCP 客户端发送的任何 x-openapi2mcp-header-* 请求头在移除前缀后都会转发到上游 API。这意味着客户端可以向上游请求注入任意请求头。为降低风险:

  • 使用网关级身份认证插件(例如 key-authjwt-auth)限制对 MCP 路由的访问,确保只有经过授权的客户端才能发送请求。
  • 如果上游 API 依赖特定请求头进行身份认证或鉴权,请在插件级 headers 配置中设置这些请求头,不要依赖客户端提供的值,因为插件级请求头的优先级高于客户端级请求头。

扁平化工具架构参数

以下示例演示了 flatten_parameters 如何影响生成的 MCP 工具输入架构中查询和路径参数的结构。

使用 Admin API、ADC 或 APISIX CRD 完成上一个示例,为 Petstore API 配置 MCP 访问。尽管配置中未显式设置 flatten_parameters,该参数的默认值为 false

在你的 AI 客户端(如 Cursor)中,检查工具输入架构。你应该看到参数嵌套在 pathParametersqueryParameters 下:

{
"operations": {
...,
"getPetById": {
"method": "GET",
"path": "/pet/{petId}",
"pathParameters": {
"type": "object",
"required": ["petId"],
"properties": {
"petId": {
"type": "integer",
"description": "ID of pet to return"
}
},
"additionalProperties": false
}
},
"findPetsByStatus": {
"method": "GET",
"path": "/pet/findByStatus",
"queryParameters": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["available", "pending", "sold"],
"description": "Status values that need to be considered for filter",
"default": "available"
}
},
"additionalProperties": false
}
}
}
}

更新插件以扁平化查询和路径参数:

curl "http://127.0.0.1:9180/apisix/admin/routes/openapi-to-mcp-route" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"openapi-to-mcp": {
"flatten_parameters": true
}
}
}'

在你的 AI 客户端(如 Cursor)中,检查工具输入架构。你应该看到像 status 这样的参数不再嵌套在 pathParametersqueryParameters 下:

{
"operations": {
...,
"getPetById": {
"parameters": {
"type": "object",
"required": ["petId"],
"properties": {
"petId": {
"type": "integer",
"description": "ID of pet to return"
}
},
"additionalProperties": false
}
},
"findPetsByStatus": {
"parameters": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["available", "pending", "sold"],
"description": "Status values that need to be considered for filter",
"default": "available"
}
},
"additionalProperties": false
}
}
}
}

自定义 MCP 工具注解

可用性

MCP 工具注解自 API7 企业版 3.9.7 起可用。

以下示例演示了如何为 openapi-to-mcp 插件公开的 OpenAPI 操作添加 MCP 工具注解。

如果没有这些注解,AI 客户端只能收到生成的工具名称、描述和输入 Schema,无法可靠判断工具是否只读、是否具有破坏性或是否幂等,因而更难正确排列工具并安全使用它们。

内置 OpenAPI-to-MCP 转换器通过以下两种方式实现此功能:

  1. 根据 HTTP 方法推断工具的默认行为。
  2. 从 OpenAPI 厂商扩展 x-mcp-annotations 中读取显式的操作级配置。

两者同时存在时,显式的 x-mcp-annotations 值会覆盖推断出的默认值。

使用 Admin API、ADC 或 APISIX CRD 完成上一个示例,通过 openapi-to-mcp 插件公开 OpenAPI 文档,然后为 OpenAPI 操作添加注解:

上一个 Petstore 示例使用无法直接编辑的公开 OpenAPI 文档。若要应用 x-mcp-annotations,请自行托管 OpenAPI 文档,并更新 openapi-to-mcp 插件配置中的 openapi_url 字段,使其指向该文档。

openapi.yaml
paths:
/users/{id}:
get:
operationId: getUser
summary: Get user information
x-mcp-annotations:
title: Get User
readOnlyHint: true
openWorldHint: false
delete:
operationId: deleteUser
summary: Delete a user
x-mcp-annotations:
title: Delete User
destructiveHint: true

支持以下注解字段:

  • title
  • readOnlyHint
  • destructiveHint
  • idempotentHint
  • openWorldHint

如果未配置 x-mcp-annotations,转换器仍会应用以下默认推断规则:

  • GETHEADOPTIONS 映射为 readOnlyHint: true
  • DELETE 映射为 destructiveHint: trueidempotentHint: true
  • PUT 映射为 idempotentHint: true

更新托管的 OpenAPI 文档后,让 MCP 客户端列出工具。以下代码片段展示了 tools/list 响应的 result.tools 部分:

{
"tools": [
{
"name": "getUser",
"annotations": {
"title": "Get User",
"readOnlyHint": true,
"openWorldHint": false
}
},
{
"name": "deleteUser",
"annotations": {
"title": "Delete User",
"destructiveHint": true,
"idempotentHint": true
}
}
]
}

注意事项:

  • 仅支持操作级 x-mcp-annotations
  • 无效值和不支持的字段会被忽略。
  • summarydescription 仍用于控制生成的工具描述。
  • title 仅从 x-mcp-annotations.title 读取。

启用对 API7 企业版 API 的 MCP 访问

以下示例说明如何通过 MCP 协议公开 API7 企业版 API,使 AI 模型和客户端能够与你的 API7 企业版配置交互。

创建一个使用 openapi-to-mcp 插件的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "openapi-to-mcp-route",
"uri": "/mcp",
"methods": ["GET", "POST"],
"plugins": {
"openapi-to-mcp": {
"transport": "streamable_http",
"base_url": "https://your-dashboard.com",
"headers": {
"X-API-KEY": "<API7_ENTERPRISE_API_KEY>"
},
"openapi_url": "https://run.api7.ai/api7-ee/openapi-latest.json"
}
}
}'

❶ 配置路由允许 GET 和 POST 方法。GET 方法用于工具发现和响应流式传输(SSE),POST 方法用于执行和操作能力(messages)。

❷ 将传输方式配置为 streamable_http(建议用于生产环境)。

❸ 替换为你的 API7 企业版地址,请求将转发到该地址。

❹ 将 X-API-KEY 请求头替换为用于 API7 企业版身份验证的凭证。

❺ 配置 API7 企业版 OpenAPI 文档的 URL。

在 Cursor 等 AI 客户端中,使用你的 API7 网关地址更新 MCP 设置,并追加之前创建的路由路径。例如:

mcp.json
{
"mcpServers": {
"api7-enterprise-mcp": {
"url": "http://123.123.123.123:9080/mcp"
}
}
}

配置成功后,你应能看到可用工具(通过 MCP 向 AI 客户端公开的外部函数或服务)。

现在,你可以直接在 AI 客户端的聊天窗口中与 API7 企业版交互。例如,可以尝试询问:“API7 企业版中有多少个网关组?”

AI 客户端与 API7 企业版交互

故障排除

要诊断问题,请检查网关容器或 Pod 中 /usr/local/openapi2mcp/error.log 处的 openapi-to-mcp 错误日志。请注意,此日志与网关的错误日志是分开的。

已知问题

  1. 错误 Cannot use 'in' operator to search for '$ref' in undefined 通常发生在 openapi_url 中使用 OpenAPI v2 文档时。该插件仅支持 openapi_url 中的 OpenAPI v3 文档。

  2. 该插件在处理从 openapi_url 获取的 OpenAPI v3 文档中的 oneOf 架构时存在已知的解析问题。在这种情况下,MCP 客户端将在加载工具时卡住。