Turn any OpenAPI/Swagger API into an MCP server with per-user OAuth2. Multi-spec gateway for Claude Code, Codex, Cursor, and other MCP clients.
OpenAPI MCP Gateway
以下摘录自该仓库的 README(片段) · 在 GitHub 读完整 README →
Mount any OpenAPI (Swagger) spec as a Model Context Protocol (MCP) server, or expose an existing FastAPI app the same way. Multiple APIs in one process, each with its own mount path and auth.
- **Multi-Spec, Multi-Auth.** Mount GitHub, an OAuth2 SaaS, and your internal API side by side, each with its own auth and token namespace.
- **Spec-Compliant Authorization.** The gateway runs its own OAuth server and mints audience-bound upstream tokens, so the MCP client's credential is never replayed against a third party.
- **Tool Shaping.** Rename ugly operationIds, hide knobs the model should never touch, and rewrite requests and responses with JSONata, all in YAML with no fork required.
- **Dynamic Exposure.** Front a 1,200-operation spec with three list → get → call meta-tools, so connecting to it does not spend the LLM's whole context window on tool schemas.
- **Resources, Not Just Tools.** Eligible read-only GETs register as MCP resources instead, addressable by URI and surfaced by the client rather than guessed at by the model.
- **FastAPI-Native.** Decorate routes with @mcp_tool to expose them in-process over ASGI, no extra hop and no second spec to maintain.
---
Installation
Requires Python 3.11+. To skip the install entirely, uvx openapi-mcp-gateway runs the published package directly.
Quick Start
Every example below uses uv run, which assumes the install above.
1. Public API, No Auth
Connect an MCP client to http://127.0.0.1:8000/petstore/mcp.
2. Bearer Token or API Key
API-Key Header instead of a Bearer Token
Use a config file so the header name is explicit:
3. OAuth2
Rather than asking you to paste an upstream token into config, the gateway obtains one per caller. authorization_code runs the gateway as the authorization server and mints each end-user their own upstream token. client_credentials shares a single service token across every client. token_exchange hands issuance to an identity provider you already run. See Authorization for how each pairs a check on the MCP endpoint with a credential for the API.
For the service-token flow, add --auth-flow client_credentials. Those two are what the CLI reaches. token_exchange needs an issuer and an audience, so it is configured per server under auth: in YAML, described in Authorization.
4. Multiple APIs at Once
Mix public, bearer, and OAuth2 services in a single config. Each server is mounted at /{name}/mcp:
That one file serves 13 tools with 3 concrete resources and 3 resource templates at /petstore/mcp, three meta-tools fronting ~1,200 endpoints at /github/mcp, and per-user OAuth2 against Asana's IdP at /asana/mcp. No spec edits anywhere. Run it with uv run openapi-mcp-gateway --config servers.yml.
5. Local Desktop Client (stdio)
For Claude Desktop, IDE integrations, or any MCP client that prefers stdio:
More Examples
Runnable configs for every scenario above live in examples/, each with its prerequisites documented at the top.
Authorization
Every request crosses two boundaries, and one auth: block settles both of them. One is who may call the MCP endpoint, the other is what credential reaches the API behind it. Setting auth.type, plus auth.flow under oauth2, picks a pairing of the two. Everything the gateway sends upstream lives under auth.upstream, so the indentation separates the two directions.
| auth.type / auth.flow | MCP Endpoint | Credential Sent Upstream |
| --- | --- | --- |
| none | open | none |
| bearer, api_key | open | a fixed one from config, shared by every caller |
| passthrough | open | the caller's own header, forwarded unchanged |
| oauth2 + client_credentials | open | one service token, shared by every caller |
| oauth2 + authorization_code | **the gateway is the authorization server** | a per-user token the gateway obtained on their behalf |
| oauth2 + token_exchange | **an external issuer is the authorization server** | a per-user token exchanged from the caller's |
Only the last two put a check in front of the MCP endpoint. The others suit a gateway on localhost or inside a private network, and leave it open to anyone who can reach the port.
token_exchange verifies JWT signatures, so it needs the oidc extra. Run the gateway as uvx --from "openapi-mcp-gateway[oidc]" openapi-mcp-gateway. Without it the gateway refuses to start and says so.
Token Forwarding Policy
The MCP spec requires a server to accept only tokens minted for itself, and forbids relaying one to an upstream API. So under both protected flows the upstream is reached with a second, separately obtained credential rather than the one the caller presented. See Access Token Privilege Restriction.