mcpField
O
openapi-to-mcp

openapi-to-mcp

github.com/mcp-use开发10.8k192 次安装1 天前更新
代码仓库

关于 openapi-to-mcp

一套根据 OpenAPI 3.x 或 Swagger 2.0 API 规范构建 MCP 服务的技能,指导开发者筛选操作、生成类型化工具、配置认证并测试和部署。

主要功能

  1. 01导入 OpenAPI 和 Swagger 规范
  2. 02将 API 操作映射为 MCP 工具
  3. 03生成 Zod 参数模式
  4. 04通过环境变量配置认证
  5. 05测试并部署服务

适用场景

  1. 01将现有 REST API 封装为 LLM 工具
  2. 02从大型 API 规范中筛选端点
  3. 03构建并验证基于 HTTP 的 MCP 服务

MCP 相关

指导构建 MCP 服务,将选定的 API 操作分别转换为工具。流程采用 Streamable HTTP 传输。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mcp-use/mcp-use --skill openapi-to-mcp

安装后在 Claude Code 中输入/openapi-to-mcp确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

LICENSE.txt
references/
auth.md
code-templates.md
deploy.md
mapping-rules.md
testing.md

详细介绍

根据 OpenAPI 规范构建 MCP 服务

将现有 REST API(由 OpenAPI 3.x 或 Swagger 2.0 文档描述)转换为 MCP 服务。规范中的每个操作都会成为一个 LLM 可调用的 MCP 工具。服务可在本地运行以供测试,也可以通过一条命令部署到 Manufact / mcp-use 云。

本技能提供端到端流程:确定范围 → 导入规范 → 映射操作 → 搭建脚手架 → 生成工具 → 配置身份验证 → 测试 → 部署。

核心理念:规范就是契约

OpenAPI 文档是唯一事实来源。工具名称、描述、参数结构和身份验证要求都应来自规范,而不是凭空编造。这一点很重要,因为:

  • LLM 会信任描述。 如果规范中写着 summary: "Get current weather for a city",那么 LLM 在判断是否调用该工具时,读到的正是这段内容。手动编写的摘要会逐渐偏离;从规范生成的摘要则会随着 API 变化保持同步。
  • Zod 模式与 OpenAPI 模式一致。 每个参数(路径、查询、请求体)都会成为一个 zod 对象中的字段。必填/可选、枚举、最小值/最大值和描述都会一并保留。LLM 会利用模式判断需要向用户询问什么。
  • 身份验证信息位于规范之外。 OpenAPI 会声明身份验证方案,但不会包含密钥。密钥来自环境变量;规范会告诉你需要哪些环境变量。

如有疑问,应优先忠实遵循规范,而不是发挥创意。创意部分由 LLM 负责——与用户对话;它只需要一个忠实且类型明确的 API 接口。

流程

1. 明确请求范围(使用 AskUserQuestion)

