关于 Sezzlee OpenAPI
Sezzlee OpenAPI 将 OpenAPI 文档转为可搜索的 MCP 工具目录,供远程 API 使用。它作为独立服务通过网络调用后端操作,并支持 stdio 或 streamable HTTP 传输。
主要功能
- 01读取 Swagger 和 OpenAPI 文档
- 02搜索并加载 API 工具
- 03调用远程 API 操作
- 04读取已存储的超大结果
- 05配置操作选择和工具名称
- 06根据文档重新加载 API 目录
适用场景
- 01将选定的 API 端点开放为 MCP 工具
- 02帮助 Agent 查找相关 API 操作
- 03通过 MCP 客户端调用远程后端
- 04文档变更后刷新工具目录
MCP 相关
通过 MCP 元工具开放 OpenAPI 描述的后端操作,支持搜索、加载、调用和读取结果。服务可使用 stdio 或 streamable HTTP,并通过 fetch 调用远程后端。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
@sezzlee/openapi-mcp
MCP 服务将 OpenAPI(Swagger 2.0 / OpenAPI 3.0–3.2)文档作为 sezzlee 的搜索优先工具目录提供,包括 search_tools、load_tool、invoke_tool、read_result,并通过 远程 后端使用 fetch 调用。
状态:
1.0.0,稳定版。使用npm install -g @sezzlee/openapi-mcp安装,或运行npx -y @sezzlee/openapi-mcp;二进制文件为sezzlee-openapi。
与嵌入式 SDK 的区别
NestJS SDK 位于你的后端进程内部:它从你自己的控制器/路由中发现端点,并通过现有管道重放每次 MCP 调用,因此身份验证和授权的运行方式与当前完全一致。
openapi-mcp 是一项独立服务。它无法访问后端的进程或管道,而是读取后端的 OpenAPI 文档来了解有哪些操作(摄取规则),并在每次调用时通过网络调用后端,同时附上它自行解析出的凭据(凭据的选择和写入方式)。对于未集成嵌入式 SDK 的后端,这是唯一可用的方式。
嵌入式 SDK 在代码中声明的所有内容,都可以在每个操作的文档中通过一个 x-sezzlee 扩展声明;无法编辑文档的宿主则可以在此配置的 operations 下声明:选择、工具名称、前缀、行为提示、参数整理、变体、族、搜索词和修订版本(x-sezzlee 扩展)。
通过一个端点(POST /Rest/InvokeDynamicMethod/{methodId})路由多种能力的后端,可以在该操作的 x-sezzlee.family 中列出这些能力;每个成员都会成为独立工具,具有自己的名称、描述和请求体,分派键则保持隐藏。
快速开始
服务从 SEZZLEE_OPENAPI_CONFIG 指定的文件读取配置。请先构建软件包(此仓库不会让 @sezzlee/core 的使用方针对过期的 dist 运行):
pnpm turbo run build --filter=@sezzlee/openapi-mcp
最简配置——使用本地文档、通过选择加入至少公开一个操作,默认使用 stdio 传输:
{
"source": "./openapi.json",
"selection": { "default": "include" }
}
SEZZLEE_OPENAPI_CONFIG=/absolute/path/to/config.json node packages/servers/openapi-mcp/dist/cli.js
source 可以是路径(相对于配置文件所在目录解析),也可以是 http(s):// URL。启动时,服务会摄取文档、构建目录,并将每种诊断代码的摘要按每行一条打印到 stderr,随后根据 transport.kind 提供 stdio 服务或监听 streamable HTTP。
如果配置未通过验证,或其中指定的环境变量未设置,进程会在 stderr 输出消息并以退出代码 2 终止。如果文档摄取时出现致命诊断,或目录出现致命诊断(name_collision、invalid_name、ambiguous_selection 等),进程会以退出代码 1 终止。
配置
以下所有键均从 SEZZLEE_OPENAPI_CONFIG JSON 文件中读取,并使用 zod 架构(src/platform/config.ts)进行验证;该架构会拒绝未知键。
| 键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
transport.kind | "stdio" | "http" | "stdio" | — |
transport.host | string(仅限 http) | "127.0.0.1" | 除非配置了 tokenExchange,否则必须保持为环回地址(127.0.0.1、::1、localhost)——见下文 |
transport.port | int,0–65535(仅限 http) | 8787 | — |
transport.path | 以 / 开头的 string(仅限 http) | "/mcp" | — |
transport.resource | url(仅限 http) | 必填 | 在 /.well-known/oauth-protected-resource 公布的 OAuth 受保护资源标识符 |
transport.authorizationServers | url 数组,至少 1 个(仅限 http) | 必填 | — |
transport.allowedHostnames | string 数组(仅限 http) | [] | 除 localhost 默认值外,额外接受的 Host 标头值 |
tokenExchange | object | 未配置 | RFC 8693 令牌交换;http 传输需通过它对调用方进行身份验证(见规则) |
tokenExchange.tokenEndpoint | url | 必填 | — |
tokenExchange.clientId | string | 必填 | — |
tokenExchange.clientSecret | { fromEnv: string } | 必填 | — |
tokenExchange.clientAuth | "basic" | "post" | "basic" | client_secret_basic 或 client_secret_post |
tokenExchange.audience | string | 不发送 | — |
tokenExchange.resource | url | 不发送 | — |
tokenExchange.scope | string | 不发送 | — |
tokenExchange.schemes | string 数组,至少 1 个 | 必填 | 交换所得令牌满足的安全方案名称 |
source | 非空 string | 必填 | 本地文件路径(相对于配置文件)或指向 OpenAPI 文档的 http(s):// URL |
reload.intervalSeconds | 整数 ≥ 10 | 未设置 | 按此间隔重新读取 source,并增加最多 10% 的抖动。对于 http(s) 来源,根据上次的 ETag/Last-Modified 条件性重新读取;与已提供内容相同的正文会被忽略 |
reload.onSignal | boolean | true | SIGHUP 会重新读取 source。如果没有 reload 块,文档会在启动时读取一次,且 SIGHUP 保持其默认行为 |
baseUrl | url | 未设置 | 替换文档的根 servers |
serverVariables | record<string, string> | 未设置 | 覆盖文档服务器变量的默认值 |
hoistPathPrefix | 以 / 开头的 string | 未设置 | 从每条路由移至基础 URL 的前导路径段 |
outputSchema | "document" | "omit" | "document" | 对于响应与文档不匹配的后端,使用 omit |
requestBodyRequired | "document" | "always" | "document" | always 会将未声明的 requestBody.required 视为 true |
strict | boolean | false | 将 openapi_document_invalid 从警告提升为致命诊断 |
selection.default | "include" | "exclude" | "exclude" | 没有规则匹配时是否公开某个操作(默认需显式启用) |
selection.rules | { route?, method?, decision } 数组 | [] | route/method 的匹配方式与嵌入式 SDK 匹配控制器路由的方式相同 |
operations | record<operation key, x-sezzlee object> | {} | 将各字段叠加到每个操作的 x-sezzlee 字段上;若键未命名任何操作,则视为致命错误。此处的字段也不得通过 names、searchTerms 或 revision.operations 设置 |
names | record<operation key, string> | {} | 覆盖工具名称;值必须匹配 ^[a-z][a-z0-9_]{0,255}$ |
revision.catalog | 整数 ≥ 1 | 未配置 | 每个工具的行为修订版本;优先级高于文档根目录的 x-sezzlee 修订版本 |
revision.paths | record<document path, 整数 ≥ 1> | {} | 该路径项下每个操作的行为修订版本;优先级高于路径项的 x-sezzlee 修订版本 |
revision.operations | record<operation key, 整数 ≥ 1> | {} | 单个操作的行为修订版本;优先级高于该操作的 x-sezzlee 修订版本。各层级会累加,而非互相替代 |
credentials | record<security scheme name, credential> | {} | 可以是 { "value": { "fromEnv": "..." } },也可以是 { "username": { "fromEnv": "..." }, "password": { "fromEnv": "..." } };见 credentials.md |
allowHosts | string 数组 | [] | 除文档自身的根服务器外,后端操作可从中提供服务的主机 |
refHosts | string 数组 | [] | 除文档自身主机外,可用于获取外部 $ref 的主机。与 allowHosts 分开设置,因此允许访问架构主机不会让调用或凭据发送到该主机 |
identityCookies | string 数组 | [] | 除默认拒绝列表外,还会被视为身份载体的 Cookie 名称(不区分大小写比较);它们会扩展列表,而不会替换列表 |
limits.timeoutMs | 正整数 | 30000 | 每次调用的截止时间 |
limits.maxResponseBytes | 正整数 | 262144 | 返回给 Agent 的最大响应;若成功响应更大,则在 results.enabled 生效时存储起来供 read_result 读取,否则拒绝 |
limits.maxBufferedBytes | 正整数 | 16777216 | 读取的最大后端正文大小,在正文流式传输时生效;超出时会在读取前拒绝 |
results.enabled | boolean | true | 在内存中保留超出预算的成功结果并公开 read_result;见 result-reading.md |
results.lifetimeMs | 整数 ≥ 1000 | 600000 | 存储结果的保留时长 |
results.maxCallerBytes | 正整数 | 16777216 | 单个调用方的存储结果可占用的空间;最旧的结果优先移除。调用方是用于身份验证的持有者令牌;若未进行令牌交换,则是所有环回调用方 |
results.maxBytes | 正整数 | 67108864 | 所有存储结果可占用的空间;至少为 results.maxCallerBytes |
limits.maxInlineFileBytes | 正整数 | 1048576 | — |
credentials 条目以其满足的安全方案名称为键;tokenExchange.schemes | |||
条目则表示该同一方案由交换后的令牌满足。credentials 的值绝不会直接内嵌,只会引用环境变量, | |||
| 因此配置文件可以提交并共享。 |
规则
- 只有
src/net/fetch.ts会访问网络。 这是应用主机允许列表、手动处理重定向和字节上限的唯一位置;src/transport/http.ts可以使用node:http进行_监听_,但绝不能用于发起外部请求。绝不跟随重定向——跟随重定向可能会将请求及其凭据发送到允许列表从未批准的主机。 - 只有
src/platform/files.ts会访问文件系统。 对于文档通过外部$ref引用的文件,或由source指定的文件,系统会根据读取该文档的目录检查其真实路径,因此../路径段和符号链接都无法跳出该目录。 - 调用方的 MCP 令牌绝不会转发给后端。 该令牌的受众是此服务,而非后端;转发会绕过后端自身的受众检查。在配置了
tokenExchange的http传输上,调用方的令牌会在传输的 bearer 门控处交换(RFC 8693),以获得作用域限定于后端的令牌,只有交换后的令牌才会到达invoke_tool。 - 没有配置
tokenExchange的http传输不会对调用方进行身份验证,因此只能绑定到环回主机(127.0.0.1、::1、localhost);否则,操作员的静态凭据将可通过网络访问。 在stdio传输上配置tokenExchange也会被拒绝(token_exchange_requires_http)——stdio上没有可供交换的调用方令牌。 - 重新加载绝不会扩大出站访问范围。
reload只重新读取文档,不会重新读取配置;第一个目录可访问的主机集合是之后所有目录的上限:如果文档中的服务器移至集合之外的主机、从 https 改为纯 http,或将凭据发送到此前未携带凭据的纯 http 源站,系统就会拒绝该文档(widens_egress)。被拒绝的文档、包含致命诊断的文档或无法读取的文档,都不会替换当前运行的目录。提交重新加载后,目录代次会递增,并标记在每个元工具上,同时发送tools/list_changed。重新加载前加载的工具如果已不存在,则会返回unknown_tool;如果调用固定到该工具的旧版本,则会返回tool_changed。 - 可见性不等于强制执行:操作的
security表示调用需要哪项凭据,而不是哪些调用方可以发起调用,因此除非文档注明security: [],否则目录会将每个操作的身份报告为unknown。
开发
pnpm turbo run build --filter=@sezzlee/openapi-mcp
pnpm turbo run lint --filter=@sezzlee/openapi-mcp
pnpm turbo run check-types --filter=@sezzlee/openapi-mcp
pnpm turbo run test --filter=@sezzlee/openapi-mcp
请通过 Turbo 运行这些任务,而不要使用 pnpm --filter @sezzlee/openapi-mcp <task>——单独使用 filter 会跳过
dependsOn: ["build"],测试任务将针对过期的 dist 运行。
test/ 包含不需要环境变量的单元测试套件,以及一个受条件限制的套件:
acceptance.spec.ts——仅当SEZZLEE_OPENAPI_ACCEPTANCE_DOC指定了真实后端的 OpenAPI 文档路径时才会运行。文档本身绝不会进入仓库;该套件会读取文档、构建目录、断言不存在致命诊断,并打印诊断摘要,而不是固定一个会将该后端接口复制到代码树中的快照。SEZZLEE_OPENAPI_ACCEPTANCE_DOC已在此软件包的turbo.jsontest任务中声明,因此 Turbo 会将其传递给任务。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。