Build MCP servers
How to turn an OpenAPI spec into an MCP server
If your API already has an OpenAPI spec, you should not have to write an MCP server by hand. This tutorial takes a spec URL to a running, private server whose tools you can grant one at a time.
An OpenAPI spec already describes everything an MCP server needs: the operations, their parameters, what they return and how to authenticate. Writing a server by hand mostly means copying that description into code, then keeping the copy in sync every time the API changes.
Statio's generator, mcp-gen, does the copying. You give it a spec URL. It writes a TypeScript server on the official MCP SDK, builds it, runs it privately and registers every tool so you can grant each one separately. By the end of this tutorial you will have done that for your own API and made a first call through it.
Prerequisites
- A Statio account. The free plan includes one hosted server generated from a spec.
- An OpenAPI 3.0 or 3.1 spec at a URL Statio can fetch. A spec behind your VPN will not work, so host a copy somewhere reachable.
- The credential your API expects: a bearer token, basic auth or an API key.
- An MCP client such as Claude Code or Cursor, set up as in How to add MCP servers to Claude Code.
Step 1: Check the parts of the spec that become tools
Five minutes spent on the spec saves a lot of confusion later, because the model only ever sees what the spec says.
- operationId names the tool. In Per Endpoint mode each operation becomes a tool named from its
operationId, sogetInvoiceis the tool the model sees for fetching an invoice. Operations without one get a stable name built from the method and path, which works but reads worse. - summary is what the model reads. The generator uses the operation's
summaryas the tool description, falls back todescription, and falls back again to the method and path. A summary like "Get an invoice by ID, including line items" helps the model pick the right tool. "GET /v1/invoices/{id}" does not. - servers sets the base URL. Generated tools call the URL in the spec's
serversblock. You can override it in the next step if the spec points at the wrong environment. - Parameters should be typed. Path and query parameters are typed from the spec, and references are resolved, including recursive schemas. A parameter declared as a bare string with no description is a guess for the model.
Step 2: Pick a generation mode
The mode decides how many tools the model sees when it connects, and that list goes into its context before anyone asks anything.
| Mode | What the model gets | Use it for |
|---|---|---|
| Per Endpoint | One tool per operation | Small, focused APIs where the model should see everything up front |
| Generic | Three tools, whatever the API's size | Large APIs |
Generic mode registers three tools ending in list_schemas, get_schema and api_call, each prefixed with a name for your server. The model searches for an endpoint, reads its schema, then calls it. The rest of the API stays on the server until asked for. By our estimate that keeps the tool list around 800 tokens, against tens of thousands for a few hundred endpoints in Per Endpoint mode. Those are estimates, not measurements.
There is also Curated mode, where you name the operations that become direct tools and a fallback reaches everything else. Today it is configured in an mcp-gen.yaml file rather than in the app.
If your spec is large and you want Per Endpoint anyway, the app does not filter endpoints yet. Host a trimmed copy of the spec that contains only the operations you want, and point Statio at that. Every tool you leave out is one less thing to grant and one less thing for the model to read.
Step 3: Create the server
In the Statio dashboard:
- Open My MCPs and click Create MCP.
- Choose Generate from OpenAPI.
- Fill in a Display Name, a URL-safe Name and a description. The URL-safe name becomes part of the connection URL, so pick something short like
billing. - Paste the OpenAPI Spec URL and choose a Generation Mode.
- Click Validate & Preview.
The preview shows how many endpoints, tools and types the spec produced, the base URL the generated tools will call (with Change if it is wrong), the list of generated tools and any warnings. Read the tool list. If a name or description looks wrong, fix the spec and validate again. If the spec has errors, they are listed with the path in the spec where each one is.
When the preview looks right, click Create MCP.
Step 4: Deploy it and let it reach your API
From the server's page, deploy it. Statio fetches the spec, generates the server, builds an image, deploys it privately on Google Cloud Run and discovers its tools. You can follow each stage as it runs, and if a stage fails the logs say which one: fetching the spec, generating, building or rolling out.
Two settings come next, and the server cannot do anything useful without them:
- Outbound Access. A server Statio runs has no direct route to the internet. Add your API's host, such as
api.example.com, to its outbound allowlist. An empty list means the server can reach nothing, and blocked attempts show up in the same panel. - Credentials. Add the key your API expects. It is encrypted at rest and added to the upstream request at call time. The model never sees it and never has to supply it.
The full details are in Deploy your own MCP server in the docs.
Step 5: Grant the tools you want, one at a time
Nothing is granted by default, including to you. On the server's permissions, grant the tools each person or agent should use. A good first pass is the read operations only. Add writes when someone needs them, and leave anything destructive, like a delete, for the few people who should have it.
Then connect your client through Statio, as described in Connect a client, and start a new session so the client picks up the server.
Ask the agent to use one of the tools you granted. The call goes through the gateway, the credential is added on the way out, and the call appears in the audit log. Now ask for a tool you did not grant. The gateway refuses it, and that refusal is in the log too.
Step 6: Ship changes as versions
When the API changes, ship a new version from the server's page. Statio fetches the spec again. If the spec, the generator and your settings are all unchanged, it reuses the last image instead of rebuilding.
Each version can run on its own preview URL before you promote it, and you can roll back to an earlier version without a rebuild. A rollback returns the code that ran before. Credentials, grants and the outbound allowlist are current settings and do not roll back with it.
The do-it-yourself route
You can also write the server yourself with the official SDK, and for a handful of tools that is a reasonable afternoon. The steps are in How to build an MCP server in Python and How to build an MCP server in TypeScript.
What you take on is everything around the tools: hosting the server, keeping it in sync with the spec, keeping the API key out of client config files, and deciding who can call what. That is the part generation saves, more than the code.
Conclusion
You took an OpenAPI spec to a private MCP server, chose how much of the API the model sees, let the server reach only your API's host, and granted its tools one at a time. When the spec changes, a new version picks it up.
Next tutorials: