内容
# oas2mcp
在启动时加载 [OpenAPI](https://www.openapis.org/) 文档,并将文档中描述的每个操作暴露为 [模型上下文协议(MCP)](https://modelcontextprotocol.io/) 服务器的工具。
每个 OpenAPI 操作都成为一个 MCP 工具。当客户端调用该工具时,`oas2mcp` 构建并发送相应的 HTTP 请求到上游 API,并返回响应。换句话说,它将任何提供 OpenAPI 描述的 HTTP API 转换为 MCP 能够驱动的工具,而无需编写一行粘合代码。
## 功能
- **从文件或 URL 输入** - 文档在启动时一次性获取/读取,支持 JSON 或 YAML 格式。
- **每个操作一个工具** - `operationId` 成为工具名称(默认为 `<method>_<path>`);路径、查询和头部参数成为顶级工具参数,JSON 请求体作为 `body` 参数传递。本地 `$ref` 被内联到每个工具的输入模式中。
- **三种传输方式** - MCP 服务器可以通过以下方式暴露:
- `stdio` - 用于本地子进程 MCP 客户端。
- `streamable-http` - 当前远程传输,单个 `POST /mcp` 端点。
- `sse` - 旧的 HTTP + SSE 传输(已被 MCP 规范废弃,但为了与旧客户端兼容而保留)。
- **身份验证透传** - 将任意静态头部(例如 bearer token)附加到每个上游请求,或将 MCP 客户端自己的请求头部(例如 `Authorization`)转发到上游(仅 `streamable-http` 支持)。
- **优雅关闭** - 在 `SIGTERM` / `SIGINT` 时。
## 安装
需要最近的 Rust 工具链(2024 版)。
```bash
cargo build --release
# 二进制文件位于 target/release/oas2mcp
```
或使用 Docker:
```bash
docker build -t oas2mcp .
```
## 使用
```text
oas2mcp [选项]
```
OpenAPI 源文件是必需的:请传递 `--openapi-file` 或 `--openapi-url` 其中之一。
| 选项 | 环境变量 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `--openapi-file` | `OPENAPI_FILE` | - | 磁盘上 OpenAPI 文档(JSON 或 YAML)的路径。 |
| `--openapi-url` | `OPENAPI_URL` | - | 启动时获取的 OpenAPI 文档的 URL。 |
| `--base-url` | `BASE_URL` | 规范 `servers` | 工具调用被代理到的上游 API 基 URL。 |
| `--header` | `UPSTREAM_HEADERS` | - | 每个上游请求的额外 `Name: Value` 头部。可以重复。 |
| `--forward-header` | `FORWARD_HEADERS` | - | 要转发给上游的传入请求头部的名称(例如 `Authorization`)。可以重复。仅 `streamable-http` 支持。 |
| `--include` | `INCLUDE_OPERATIONS` | - | 仅公开名称与此 glob(`*` / `?`)匹配的操作。可以重复。 |
| `--exclude` | `EXCLUDE_OPERATIONS` | - | 丢弃名称与此 glob 匹配的操作。可以重复。优先级高于 `--include` / `--tag`。 |
| `--include-regex` | `INCLUDE_OPERATIONS_REGEX` | - | 仅公开名称与此正则表达式匹配的操作。可以重复。 |
| `--exclude-regex` | `EXCLUDE_OPERATIONS_REGEX` | - | 丢弃名称与此正则表达式匹配的操作。可以重复。优先级高于允许列表。 |
| `--tag` | `INCLUDE_TAGS` | - | 仅公开带有此 OpenAPI 标签的操作(不区分大小写)。可以重复。 |
| `--exclude-tag` | `EXCLUDE_TAGS` | - | 丢弃带有此 OpenAPI 标签的操作(不区分大小写)。可以重复。优先级高于允许列表。 |
| `--transport` | `TRANSPORT` | `stdio` | `stdio`、`sse`、`streamable-http` 之一。 |
| `--bind-addr` | `BIND_ADDR` | `127.0.0.1:8000` | `sse` 和 `streamable-http` 传输方式的绑定地址。 |
| `--log-filter` | `RUST_LOG` | `info` | `tracing` 过滤器指令(例如 `oas2mcp=debug,rmcp=warn`)。 |
配置按照 CLI 标志 → 环境变量 → 默认值的顺序解析,每个选项都可以通过其环境变量设置。当未明确传递基准 URL 时,将使用文档 `servers` 列表中的第一个绝对条目。
### 示例
通过 stdio 公开捆绑的 Petstore 示例:
```bash
oas2mcp --openapi-file examples/petstore.yaml
```
通过 Streamable HTTP 提供远程 API,转发 bearer token 到上游:
```bash
oas2mcp \
--openapi-url https://api.example.com/openapi.json \
--transport streamable-http \
--bind-addr 0.0.0.0:8000 \
--header 'Authorization: Bearer <token>'
# MCP 端点:POST http://0.0.0.0:8000/mcp
```
将每个 MCP 客户端自己的 `Authorization`(和租户头部)转发到上游 API,而不是单个共享令牌(仅 `streamable-http` 支持):
```bash
oas2mcp \
--openapi-url https://api.example.com/openapi.json \
--transport streamable-http \
--bind-addr 0.0.0.0:8000 \
--forward-header Authorization \
--forward-header X-Tenant-Id
```
静态 `--header` 具有相同名称的优先级高于转发头部。头部名称不区分大小写。使用环境变量设置多个值时,请用换行符分隔(例如 `FORWARD_HEADERS=$'Authorization\nX-Tenant-Id'`)。
使用旧 SSE 传输方式提供服务:
```bash
oas2mcp --openapi-file examples/petstore.yaml --transport sse
# SSE 流:GET http://127.0.0.1:8000/sse
# 客户端发布:POST http://127.0.0.1:8000/messages?sessionId=<id>
```
### 限制公开的操作
大型 API 转换为巨大的工具集:GitLab 的 OpenAPI 文档定义了约 1700 个操作,其 `tools/list` 有效载荷约为 **50 万个标记** - 它不适合模型的上下文,大多数 MCP 客户端在达到此限制之前就已经报错。使用 `--include` / `--exclude`(名称通配符)、`--include-regex` / `--exclude-regex`(名称正则表达式)和 `--tag` / `--exclude-tag`(OpenAPI 标签)来宣传您实际需要的操作。
如果操作通过两个测试:它匹配允许列表(任何 `--include` 通配符、任何 `--include-regex` 或任何 `--tag`;空允许列表表示“所有内容”)并且不匹配拒绝列表(`--exclude` / `--exclude-regex` / `--exclude-tag`,始终优先),则该操作将被保留。名称模式与工具名称匹配 - `operationId` 或 `<method>_<path>` 备用。通配符支持 `*`(任何运行)和 `?`(单个字符);正则表达式使用 [`regex`](https://docs.rs/regex) crate 语法(不区分大小写通过前导 `(?i)`)并且除非您使用 `^` / `$` 锚定它们,否则它们是未锚定的。
```bash
# 仅公开 GitLab 的 Projects 和 Merge requests 端点:
oas2mcp \
--openapi-url https://gitlab.com/gitlab-org/gitlab/-/raw/master/doc/api/openapi/openapi_v3.yaml \
--tag Projects --tag 'Merge requests'
# ~1700 操作 → 114 工具(约 9 倍缩小)
# 或按名称选择并丢弃已弃用的操作:
oas2mcp --openapi-file api.yaml --include 'getApiV4Projects*' --exclude '*Deprecated'
# 通过正则表达式仅公开只读 Projects/Groups 端点:
oas2mcp --openapi-file api.yaml --include-regex '^getApiV4(Projects|Groups)'
```
启动日志报告了保留和过滤的操作数量。
### 从 MCP 客户端使用
对于 stdio 客户端(例如 Claude Desktop / Claude Code),请将其指向二进制文件:
```json
{
"mcpServers": {
"petstore": {
"command": "oas2mcp",
"args": ["--openapi-file", "/abs/path/to/examples/petstore.yaml"]
}
}
}
```
对于远程客户端,请启动 `streamable-http` 传输方式,并将其连接到 `http://<host>:<port>/mcp`。
## 在 Kubernetes(Helm)上部署
Helm 图表位于 [charts/oas2mcp](charts/oas2mcp) 下。它使用 `streamable-http` 传输方式、有限制的 security context 和资源请求/限制部署服务器。上游身份验证头部存储在 `Secret` 中。
```bash
helm install petstore charts/oas2mcp \
--set oas2mcp.openapi.url=https://petstore3.swagger.io/api/v3/openapi.json \
--set-string 'oas2mcp.upstream.headers[0]=Authorization: Bearer <token>'
```
OpenAPI 文档可以来自 URL(`oas2mcp.openapi.url`) 或内联提供(`oas2mcp.openapi.inline`),在后一种情况下,它将从 `ConfigMap` 挂载。要重用现有的 `Secret` 进行上游头部,请设置 `oas2mcp.upstream.existingSecret`(键 `UPSTREAM_HEADERS`)。请参阅图表的 [README](charts/oas2mcp/README.md) 以获取所有值。
## 操作如何映射到工具
给定此操作:
```yaml
paths:
/pet/{petId}:
get:
operationId: getPetById
parameters:
- { name: petId, in: path, required: true, schema: { type: integer } }
```
`oas2mcp` 公告了一个 `getPetById` 工具,其输入模式需要一个 `petId` 属性。调用它时,使用 `{ "petId": 1 }` 发出 `GET <base-url>/pet/1` 并返回上游响应(状态行后跟正文)。非 2xx 上游状态作为 MCP 工具错误显示。
## 运行测试
```bash
cargo test
```
## 开发
安装 git hooks 并运行所有检查:
```bash
pre-commit install
pre-commit run --all-files
```
这运行 `cargo fmt --check`、`cargo clippy -D warnings`、`hadolint`、`actionlint`、`helm lint`、`helm-docs` 和标准空白/合并钩子。
### CI / 发布
GitHub Actions 工作流:
- **质量** - 在每次推送到 `main` 和每个拉取请求时运行 `pre-commit` 和测试套件。
- **构建** - 构建容器镜像(在原生运行器上支持多架构);仅在手动调度或发布后推送到 `ghcr.io/therealm-tech/oas2mcp`。
- **图表** - 将 Helm 图表发布为 OCI 工件到 `ghcr.io/therealm-tech/charts`,由 `chart-X.Y.Z` 标签(或手动调度)触发。图表版本独立于应用程序版本。
应用程序和图表有单独的发布生命周期:
```bash
# 发布应用程序(镜像 + GitHub 发布):
git tag v0.1.0 && git push origin v0.1.0
# 独立发布 Helm 图表(OCI 推送):
git tag chart-0.1.0 && git push origin chart-0.1.0
```
## 限制
- 支持 OpenAPI **3.0.x**(通过 [`openapiv3`](https://docs.rs/openapiv3));3.1 及以上文档可能无法解析。
- 仅代理 `application/json` 请求体。
- 忽略 Cookie 参数。
- 旧 `sse` 传输方式为了兼容性而保留,但已被 MCP 规范废弃;对于新的远程部署,请首选 `streamable-http`。
## 许可证
在 [Apache License, Version 2.0](LICENSE) 下许可。