If you have an OpenAPI 3.x spec, you already have most of what an MCP server needs. The translation is mostly mechanical: operations become tools, request schemas become argument schemas, base URLs become an HTTP layer the tools delegate to. This post is the short version of what's possible today, what works cleanly, and what still needs human input.
What translates cleanly
1. Operations → tools
Each OpenAPI operation becomes one MCP tool. The mapping:
operationId→ tool name (sendMessagebecomessend_message, snake-cased per MCP convention).summary→ tool description (the agent reads this when deciding what to call).description→ extended tool documentation.tags→ tool grouping (some MCP servers expose tags as namespaces).
A clean operationId and summary produce a clean tool surface. The OpenAPI best practices post covers what "clean" looks like.
2. Request schemas → argument schemas
The OpenAPI request body and parameters become the MCP tool's argument schema. JSON Schema 2020-12 (OpenAPI 3.1) translates almost 1:1; OpenAPI 3.0 needs a small nullable: true → type: [..., "null"] shim.
Required parameters stay required. Optional parameters keep defaults. Enums stay enums. Examples flow through and help the agent understand expected values.
3. Auth schemes → MCP auth
OpenAPI securitySchemes declare what credentials the API expects. The MCP server reads those credentials from environment variables (typical for self-hosted MCP) or per-call arguments (for hosted multi-tenant MCP):
apiKeyin header →X-API-Keyenv var → set on every HTTP call.http bearer→<NAME>_BEARER_TOKENenv var.oauth2→ token passed in per-tool arguments (more complex; needs OAuth flow on the MCP client side).
4. Base URLs → HTTP layer
servers[0].url becomes the base URL the MCP server proxies to. If the OpenAPI spec has multiple environments (sandbox + production), the MCP server should expose them as separate connections or accept a base_url env var.
What needs human input
1. Tool granularity
OpenAPI operations are typically fine-grained (one per HTTP verb per resource). MCP tools work better when they're task-shaped (book_appointment rather than create_event + attach_attendees + send_invite).
A good OpenAPI-to-MCP generator will emit one tool per operation by default and let you override with custom tool definitions for higher-level workflows. You write the override; the generator handles the boilerplate.
2. Tool descriptions tuned for an agent reader
OpenAPI summary and description are written for human developers reading docs. MCP tool descriptions are read by an AI agent deciding whether to call. The wording differs.
A human-targeted summary: "Send a message to a phone number."
An agent-targeted description: "Send an SMS message to a phone number. The agent should use this when the user explicitly asks to text someone. Do NOT use this for emails (see send_email). Do NOT use this for group messages (see send_group_message). Always confirm the phone number with the user before calling."
The agent-targeted version reduces miscalls. Most generators won't write these for you; plan to author them by hand for the tools that matter most.
3. Destructive vs read-only tagging
OpenAPI has no concept of "this operation is destructive." MCP servers benefit from marking destructive tools so the client can prompt for confirmation. Add a custom OpenAPI extension (e.g. x-mcp-destructive: true) and have your generator surface it.
4. Rate limits and timeouts
OpenAPI doesn't model per-operation rate limits. MCP servers should — see the MCP security post. You add these as generator configuration, not from the spec.
Tools that ship OpenAPI-to-MCP today
Stainless's MCP target
Stainless ships MCP server generation alongside their TypeScript and Python SDK targets. The most mature option in 2026 for teams already on Stainless. Reads stainless.yml for per-resource configuration; emits a working MCP server with auth, transport, and basic logging.
openapi-mcp-generator (open-source)
A community project that walks an OpenAPI 3.x spec and emits an MCP server skeleton. Less polished than Stainless's target but free and forkable.
Hand-written using @modelcontextprotocol/sdk
For small APIs (<20 operations) or for higher-level tool surfaces, hand-writing is often cleaner than codegen. The SDK gives you typed server.tool(name, description, schema, handler) registrations; you wire each to your existing API.
Bloom (planned)
Bloom does not generate MCP servers today. The same OpenAPI workflow that drives TypeScript and Python SDK generation will drive MCP target generation when it ships. Spec-quality work you do today (clean operation names, good summaries, proper schemas, descriptive auth schemes) translates directly when the target lands.
Migration shape, when you switch generators
If you're moving from one OpenAPI-to-MCP generator to another, the SDK compatibility report pattern applies:
- List old and new tool names.
- Diff argument schemas (additions OK; removals or type narrowings are breakage).
- Diff auth requirements per tool.
- Diff destructive-action handling.
A clean cutover keeps the MCP client config stable on the customer side.
What to do this week
- Audit your OpenAPI spec against the best-practices post. Clean spec → clean MCP server.
- If you ship a developer product and don't have an MCP server, evaluate Stainless's target (if you're already a customer) or hand-write a small one using the official SDK.
- If you ship MCP today, walk the security checklist — confirmation flows, rate limits, structured errors.
The MCP standard is young but the OpenAPI side is mature. Most of the work to ship an MCP server is work you've already done on your REST API.