Skip to main content
Glama

OpenAPI → MCP Generator

Published on npm as @beernathan87/openapi-mcp-generator (the unscoped name was already taken); the command name stays openapi-mcp.

Turn an existing REST/OpenAPI application into an MCP server - security-first: nothing is exposed until you opt it in, destructive operations need an explicit second flag, auth never comes from the model, and every call is confined to one base URL with timeouts, size caps and a rate limit.

npx openapi-mcp init https://api.example.com/openapi.json      # -> openapi-mcp.config.json, all tools disabled
#   edit: "enabled": true on the operations you want; destructive ones also need "confirmDestructive": true
npx openapi-mcp list                                            # what would be exposed
npx openapi-mcp console                                         # local test page: call tools through the real executor
npx openapi-mcp serve                                           # stdio MCP server for your client

MCP client config (Claude Desktop / Claude Code / Cursor):

{ "mcpServers": { "petstore": { "command": "npx", "args": ["openapi-mcp", "serve", "--config", "/abs/path/openapi-mcp.config.json"], "env": { "API_TOKEN": "..." } } } }

What it generates

For every operation in the spec (OpenAPI 3.x, JSON or YAML, local $refs resolved):

  • a tool name (operationId, or method_path), a description with method, path and a [WRITE]/[DESTRUCTIVE] tag

  • a JSON Schema input built from path/query/header parameters plus the request body (body argument), with required and additionalProperties: false

  • MCP annotations derived from the method and wording: readOnlyHint (GET/HEAD), destructiveHint (DELETE, or "delete/remove/destroy/purge/reset/revoke" in the summary), idempotentHint, openWorldHint: false

  • a risk class read | write | destructive shown in list and the console

Related MCP server: safe-oas2mcp

Guardrails (executor)

  • Only the config's baseUrl origin is ever contacted; path parameters are URL-encoded; dot segments, slash/backslash and percent escapes are rejected, including in route templates. Review the base URL before enabling anything.

  • Auth is injected from an environment variable (auth.type: bearer | header | basic; auth.env, default API_TOKEN). Tool arguments cannot set Authorization, Cookie, Host or other transport headers.

  • Timeout (limits.timeoutMs, 15 s), response cap (limits.maxResponseBytes, 256 KiB - truncated and flagged), per-process rate limit (limits.maxCallsPerMinute, 60), no redirect following.

  • Disabled tools are not merely refused - they are not listed. Enabled destructive tools without confirmDestructive: true are blocked, and the config fails validation so you notice.

  • refresh re-reads the spec after an API update, keeps enabled flags for matching method/path pairs, and reports operations added/removed - new endpoints stay disabled.

Test console

openapi-mcp console serves a page on 127.0.0.1 only: it lists all operations (greyed out when disabled), shows the generated schema and annotations, lets you edit JSON arguments and calls the tool through the same executor the MCP server uses, showing the exact request URL and the response.

Limits (v1)

OpenAPI 3.x only (no Swagger 2.0); external $refs are not fetched; oneOf/anyOf bodies are passed through as-is; multipart/file uploads are not supported; responses are returned as text/JSON up to the cap; no OAuth flows (bring a token). Single-process rate limiting.

Development

npm install
npm test   # includes an in-memory MCP client <-> server round trip with a fake upstream API

MIT.

Production notes

  • Verified 2026-09-13 from the packed tarball on Windows 11 and Linux (node:22 container) against two real APIs: httpbin.org through a rich spec (component $refs, allOf, three auth styles, optional/array/object/header parameters, path templates, error responses, a deprecated operation) and Swagger Petstore v3 from its public URL. Through a real MCP stdio session: tools listed with correct annotations; path traversal in a path parameter rejected; Authorization/Host supplied as tool arguments ignored (auth comes only from the environment); upstream 404/500/503 and a 4 s timeout returned as tool errors while the session stayed protocol-clean and exited 0; disabled and undeclared-parameter operations fail closed. refresh after a spec change disabled an operation whose method changed to DELETE, kept a confirmed destructive tool enabled, left a new operation disabled and reported the removed one.

  • Exit codes: serve exits 1 on an invalid config (including enabled-but-unconfirmed destructive tools) before speaking MCP; stdout is protocol-only, diagnostics go to stderr.

  • Auth: the token env var must be present at serve time or every call fails closed (auth requires environment variable …). Put it in the MCP client's env block, never in the config file.

  • Update: npm install -g @beernathan87/openapi-mcp-generator@latest, then openapi-mcp refresh per config; review the added/removed list. Configs are plain JSON you own - back them up with your project.

