Your API, as a tool
an AI can use safely.
One command reads your OpenAPI document and writes a real MCP server: a small, reviewed tool surface, human approval on everything that changes data, and a score that tells you whether an agent can actually use it. You read the plan, you own the code.
$ promptise mcpcast https://api.acme.com/openapi.json
Parsed 23 operations; profile=read-only
Curating with openai:gpt-5-mini…
acme → acme-mcp/
tools: 7 (0 require human approval)
not exposed: 16 operations (with reasons)
files: plan · package · tests · README
$ python acme-mcp/server.py
serving over stdio — add it to Claude DesktopYour users have AI assistants.
Your API is not usable by them yet.
An OpenAPI document describes everything your API can do — hundreds of operations, developer prose, parameters nobody sets. Hand that to a model and it picks the wrong call, invents identifiers, and deletes something on a Tuesday.
MCPcast designs the small surface an agent needs, gates everything that changes data behind a human, and writes it as a project you can read, edit and ship. The plan file is yours; the server is generated from it, every time.
Any MCP client
Claude Desktop, Claude Code, Cursor, or your own build_agent() — stdio and HTTP/SSE, nothing bespoke.
Safe by default
Read-only unless you opt in, and every non-read tool waits for a human — enforced by the server, not by a prompt.
Code you own
An installable package with its own tests, Dockerfile and README. No runtime dependency on a hosted service.
Six stages. You own the one in the middle.
Code does the deterministic work. A model designs the surface under rules code enforces. You review the plan before a single file is written.
Every operation, with where each value travels
A file, a URL, or an API running on your machine. OpenAPI 3.x and Swagger 2. Local $refs inlined (cycle- and depth-guarded), parameters resolved to their wire location — path, query, body — security schemes read, deprecations kept. Hostile documents fail with one actionable error, never a traceback: alias bombs, 300-level nesting and 20 MiB specs are refused before they cost you anything.
promptise mcpcast https://api.acme.com/openapi.json promptise mcpcast ./openapi.yaml promptise mcpcast # detects an API running locally
Never trust it blindly.
A model designed this surface. It will misread something — in our own documented run it wrote “use delete_ticket instead” into a description for a tool the safety profile had excluded, and hid a parameter users need behind a default.
So the review is not decoration. The warnings are computed from the plan, not guessed: a description that names a tool this plan does not expose, parameters sent as fixed defaults, examples that teach the wrong identifiers. Each one is a one-line fix inmcpcast.plan.yaml— after a human read it.
What an agent may do is a decision, not an accident.
The safety profile decides which risk classes become tools at all. Everything that is not a read waits for a human — enforced inside the server, for every MCP client.
--profile read-onlyThe defaultOnly reads are generated. Writes, deletes and anything financial are left out of the server entirely — an agent cannot call what does not exist.
--profile standardReads and writesWrites are generated and every one of them is approval-gated, enforced by the server for any MCP client. Destructive and financial operations stay out.
--profile fullEverything, gatedDestructive and financial operations too — each one gated. You opt in explicitly, and the plan records the risk class next to every tool.
A human says yes, or nothing happens.
The gate is middleware in the server’s own request pipeline, so it applies to every client — not only to agents you built. Over stdio the client asks its user through MCP elicitation. In a multi-tenant deployment a second person of the same tenant decides, four-eyes.
A client that cannot ask, a reviewer who declines, a decision that never comes — all of them end the same way: APPROVAL_DENIED, fail-closed, nothing sent upstream.
Whose credential reaches your API?
Four deployments, one flag. The generated server presents the credential where your spec’s security scheme puts it — an Authorization header, a custom header, or a query key.
One credential from MCPCAST_UPSTREAM_TOKEN, presented where the spec’s security scheme puts it: the Authorization header, or the custom header or query parameter an apiKey scheme names. Claude Desktop, Claude Code and Cursor launch it over stdio. Because it carries one shared secret and authenticates nobody, it binds loopback only unless you pass --public behind a gateway.
A credential is validated when read and never appears in an error message — not even when the upstream quotes it back in a 401 body.
Modes that carry one shared secret bind loopback only; publishing one takes an explicit --public behind a gateway.
Response size caps, a wall-clock deadline per call, retryable 408/425/429 with Retry-After, and structured UPSTREAM_* errors an agent can act on.
A credentialed call to a non-loopback http:// host is refused unless you say you mean it.
Run it with no arguments and it walks you through.
A full-screen terminal wizard that finds the API already running on your machine, explains each of the seven decisions next to the choice, shows how many tools each safety profile would produce from your spec, opens a review workspace before anything is written — and ends by printing the exact non-interactive command, so the second run is a script.
3 · What may an agent do?
▸ read-only 5 tools · reads only
standard 8 tools · 3 require human approval
full 11 tools · 6 require human approval
── Explain ─────────────────────────────────────
Counted from your spec, not from a brochure.
Anything that changes data is generated only if
you ask for it — and then it is approval-gated.
↑↓ choose · enter continue · esc back · f1 helpMeasure it instead of guessing.
--eval writes tasks from your plan, runs a real agent against the full server pipeline, and grades the run A–F: did it reach for the right tool first, did its arguments validate, which tools no task could reach, which examples sent the API identifiers it does not recognise.
The report names the fix, not the symptom. Edit the plan, regenerate, run it again — and watch the number move. That is the loop: review, fix, measure.
What lands on disk
A package you could have written by hand — and would have, in a month. It depends on promptise and httpx, nothing else.
mcpcast.plan.yaml the source of truth — you edit this
server.py python server.py · promptise serve
helpdesk_mcp/
__init__.py build_server()
__main__.py --transport stdio | http | sse
config.py the plan’s constants + MCPCAST_* env
upstream.py the HTTP client: routes, credentials
approval.py the human approval gate
server.py where the pieces meet
tools/
tickets.py @server.tool per resource, with ROUTES
customers.py
tests/ a pytest suite: listed · routed · gated
pyproject.toml pip install -e . → the helpdesk-mcp command
Dockerfile non-root, slim, no baked-in config
.env.example every variable, with what it does
README.md install snippets for each MCP clientEverything derived is rewritten from the plan; a module you wrote by hand is never overwritten — regeneration refuses and tells you which file, so nothing of yours disappears silently.
Every tool is listed, every route reaches the right method and path against a fake upstream, and every gated tool is denied when the human says no — with nothing reaching your API.
ruff, ruff format and mypy pass on the generated tree, with its own pinned lint rules so the result does not change when your ruff updates.
stdio for desktop clients, HTTP for shared deployments, a Dockerfile for your cluster, and promptise serve when you want the framework to host it.
Twenty minutes from OpenAPI
to an agent using your API.
Point it at a spec, read what it decided, fix the two things it got wrong, and hand the result to Claude Desktop. The plan stays yours.
pip install promptisepromptise mcpcast