You already have working endpoints: order lookup, inventory, shipment tracking. Now the business wants an AI assistant — "give it an order number and it summarizes the order and where it is in transit."

The API is done. The to-do list, somehow, is not:

  • define a tool name for every operation;
  • hand-write the input schema and describe each field;
  • translate those inputs into an HTTP request;
  • shape the response back into something the model can use;
  • and then maintain this second description every time a field changes.

One interface, two sources of truth, guaranteed to drift.

If your API is already described in OpenAPI, every one of those definitions already exists. You should not be re-declaring it for agents.

The duplication nobody budgets for

Here is the wrapper people end up writing by hand for a single endpoint:

// hand-maintained, and now it must track the OpenAPI doc forever
server.tool("get_order", { orderId: z.string() }, async ({ orderId }) => {
  const res = await fetch(`${BASE}/orders/${encodeURIComponent(orderId)}`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  return res.json();
});

Multiply that by forty endpoints, add the inventory and logistics services, and then keep the parameter names, nullable fields, enums and error codes in sync with the HTTP API by hand. The moment the backend renames warehouseId or adds a status, the agent tool lies.

This is pure transcription. The operation ID, the path parameters, the request and response schemas, the auth scheme — OpenAPI already carries all of it.

Generate the tools from the contract

OpenAPI-to-MCP generation turns each operation into a discoverable tool and reuses the contract you already maintain:

  • the path and method become the tool's transport;
  • parameters and the request body become the tool's input schema;
  • the response schema tells the model what it will get back;
  • the operation description and security requirements carry over.

Conceptually, GET /orders/{orderId} becomes a tool the agent can discover:

{
  "name": "getOrder",
  "description": "Fetch one order by id, including status and line items.",
  "inputSchema": {
    "type": "object",
    "properties": { "orderId": { "type": "string" } },
    "required": ["orderId"]
  }
}

The generated server calls your existing service. It doesn't reimplement order logic, hold a copy of the data, or stand up a new backend. Your API stays the system of record; MCP is just another entry point to it. Change a field in OpenAPI, regenerate, and the human-facing docs and the agent-facing tools move together because they are built from the same file.

Start read-only. Treat writes as a separate decision

Resist the urge to expose everything on day one. For the customer-support assistant, open the read operations first — order lookup and shipment tracking — and let the agent answer real questions:

"Has this order shipped?" → call getOrder, then getShipment, answer from the actual responses.

This sequencing is practical, not cautious theater. It lets you verify the things that actually break first:

  • Are the tool descriptions clear enough for the model to pick the right one?
  • Do parameters get passed through correctly (types, enums, required fields)?
  • Does upstream auth work end to end?
  • Are responses shaped so the model can cite real values instead of guessing?

Writes — cancel order, issue refund, adjust inventory — are a different risk class. Gate them behind explicit user confirmation, least-privilege scopes, and audit logging, and expose them only after the read path is proven.

Discoverable is not the same as authorized

This is the single most important security note in this whole setup: a tool being discoverable does not mean the caller is allowed to execute it. MCP solves the connection problem; it does not replace your authorization model.

  • The generated server forwards credentials; your API still makes the allow/deny decision.
  • Scope the exposed operations per audience. A partner integration does not need your internal bulk-adjustment endpoints.
  • Never let "the agent asked nicely" bypass a permission check that the HTTP API would otherwise enforce.

A useful mental model: the OpenAPI-to-MCP layer is a typed, discoverable proxy in front of endpoints that keep enforcing every rule they enforce today.

Local for development, hosted for partners

The same generated server fits two deployment shapes:

NeedShapeWhen you use it
Local agent / dev machinestdio or local HTTP MCP serverYou're wiring an agent to services on your own machine
Remote agents and partnersHosted MCP endpoint over HTTPExternal agents or teammates need stable access without your laptop
Humans, in parallelPublished API docs from the same specA developer wants to read, not call through an agent

Hosting can also carry the documentation, so a partner gets a readable spec and a callable MCP endpoint from one published version. Publish a versioned snapshot rather than your working draft: internal, half-built operations shouldn't become external promises the moment you save a file.

Don't confuse the two MCPs

Teams hit confusion here because "MCP for APIs" shows up in two distinct moments, and they answer different questions:

Development-time MCPRuntime MCP (this article)
Who calls itYour AI coding assistantAn end-user-facing AI agent
What it doesReads the contract, mocks and tests while you buildCalls the running API to get work done
Answers"How should this endpoint be implemented and checked?""Call this endpoint and return the result"
Feeds onThe evolving local specA published, authenticated service

You can use both against the same OpenAPI file; they just sit on opposite sides of "the API exists."

Ship the read path this week

You don't need an agent framework rewrite to start:

  1. Take one reasonably complete OpenAPI spec (or generate one from existing code if the API predates its docs).
  2. Generate the MCP tools and expose two or three read-only operations.
  3. Connect an MCP-compatible client and run a real query end to end.
  4. Check auth and response shape, then widen the surface deliberately.
  5. Publish a versioned endpoint (plus matching docs) when you're ready for partners.

The consumers of an API used to be front ends, mobile apps and other services. Agents are now on that list — and they need the same contract, not a parallel, hand-written shadow of it.

You can generate an MCP server from an OpenAPI spec and run it locally or host it alongside your docs in the free web app at powerduck.com/app.

If you've already hand-rolled agent wrappers around a REST API: how did you keep the tool schemas from drifting from the real endpoints? I'd love to hear the approach (and the war stories) in the comments.