Troubleshooting

Symptom

Cause / fix

baseUrl must be an absolute http(s) URL on init from a local file

the spec's servers[0].url is relative; init from the spec's URL instead, or set baseUrl in the config by hand

missing path parameter …

the spec does not declare a parameter its path template uses; declare it in the spec and refresh

a tool is listed by list but not by the client

the client cached tools/list; restart the client after editing the config

auth requires environment variable API_TOKEN

export the variable (or the one named by auth.env) in the client's server env

Credits

Created by Nathan Beer. Developed by Nathan Beer with AI-assisted engineering using Claude and ChatGPT. Third-party licenses: THIRD_PARTY_NOTICES.md. Not affiliated with or endorsed by Anthropic, OpenAI, SmartBear/Swagger or the Model Context Protocol project.

Security review contract (v0.1)

The config is trusted local policy. The spec, model arguments and upstream response are untrusted. Review destinations and operation semantics before enabling tools: method-derived risk hints cannot prove that an API is read-only. confirmDestructive is a persistent operator opt-in, not per-call user consent. A newly destructive operation is disabled on refresh; descriptions, schemas, names and annotations are regenerated, replacing manual overrides. New routes remain disabled even when an operation ID is reused. Deprecated enabled operations warn on serve stderr.

Relative or templated server URLs are rejected; provide an absolute HTTP(S) URL without credentials, query or fragment. Imports are limited to 4 MiB, 512 operations, 64 KiB per input schema, depth 40 100,000 expansion nodes and 8 MiB expanded string data; remote imports time out after 15 seconds. External refs are not fetched and recursive refs become placeholders. Review these incomplete schemas before use. Descriptions/titles have control and format characters removed and are capped at 1,000 characters. This does not neutralize prompt injection: run mcp-scan against the generated server before deployment and after refresh, and treat response text as untrusted data.

Only declared top-level parameters are serialized; unknown top-level arguments are dropped. Request bodies remain API payloads, without runtime JSON Schema validation or recursive filtering. Object/array path, query and header parameters use JSON strings; OpenAPI style/explode is not implemented. GET/HEAD bodies are omitted. Basic auth uses one environment variable containing user:pass. Custom auth headers cannot be overridden by model arguments. API-specific query credentials and semantic routing headers are not inferred: do not enable parameters that act as credentials, proxy destinations or routing overrides.

Responses are streamed up to the byte cap and cancelled when exceeded; redirects are unsuccessful results. Non-JSON content stays text (binary is decoded as UTF-8). Text plus structuredContent duplicates the bounded response; JSON escaping can increase wire size by a constant factor. Peer exception details are withheld. Exact raw and Basic-base64 credential echoes are redacted from response bodies/content types; transformed, split, or encoded secrets cannot reliably be recognized. The upstream necessarily receives configured auth: only use a trusted destination, and treat console/results as sensitive.

The console binds to loopback, checks Host and exact Origin when present, and limits call bodies to 256 KiB. It is not an authentication boundary against local processes. Rate limits use a rolling 60-second process-local window, including invalid attempts. serve reserves stdout for MCP; diagnostics go to stderr; CLI failures exit 1.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Turns OpenAPI specs into MCP tools with secure defaults, risk inspection, confirmation gates, response limits, audit logging, and secret redaction.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Convert any OpenAPI spec into a secure MCP server with scoped auth, per-tool allow/deny policies, rate limiting, and a redacted audit trail.
    10 npm
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables turning existing REST APIs into governed, agent-callable MCP servers by analyzing OpenAPI schemas, generating tool definitions, and gating releases behind automated evals.
    -