Highlights

TalkSpeaker

Your OpenAPI Spec Is Already an MCP Server

Speaking session at DeveloperWeek 2026

By Sachin Gupta
Portrait of Sachin Gupta rendered in binary
Speaking at DeveloperWeek — slide 1 of 14
Slide 1 / 14Download the deck (PDF) ↓

Generating working MCP servers straight from the OpenAPI specs you already have: the mechanical field mapping, why it takes a library and not a script, the production traps, and the guardrails to set before an agent touches real users.

DeveloperWeek is a room full of people who ship developer tooling for a living. I went there to make a slightly cheeky argument: for most REST APIs, the MCP server you were about to hand-write is already sitting in your OpenAPI spec. You do not have to write it. You have to generate it.

A short note on where I was

On 9 June 2026 I gave a session at DeveloperWeek in New York titled "From OpenAPI to MCP, in 90 seconds." The honest word for the experience is surreal. You spend weeks compressing an idea onto a handful of slides, and then you are standing in front of a room of people who build this kind of thing for a living, watching to see whether the idea actually lands. It did, and the hour I spent afterward in the networking lounge was better than the talk. I met some genuinely brilliant people, the kind who poke at your argument in exactly the right place, and a good part of this write-up is sharper because of those conversations.

What follows is the long-form version of the talk, for the people who were in the room and wanted the detail, and for those who were not.


The boring math that pays for the talk

The motivation is not glamorous, and I opened with it on purpose. Organizations already have their REST APIs documented in OpenAPI, often hundreds of them. The number of MCP servers they have actually built is usually a rounding error next to that. So agents can call a tiny sliver of what the business already exposes over HTTP, and every one of those MCP servers was hand-written, one tool at a time. Hand-writing does not scale to the size of an API estate.

The realization that turns that complaint into a project is this: for the common REST case, an MCP tool needs a useful name, a clear description, a typed input schema, and predictable behavior on success and failure. An OpenAPI operation already carries almost all of that. We are not inventing information. We are translating it.

What an operation already carries

An OpenAPI operation always carries five things: an operationId, human prose in summary and description, parameters that say where the inputs live, responses that describe the success and error shapes, and security that says which credentials the call needs. The core surface of an MCP tool is just three fields, name, description, and inputSchema, the things an agent sees first when it lists tools. Line the two up and the mapping falls out almost by inspection.

Field-by-field mapping: operationId becomes the tool name, summary plus description becomes the description, parameters plus their schema become the inputSchema, and responses, security and path become runtime behavior implemented as an HTTP plan, an auth decorator and an error chain operationId becomes the name, summary and description become the description, parameters become the inputSchema. The three left over, path, security, and responses, are not tool fields at all. They become runtime behavior.

So getPetById in the spec becomes a petstore_getPetById tool with a typed petId input, and a tools/call with { "petId": 10 } runs the real HTTP request behind the scenes. That is the ninety-second version, and it is genuinely that mechanical.

Why it takes a library, not a fifty-line script

Mechanical is not the same as trivial, and this was the part I most wanted people to leave with. A naive auto-mapper gets at least six things wrong, and each is a place where a real library has to do real work.

  • $ref resolution. Schemas reference other schemas, recursively, sometimes cyclically. A spec is a graph, not a tree, and you have to walk it as one.
  • Polymorphic shapes. oneOf, anyOf, and allOf are everywhere in real APIs. Most translators flatten them and silently lose information the agent needed.
  • Description cleanup. OpenAPI descriptions carry markdown, links, and asides like "see the diagram." Agents read that text verbatim, including the parts that make no sense out of context.
  • operationId fallback. Not every operation has one. You need a deterministic verb-plus-path fallback, sanitized to the character rules tool names allow.
  • Parameter binding. Path templates, query encoding, header rules, multipart bodies. Each parameter location has its own little protocol.
  • Auth and errors at runtime. The spec describes contracts; the runtime needs plumbing. That gap is exactly where libraries live and scripts fall over.

The system on one page

The implementation splits into components with clean responsibilities. A pure Java library, openapi-mcp-core, parses the spec, emits a list of generated tools, and at call time binds arguments, applies auth, and calls the backend. A Spring Boot starter, openapi-mcp-server, auto-configures that generator at boot, wraps the tools as Spring AI tool callbacks, and publishes them on a /mcp endpoint over Streamable HTTP. A reference app wires the two together against the public petstore spec.

Architecture: an AI agent posts a tools/call to the /mcp endpoint of the openapi-mcp-server Spring Boot starter, which uses the openapi-mcp-core Java library to parse the spec, bind arguments and apply auth, then calls the real backend over an HTTP WebClient; the OpenAPI spec feeds the core library, parsed at boot Five components, four hops. The agent posts to /mcp, the server looks up the tool and binds arguments, the auth layer attaches credentials, the HTTP client calls the real backend, and the response mapper passes 2xx through and translates failures into MCP error codes. On the live demo it was roughly eighty milliseconds end to end.

