How to Turn Any REST API Into an MCP Server in 5 Minutes

SchemaBridge Team · 2026-08-22 · MCP, AI Agents, API Design, Security

Wrapping a REST API as an MCP server takes 5 minutes — the real work is retries, idempotency, audit and scoped tokens. The fix: serve it as a workflow.

The Five Minutes Are Real — and They Are the Trap

You can wrap an API you already own as an MCP server in minutes. Install an SDK — mcp[cli] for Python, @modelcontextprotocol/server for TypeScript — pick a transport (stdio to debug locally, streamable HTTP to deploy), wrap a few endpoints as tools, and any compliant host can drive it. The Model Context Protocol, Anthropic's open standard for how a model discovers and invokes tools, exists to collapse an N × M problem — N models and agent frameworks, M APIs, a bespoke adapter for every pair — down to N + M. You implement one server; every host talks to it.

Five minutes in, it works. That is the trap, because five minutes is where most teams stop — and a server that technically works is not one an agent can use.

An Endpoint Is Not a Tool

Point an OpenAPI generator at a mature spec and it emits a tool per operation — 400 of them. The server starts, lists everything, and looks like a success. Then an agent connects and three things break at once:

None of these is a protocol failure — the server is spec-compliant. The failure is that an endpoint is not a tool. An endpoint is a resource-shaped primitive for a programmer with your docs open, composing several calls. A tool is a task-shaped primitive for a consumer with no docs and no memory that wants one intent done in one call. The mapping was never one-to-one.

The remedy is unglamorous, and it is the actual work:

The Hard Part Isn't the Protocol — It's Durable Execution

Curate the catalogue and four more properties decide whether the server survives real usage. Read what kind of problem each one is:

Every one of those is a distributed-systems property, and none of them ships in the MCP SDK — the SDK gives you tools/list and tools/call, not a place to stand when a tool is halfway through three API calls and the process dies. So the honest shape of "build a production MCP server" is: five minutes of protocol, then a slow re-implementation of a slice of a workflow engine around it — retry policy, idempotency store, audit log, confirmation path, concurrency bound — discovered one incident at a time, in production.

Which invites a better question than "how do I build an MCP server?" — what if the thing behind the protocol already had all of that?

The MCP Server You Actually Want Is a Workflow

This is the reframe, and it is the bet we made in SchemaBridge. A durable workflow engine — a DAG of steps with named entrypoints, a declared output, run history, retries, and per-step credentials and permissions — already is the production substrate an MCP server needs. It has the retry loop, the audit trail, and survival across a restart mid-run because it is event-sourced. The one thing it lacked was a protocol adapter that says "this workflow is a tool."

So we didn't add a new object to configure. An MCP server is not something you build — it is a workflow you author. A workflow already has entrypoints, an output, history and permissions, so nothing is left over to build a "server" from. It carries a third execution mode beside async and sync — executionMode: mcp — a serving concern, not an execution one. Set it, tag the entrypoints, and the workflow is reachable as an MCP server scoped to its owner:

{
  "executionMode": "mcp",
  "vertices": [
    {
      "type": "ENTRY_POINT",
      "tags": ["platform:tool"],
      "config": {
        "toolName": "find_stock",
        "toolDescription": "Current stock for one SKU. To search by product name, use catalogue_search first.",
        "toolEffect": "OBSERVE",
        "toolInputSchema": {
          "type": "object",
          "properties": {"sku": {"type": "string"}},
          "required": ["sku"]
        }
      }
    }
  ]
}

Three mappings are the entire protocol surface:

Now count what you did not build. No retry loop: a failed step retries under the workflow's policy, and the agent sees one clean result or one actionable error, never a partial. No idempotency store and no audit log: every tools/call is a run — its arguments, intermediate steps and output recorded and queryable, so "what did the agent do?" has an answer, and it is a run id. No concurrency bound of your own: the call blocks with guardrails — a hard per-call timeout and a process-global semaphore that sheds load rather than saturating the connection pool. (That last point has an honest consequence: a slow workflow is a poor MCP tool by design, and the sync ceiling is a real product limit.)

The credential and confirmation story is not hand-assembled either. The same short-lived OAuth 2.1 token, scope re-intersection on refresh, and three effect tiers apply unchanged: OBSERVE runs autonomously, DRAFT mutates draft state only, and PRODUCTION — deploy, execute, delete — is withheld from a headless caller entirely. We derive our own catalogue this way: each route carries an @AgentTool annotation, the annotation is an allowlist (a new endpoint is invisible to every agent until someone opts it in), and a build-time parity test fails if the in-product assistant and the MCP endpoint diverge. The result is 34 tools over a platform with several hundred routes — what "ten to thirty" looks like when you actually do it.

The payoff, stated plainly: the fifteen tasks you curated down become fifteen workflows — each one something you can run, monitor, version and expose as an agent tool, with the production hardening supplied by the engine rather than hand-rolled around a wrapper. "Write one tool that makes three calls" stops being extra server code and becomes three vertices on a canvas. The tool is the workflow. And because it is a conforming MCP server, the same workflow is available to every agent runtime you adopt, not just one chat window.

Be honest about maturity: this is newly built — proven end to end through the real execution engine, but not yet exercised against a live external MCP host — so treat it as an architecture bet, not a battle-scars claim. But the bet is what the protocol was for: you write one conforming server, and it inherits durability you would otherwise have written five times.

Frequently Asked Questions

Do I need to change my REST API to support MCP?

No. An MCP server is a wrapper over your existing API. But do not map endpoints to tools one-to-one — an endpoint is resource-shaped, a tool is task-shaped.

Is it safe to expose a write API through an MCP server?

Not by default. A headless agent has no confirmation surface, so ship read-only first and refuse destructive tools at invocation time, not merely by omitting them from the listing.

Where should a production server's retries, idempotency and audit trail come from?

Not from code you write around the SDK. Those are durable-execution properties, and the cleanest source is the execution substrate itself — a workflow engine that already retries steps, dedupes delivery, and records every run. Serve the MCP server as a workflow and tools/call inherits all three instead of re-implementing them per server.

Conclusion: Make Less Possible, Describe It Better — Then Let the Engine Run It

The protocol work is five minutes and the SDKs earn their keep. Two harder problems remain, and neither is a protocol question. The first is deciding what a model should be allowed to do with the system you spent years building — the same question you answer when you design any API, except this caller reads your descriptions literally, has no memory of yesterday, and will do exactly what you made possible. The second is making it survive real use: retries, idempotency, an audit trail, scoped credentials, a concurrency bound. That second problem is already solved by any durable workflow engine — which is why the strongest version of "build an MCP server" is "author a workflow and serve it as one."

Make less possible. Describe it better. Then let the execution engine — not a hand-rolled wrapper — run it.

Explorar