编写代码前,通过 AskUserQuestion 工具确认以下五项。五项内容都与 API 和要构建的内容有关;部署是单独的问题,稍后在第 10 步询问,届时用户可以根据已运行的服务进行实际评估。

  • 规范来源:工作区中的文件路径、URL(例如 https://api.example.com/openapi.json),或直接粘贴到聊天中。如果是粘贴内容,请先将其保存为 openapi.yaml 或 openapi.json。
  • 服务基础 URL:如果规范中存在 servers[0].url,就使用该值;否则询问用户。规范中通常会有多个 servers 条目(生产环境/预发布环境),请确认使用哪一个。
  • 身份验证方案:读取 components.securitySchemes。如果有多种方案,请询问要使用哪一种。如果 API 需要 API 密钥或令牌,请询问存放它的环境变量名(API_KEY、OPENAI_API_KEY 等)。不要询问密钥本身——绝不要将其放进对话或提交到代码仓库。
  • 操作筛选:大型规范(如 Stripe、GitHub)包含数百个端点。询问用户要公开所有操作、某个标签下的操作(pets、users),还是手动挑选的操作列表。对于操作数少于约 30 个的规范,默认选择“全部”;超过该数量时则询问。筛选模式请参阅 references/mapping-rules.md。
  • 小组件:询问哪些操作需要在聊天中渲染小组件(显示在 LLM 回复旁边的 React 组件),或者这是否是一个纯工具型服务。OpenAPI 包装器默认应为纯工具型——LLM 读取 JSON 并进行对话。只有在用户希望为特定响应提供更丰富的 UI 时才选择小组件(例如,地理编码端点使用地图、指标端点使用图表、搜索结果使用卡片列表)。此回答将决定第 3 步使用的脚手架模板:纯工具型 → --template blank,包含任何小组件 → --template mcp-apps(该模板已预先配置 resources/ 小组件基础设施)。如果用户希望大多数操作都使用小组件,那么 mcp-apps-builder 技能通常比本技能更合适——请指出这一点,并在继续前确认。

不要跳过此步骤。生成用户不需要的 200 个工具会让 LLM 的工具列表变得臃肿,也会拖慢运行速度。

2. 获取并解除规范引用

将规范解除引用后,保存为磁盘上的单个 JSON 对象。解除引用会内联 $ref,这样下游代码就不必再追踪指针。

# In the scaffolded project root
npm install @apidevtools/swagger-parser
// scripts/load-spec.ts (run once, manually or as a build step)
import SwaggerParser from "@apidevtools/swagger-parser";
import { writeFileSync } from "node:fs";

const spec = await SwaggerParser.dereference("./openapi.yaml");
writeFileSync("./openapi.dereferenced.json", JSON.stringify(spec, null, 2));

对于 URL 规范,swagger-parser 可直接接受 URL。对于粘贴的 YAML,先将其写入 openapi.yaml,再解除引用。如果规范是 Swagger 2.0,先用 swagger2openapi 转换(npx swagger2openapi --outfile openapi.yaml swagger.yaml)。

对解除引用后的文件进行基本检查:打开文件并搜索 "$ref"——应该不会找到任何结果。如果仍有结果,说明规范包含循环引用,swagger-parser 会原样保留这些引用;在 zod 中将这些引用视为不透明对象类型。

3. 使用 create-mcp-use-app 搭建项目骨架

根据第 1 步中关于 widget 的回答选择模板:

# Tools-only (the default for an OpenAPI wrapper)
npx create-mcp-use-app@latest <project-name> --template blank

# Any widgets at all
npx create-mcp-use-app@latest <project-name> --template mcp-apps

让脚手架安装依赖并运行 git init——这两项都很有用(npm install 会在 postinstall 阶段运行 mcp-use generate-types,而后续运行 npm run deploy 需要 git 仓库)。该技能默认也会安装配套的编码 Agent 技能;这没问题。

如果有一段时间没查过模板目录,可通过 npx create-mcp-use-app@latest --list-templates 确认模板列表——截至本文撰写时,可用模板有 blank、mcp-server 和 mcp-apps。对于 OpenAPI 优先的服务端,使用 blank;mcp-server 包含需要删除的示例工具。

搭建项目骨架后,添加 OpenAPI 流程所需的另外两个依赖:

cd <project-name>
npm install @apidevtools/swagger-parser dotenv

使用 blank 模板后,你会得到以下内容(mcp-apps 是其超集,另外包含 resources/ 和 widget 基础设施):

  • 根目录下的 index.ts,其中包含已配置的 MCPServer 实例——name、title、version、description。还包含已注释掉的工具、资源和提示词示例。监听 process.env.PORT(默认值为 3000)。
  • package.json,其中的脚本已配置为使用 mcp-use CLI:dev(热重载 + 检查器)、build、start、deploy。tsx、zod 和 typescript 已在开发依赖或常规依赖中;不要重复安装。
  • tsconfig.json,已针对 ESM 预先配置("type": "module")。
  • public/,包含一个 favicon 和一个 SVG 图标——作为静态资源提供。
  • .git 目录和一条初始提交。

脚手架将环境变量 MCP_URL 保留给 MCP 服务自身的公共基础 URL(用于 widget 资源 URL 等)。它不是上游 API 的基础 URL——请将上游变量命名为 BASE_URL(或者使用更明确的 API_BASE_URL),以免与之冲突。

4. 规划项目结构

保持目录树浅且易于预测。这样,初次阅读项目的人就能在三个显而易见的文件中找到 OpenAPI 客户端、工具配置和身份验证。

<project>/
├── index.ts                         # MCPServer + server.tool() registration loop
├── openapi.yaml                     # The original spec (committed)
├── openapi.dereferenced.json        # Dereferenced spec (gitignored; regenerated)
├── src/
│   ├── client.ts                    # fetch-based HTTP client (base URL + auth + error handling)
│   ├── auth.ts                      # Reads env vars, builds the auth header
│   ├── operations.ts                # Loads dereferenced spec, exposes operation metadata
│   └── schema.ts                    # OpenAPI schema → zod converter
├── scripts/
│   └── load-spec.ts                 # Dereference helper (step 2)
├── .env.example                     # Document required env vars (API_KEY, BASE_URL, etc.)
└── package.json

对于很小的规范(少于 10 个操作),可以将 client.ts、auth.ts 和 operations.ts 内联到 index.ts 中。对于规模更大的规范,则应拆分——LLM 在每个文件只负责一项任务时表现更好。

5. 将操作映射为工具

对于规范中的每个操作,都要生成一个 server.tool({...}, handler) 调用。映射过程是机械式的:

OpenAPI 字段MCP 工具字段
operationId(优先使用)或经过 slug 化处理的 ${method}_${path}工具 name(snake_case)
summary + description工具 description
parameters(path + query)+ requestBody.content."application/json".schema合并后的 zod 对象 → 工具 schema
responses.200.content."application/json".schema可选的 zod 对象 → 工具 outputSchema
security(或回退到根级配置)处理程序要附加哪些身份验证标头

完整规则请阅读 references/mapping-rules.md——包括缺少 operationId 时如何命名工具、如何在 zod 中处理 oneOf / anyOf / 可空类型、如何扁平化包含多种内容类型的请求体,以及如何处理响应形状上的特殊情况(二进制下载、流式传输、分页列表)。

6. 生成 zod 模式

OpenAPI 类型按以下方式映射到 zod。完整转换器位于 src/schema.ts 中——实现请参阅 references/code-templates.md。关键选择:

  • type: string 搭配 enum → z.enum([...])。使用 OpenAPI 的 description 作为 .describe() 参数,以便 LLM 能看到它。
  • type: integer / type: number → z.number().int() / z.number()。保留 minimum、maximum、multipleOf。
  • type: array → z.array(<itemType>)。如果存在 minItems / maxItems,则链式调用 .min() / .max()。
  • type: object → z.object({...})。必填属性为非可选;其他属性包装在 .optional() 中。
  • oneOf / anyOf → z.union([...])。对于仅包含对象成员的 allOf,合并为一个 z.object。
  • nullable: true(OpenAPI 3.0)或 type: ["string", "null"](3.1)→ .nullable()。

始终对每个字段调用 .describe(openapi.description ?? openapi.summary ?? ""),以便 LLM 在填写参数时获得易读的提示。

7. 构建 HTTP 客户端和身份验证层

src/client.ts 暴露一个函数:callOperation(operationId, args) → Promise<unknown>。其内部会:

  1. 在解引用后的规范中查找操作。
  2. 将路径参数代入 URL 模板(/users/{id} + {id: 42} → /users/42)。
  3. 将查询参数附加为 ?key=value。
  4. 添加来自 src/auth.ts 的身份验证标头。
  5. 将请求正文序列化为 JSON(如果规范有此要求,则序列化为 application/x-www-form-urlencoded)。
  6. 发送请求;对于非 2xx 响应,抛出异常并附带服务端的错误正文。
  7. 返回解析后的 JSON(非 JSON 响应则返回文本)。

src/auth.ts 根据规范的 securitySchemes 从 process.env 读取值。四种常见方案及其对应的标头请参阅 references/auth.md。必需的环境变量应放在 .env.example 中——这是之后运行服务的人所依据的约定。

8. 在 index.ts 中注册工具

注册循环很简短。伪代码:

import "dotenv/config";
import { MCPServer, text } from "mcp-use";
import { operations } from "./src/operations";
import { callOperation } from "./src/client";
import { operationToZod } from "./src/schema";

// Keep the MCPServer fields from the example (title, favicon, icons).
// Just adjust `name`, `title`, and `description` to match the API you're wrapping.
const server = new MCPServer({
  name: "<api-name>",
  title: "<API name>",
  version: "1.0.0",
  description: "MCP server wrapping the <API name> REST API",
  favicon: "favicon.ico",
  icons: [{ src: "icon.svg", mimeType: "image/svg+xml", sizes: ["512x512"] }],
});

for (const op of operations) {
  server.tool(
    {
      name: op.toolName,
      description: op.description,
      schema: operationToZod(op),
    },
    async (args) => {
      const result = await callOperation(op.operationId, args);
      return text(typeof result === "string" ? result : JSON.stringify(result, null, 2));
    },
  );
}

// Streamable HTTP transport — the only supported transport for this skill.
// MCP endpoint: POST http://localhost:<port>/mcp
// Inspector:    http://localhost:<port>/mcp/inspector
const PORT = process.env.PORT ? Number(process.env.PORT) : 3000;
server.listen(PORT);

传输必须使用可流式 HTTP,而不是 stdio。 mcp-use 的 server.listen(port) 会在 /mcp 设置可流式 HTTP 传输——这是此技能生成的所有服务的正确选择。不要替换成 stdio。Stdio 服务无法部署到 Manufact / mcp-use cloud(云端需要 HTTP 端点来路由流量),无法通过在线检查器测试,无法在 ChatGPT 中添加为自定义 MCP 服务,也无法在 Claude 中添加为自定义连接器(两者都通过 HTTPS 连接),并且无法使用 references/testing.md 中的 curl 测试进行访问。Stdio 适用于本地命令行工具的 MCP 服务,而这不是我们要构建的服务。

每个文件的完整模板请参阅 references/code-templates.md。

9. 测试服务

先启动开发服务器——此步骤中的所有测试都假设服务器正在运行:

npm run dev

日志会打印端口(默认是 3000,如果端口被占用则回退到 3001)、MCP URL(http://localhost:<port>/mcp)和检查器 URL。在一个终端中保持服务器运行;在第二个终端中运行下面的测试命令。

然后分两个层次测试。在两层测试都通过之前,不要声称“完成”。完整操作步骤见 references/testing.md。

第 1 层——mcp-use client CLI。 首先尝试这一方式。mcp-use 软件包附带的 CLI 可以通过可流式 HTTP 通信、处理会话和身份验证记录,并可直接在终端中提供 tools list / tools call / interactive 循环。无需编写代码,也无需处理 curl 参数。

# Save the dev server under a short name
npx mcp-use client connect dev http://localhost:3000/mcp

# List and describe tools
npx mcp-use client dev tools list
npx mcp-use client dev tools describe <tool_name>

# Call a tool — args are key=value, or pass JSON for complex shapes
npx mcp-use client dev tools call <tool_name> limit=5
npx mcp-use client dev tools call <tool_name> '{"limit": 5, "filter": "active"}'

# REPL mode for fast iteration
npx mcp-use client dev interactive

对于 CI / 脚本化测试,请添加 --json 并将输出传递给 jq。如果 tools list 没有返回任何结果,说明 index.ts 中的操作筛选器过滤掉了所有内容,或者缺少 openapi.dereferenced.json。如果 connect 本身失败,则说明开发服务器未运行或使用了其他端口——改用 curl(见 references/testing.md 的“原始协议调试”部分),确认端点是否正常运行。

第 2 层——检查器聊天(真实的大模型循环)。 第 1 层证明服务正常工作。检查器则证明大模型能够使用它——工具描述是否足够清晰,能让模型选对工具;zod 架构是否提供了足够的提示,让模型正确填写参数;响应格式是否不会过于奇怪,以至于模型无法总结。

http://localhost:<PORT>/mcp/inspector?server=http%3A%2F%2Flocalhost%3A<PORT>%2Fmcp&tab=chat

同时测试强制调用(“使用 list_pets,limit 设为 5。”)和自由形式发现(“向我展示商店里的前 5 只宠物。”)——后者更难,也更能检验描述质量。

在两个层次中都测试失败路径:缺少必需参数(zod 拒绝)、身份验证错误(上游 401)、上游 5xx(将 BASE_URL 指向一个未开放的端口)。两个层次都应以清晰的错误信息妥善处理,而不是导致服务器崩溃。

如果任一层次出现“Failed to resolve import”或工具定义过时,请运行:rm -rf .mcp-use && npm run dev。

10. 部署(询问用户)

服务已在本地正常运行。现在通过 AskUserQuestion 询问用户,是要将其部署到 mcp-use cloud,还是保留在本地。只有两个选项,无需罗列其他方案:

  • 部署到 mcp-use cloud — 将服务发布到 https://<name>.run.mcp-use.com/mcp,可供 ChatGPT、Claude 及任何 MCP 客户端使用。如果除了开发者自己的开发机器之外,还有其他人会使用此服务,这是最佳选择。
  • 保留在本地 — 提供开发服务器 URL,然后停止。适合针对内部 API 进行原型开发,或用户希望在提交到公开 URL 前评估输出的情况。

如果用户选择保留在本地,则流程已完成——提供第 9 步中的检查器和 /mcp URL,并跳过此步骤的其余部分。不要推送部署;过早部署会泄露凭据并产生过时的公开端点。

如果用户选择部署,blank 脚手架已经将 npm run deploy 配置为调用 mcp-use deploy。登录后只需运行两条命令:

npx mcp-use login
npm run deploy

目前这需要一个 GitHub 仓库。如果项目还没有放在 GitHub 上:

gh repo create <org>/<name> --private --source=. --push

部署后,你会获得类似 https://<name>.run.mcp-use.com/mcp 的 URL。在 Manufact 控制面板中设置相同的环境变量(部署 CLI 会打印项目页面的链接),以便生产服务器使用与本地相同的身份验证配置。

完整的部署指南——包括如何在控制面板中配置环境变量、如何查看日志以及如何设置分支部署——见 references/deploy.md。

11. 发布检查清单

在宣布完成之前:

  • .env.example 列出每个必需的环境变量,并附有简短注释。
  • openapi.dereferenced.json 位于 .gitignore 中(从 openapi.yaml 重新生成)。
  • npm run build 运行通过;npx tsc --noEmit 检查无误。
  • 检查器已针对实时 API 至少运行过一次你关心的每个工具。
  • 部署后的 URL 对 curl https://<name>.run.mcp-use.com/mcp 请求返回有效的 MCP 响应。
  • 提交并推送。

关键参考资料

在相关步骤开始时阅读这些文件。每个文件都深入讲解一个主题——不要一开始就全部加载。

  • references/mapping-rules.md — 操作到工具的映射规则:命名、参数合并、响应处理、架构边缘情况(oneOf/anyOf/allOf、nullable、递归引用)、大型规范的筛选。
  • references/code-templates.md — 可直接复制的 index.ts、src/client.ts、src/auth.ts、src/operations.ts、src/schema.ts、scripts/load-spec.ts、.env.example 和 tsconfig.json 基础模板。每个模板都附有注释。
  • references/auth.md — 四种常见身份验证方案(apiKey、http bearer、http basic、OAuth2 bearer),以及它们如何转换为请求头。包含使用刷新令牌的 OAuth 模式。
  • references/testing.md — Inspector 使用方法、.mcp-use 缓存过期陷阱、如何强制调用工具、工具响应的检查项,以及常见的 4xx/5xx 调试方法。
  • references/deploy.md — mcp-use deploy、GitHub 设置、Manufact 控制面板中的环境变量、分支部署、可观测性选项卡,以及如何在 ChatGPT 中将已部署的 URL 添加为自定义 MCP 服务,或在 Claude 中添加为自定义连接器。

触发词和别名

当用户提到以下相关内容时,使用此技能:

  • “根据这个 OpenAPI 规范 / Swagger 文档构建 MCP 服务”
  • “把这个 API / swagger.json / openapi.yaml 转换成 MCP 工具”
  • “将 [API 名称] 封装为 MCP 服务”
  • “让 Claude 能调用 [Stripe / GitHub / 我们的内部 API]”
  • “将这些端点开放给大模型”
  • “我有一个 OpenAPI 规范,生成 MCP 服务”
  • 粘贴或附加 .yaml / .json 规范,并请求生成 MCP 版本
  • 描述现有 REST API(附带密钥、基础 URL 或文档链接),并希望大模型能够访问

不要使用此技能的情况

  • 用户想要构建一个由组件驱动的 MCP App,其中大多数或所有工具都会在聊天中呈现自定义 UI → 改用 mcp-apps-builder。此技能可以为一两个特定工具添加组件,但如果组件是主要需求,另一个技能才是合适的起点。请在第 1 步与用户确认。
  • 用户还没有 API,想要从零开始设计 API → 这是 API 设计任务,而不是 MCP 封装任务。
  • 用户想要作为客户端使用 MCP 服务(而不是构建服务)→ 这是另一种技能 / 不适用此技能。
  • 规范描述的是 GraphQL 或 gRPC 服务,而不是 OpenAPI → 此技能专用于 OpenAPI;相关模式虽可借鉴,但架构转换器不适用。

评论

支持 Markdown