Five ways a generated server will embarrass you

Generation gets you a working server. It does not get you a server you should put in front of real users. Five things break in production, and each has a fix worth baking into the generator rather than leaving to the reader.

  • Pagination. Agents ask for everything, and context budgets explode. Inject a sane page limit, capped before the request goes out.
  • File uploads. Multipart and binary do not round-trip as JSON tool inputs. Accept base64 in and send multipart out.
  • Polymorphic responses. oneOf and anyOf confuse agents that want a fixed shape. Preserve the union in the tool schema so the agent can switch on what actually came back.
  • Auth propagation. Per-user tokens cannot be a static config value. Thread a per-call token from your app through every request.
  • Tool name collisions. Two APIs both define getStatus. Auto-prefix and de-duplicate so each spec gets its own namespace.

The dials you turn before an agent goes live

A few defaults are opinionated on purpose, and a few things you should tune deliberately. Authentication, error mapping, tool naming, and operation filtering are all meant to be swapped: plug in bearer or JWT or per-user OAuth, map 422 to SCHEMA_INVALID so agents branch on codes instead of English, pick your own namespace, and ship the smallest tool set you can with skip-deprecated, exclude-by-tag, or read-only mode.

Beyond that, four dials matter. Refine the schema descriptions, because agents need verbs, constraints, and examples, not human prose; treat the spec as a product surface. Control the surface area, because all of your endpoints exposed is a starting point, not an end state. Tag capabilities and enforce destructive actions with server-side permission checks, because the client may or may not show a warning and your server is the only thing that can actually stop a bad call. And put a token bucket in front of the HTTP client so an over-eager agent cannot blow your downstream SLA.

There is one more piece of cheap insurance: a build-time report. A small Gradle plugin emits the full list of generated tools, so you can diff it in pull requests and fail the build when a known tool disappears or a name collides, catching regressions before an agent does.

The questions the idea keeps getting

The nice thing about giving a talk is that the pushback tells you where the argument is thin. A few objections came up more than once, and they are the ones the deck was built to answer.

"Why generate instead of just writing the server?" Because generation is repeatable and hand-writing is not. When the API changes, you regenerate and diff, instead of hunting for the tool you forgot to update. The interesting work was never the boilerplate; it is the runtime and the guardrails, and generation frees you to spend your time there.

"Doesn't a generated tool make a worse tool than a hand-crafted one?" It can, if your spec descriptions are written for humans. That is exactly why I argue you should treat descriptions as product copy and measure agent success before and after. The generator is honest: it surfaces how good your spec actually is.

"What about the flows that are genuinely dynamic?" Fair. Generation covers the large, boring middle of your API estate extremely well. The unusual, stateful, multi-step flows still deserve a hand. The point is not to generate everything; it is to stop hand-writing the ninety percent that is mechanical so you have time for the ten percent that is not.

What I took home

Three things stuck with me on the flight back.

First, the idea is almost boring in the best way. The material is already in the spec, the translation is mechanical, and everything genuinely hard lives in the runtime and the guardrails. Boring-but-useful is a good place for a tool to be.

Second, the audience for a developer tool is not impressed by cleverness; they are impressed by "I could ship this Monday." The parts of the talk that landed hardest were the concrete ones: the five production traps, the build-time report, the number twenty operations into twenty tools in an afternoon.

Third, and this is the part I did not expect, the hallway is where the real work happened. The questions above did not come from me being clever in front of slides. They came from people walking up afterward and arguing with me in exactly the right places. That is the surreal, slightly humbling gift of a conference: you bring an idea, and a room of strangers hands it back to you sharper.

If you want to try it

I closed the talk on the practical note, because a talk you cannot act on by Monday is entertainment, not help.

  1. Generate one MCP server this week. Pick a single OpenAPI spec from your portfolio and use the demo template. Twenty operations become twenty tools in an afternoon.
  2. Add the build-time check to CI. Around thirty lines of config buys a pipeline that fails when a tool vanishes or two collide.
  3. Treat tool descriptions as product copy. Spend the spec writer's time on the descriptions, regenerate, and measure agent success before and after. It is the cheapest measurable lift you will find.

The code, the plugin, and the petstore wiring are all open source at github.com/sachinkg12/openapi-mcp.


Sachin Gupta · linkedin.com/in/guptasachin1

From the "From OpenAPI to MCP, in 90 seconds" session at DeveloperWeek, New York, 9 June 2026.

Related