DEV Community

Shadab Khan
Shadab Khan

Posted on

Turn Any OpenAPI Spec into Safe MCP Tools for Claude in Seconds

If you've tried connecting REST APIs to AI agents, you've probably hit this moment:

The MCP server starts. Claude sees the tools. You ask it to fetch some data.

And it calls the wrong endpoint. Or fires a DELETE it shouldn't. Or gets confused between two tools that look similar and just... picks one.

Your spec passed every linter. The conversion worked fine.

The agent still broke.

This is the gap nobody talks about. OpenAPI specs were designed for human developers who can read vague documentation, infer intent, and apply common sense. AI agents can't do any of that. They need:

  • Every endpoint to have a clear, unambiguous name (operationId)
  • Descriptions that say when to call a tool, not just what it does
  • Explicit safety signals on destructive operations
  • No two tools that look similar enough to cause confusion

Standard linters don't check for any of this. So the spec looks clean, the linter passes green, and the agent quietly makes bad decisions.

That's the problem I kept hitting. So I built mcp-openapi-doctor to fix it.


What mcp-openapi-doctor Does

It's a CLI tool with four commands that take a raw OpenAPI or Swagger spec and make it genuinely agent-ready.

OpenAPI spec → mcp-openapi-doctor → cleaned spec + MCP overlay → your MCP server → Claude
Enter fullscreen mode Exit fullscreen mode

It's a preprocessor, not a replacement. It fits in front of whatever MCP tooling you're already using — AWS OpenAPI MCP, FastMCP, Tyk, or your own server.


Step 1: Inspect — See Your Agent-Readiness Score

The first thing you want to know is how broken your spec actually is for agent use.

npx mcp-openapi-doctor inspect https://petstore3.swagger.io/api/v3/openapi.json
Enter fullscreen mode Exit fullscreen mode

You get a score from 0–100 broken into three dimensions:

MCP OpenAPI Doctor 🩺
─────────────────────────────────────
API:        Petstore API v1.0.0
Operations: 19 across 9 paths
Version:    OpenAPI 3.0.3

Agent-readiness score: 61/100

Safety       ████░░░░░░  24/40
Clarity      ███░░░░░░░  21/35
Efficiency   █████░░░░░  16/25

Issues found:
  ✗ error   6x missing operationId
  ✗ error   3x destructive endpoint without warning
  ⚠ warn    8x vague or missing description
  ⚠ warn    1x response schema exceeds 30 fields
Enter fullscreen mode Exit fullscreen mode

These aren't style issues. Each one is a real agent failure mode:

Issue What actually happens
Missing operationId Agent has no stable tool name to reference
Destructive endpoint without warning Agent fires DELETE with no hesitation
Tool name collision LLM picks between two similar tools arbitrarily
Vague description Agent calls the wrong tool because intent isn't clear
Response schema bloat (80+ fields) Burns context window, degrades reasoning quality

Step 2: Generate — Preview Exactly What Claude Will See

Before running a server, generate shows you the exact tools Claude will have access to — names, descriptions, inputs, and safety classification.

npx mcp-openapi-doctor generate ./openapi.yaml
Enter fullscreen mode Exit fullscreen mode
Generated tools: 4

✓ list_users
  Operation: GET /users
  Safety:    SAFE_READ
  Inputs:    none

✓ get_user
  Operation: GET /users/{id}
  Safety:    SAFE_READ
  Inputs:    id*

⚠ update_user
  Operation: PUT /users/{id}
  Safety:    WRITE
  Inputs:    id*, body

✗ delete_user
  Operation: DELETE /users/{id}
  Safety:    DESTRUCTIVE
  Inputs:    id*
Enter fullscreen mode Exit fullscreen mode

Use --read-only to see only the tools that would be exposed in safe mode:

npx mcp-openapi-doctor generate ./openapi.yaml --read-only
# Only SAFE_READ tools appear — WRITE and DESTRUCTIVE are hidden from the agent
Enter fullscreen mode Exit fullscreen mode

This is useful when you're scoping what you want Claude to access before you open up write operations.


Step 3: Fix — Auto-Fix What's Safe to Fix

fix generates a cleaned spec in an output folder. It never modifies your original file.

npx mcp-openapi-doctor fix ./openapi.yaml --out ./output/ --diff
Enter fullscreen mode Exit fullscreen mode

What gets generated:

output/
├── cleaned-openapi.yaml    ← patched spec with fixes applied
├── mcp-overlay.yaml        ← x-mcp-* metadata for downstream MCP servers
├── doctor-report.json      ← structured issues + score
├── fixes.md                ← human-readable log of every change
├── summary.md              ← before/after score + remaining actions
├── diff.md                 ← readable diff of every change
└── diff.json               ← structured diff for tooling
Enter fullscreen mode Exit fullscreen mode

What the fixer will safely change:

  • Generate missing operationId from method + path, slugified and deduplicated
  • Normalize all operationId values to snake_case
  • Add fallback summaries where missing
  • Inject x-mcp-destructive: true on DELETE endpoints
  • Add placeholder schemas for missing request bodies and responses

What it will never do:

  • Remove any endpoint
  • Change runtime behavior
  • Touch your source file
  • Use AI to rewrite anything (all fixes are deterministic)

The summary.md shows you the before/after score and what still needs a human:

Before: 61/100
After:  88/100

Fixed automatically:
  ✓ 6 missing operationIds generated
  ✓ 3 destructive endpoints flagged with x-mcp-destructive
  ✓ 4 missing summaries added

Still needs your attention:
  ⚠ 8 vague descriptions — these need human context to fix well
  ⚠ 1 response schema with 87 fields — consider a filtered endpoint
Enter fullscreen mode Exit fullscreen mode

Step 4: Serve — Connect Directly to Claude Desktop

Once your spec is clean, serve starts an MCP stdio server that Claude Desktop connects to directly.

npx mcp-openapi-doctor serve ./openapi.yaml --read-only
Enter fullscreen mode Exit fullscreen mode

The terminal will look idle — that's expected. It's waiting for an MCP client over stdio.

Add it to your Claude Desktop config:

{
  "mcpServers": {
    "my-api": {
      "command": "npx",
      "args": [
        "mcp-openapi-doctor",
        "serve",
        "/absolute/path/to/openapi.yaml",
        "--read-only"
      ],
      "env": {
        "API_TOKEN": "your_token_here"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Restart Claude Desktop and ask: What tools do you have available?

The tools from your spec appear. Claude can call your actual REST API through them.


The Safety Model

Every endpoint is classified before it's exposed:

GET                          →  SAFE_READ    ✓ exposed in --read-only
POST / PUT / PATCH           →  WRITE        ✗ hidden in --read-only  
DELETE                       →  DESTRUCTIVE  ✗ hidden in --read-only
Paths with admin/billing/
payment/secret/token/
credential                   →  SENSITIVE    ✗ hidden in --read-only
Enter fullscreen mode Exit fullscreen mode

--read-only is the recommended mode when you're first exposing an API to an agent. Let Claude explore and read before you decide which write operations to open up.


Works With Your Existing MCP Stack

Because it outputs a standard cleaned OpenAPI spec, the output drops straight into whatever you're already using:

# Clean first
npx mcp-openapi-doctor fix ./stripe.yaml --out ./output/

# Then feed cleaned spec to your preferred MCP server
npx @aws/openapi-mcp-server --spec ./output/cleaned-openapi.yaml
# or fastmcp, tyk, your own server
Enter fullscreen mode Exit fullscreen mode

The mcp-overlay.yaml contains x-mcp-* extensions that compatible servers can read for additional agent hints.


Try It Now — Five Real Examples

The repo ships with five fixture specs covering a range of quality levels:

git clone https://github.com/yourname/mcp-openapi-doctor
cd mcp-openapi-doctor
pnpm install && pnpm build

# A clean, well-described read-only API — should score 90+
pnpm start -- inspect ./examples/clean-read-api.yaml

# An intentionally broken CRM API — good for seeing all the checks fire
pnpm start -- inspect ./examples/risky-crm-api.yaml
pnpm start -- fix ./examples/risky-crm-api.yaml --out .output/ --diff

# Swagger 2.0 compatibility
pnpm start -- inspect ./examples/swagger-2-api.json

# The classic Petstore
pnpm start -- serve ./examples/simple-openapi.yaml --read-only
Enter fullscreen mode Exit fullscreen mode

Or just run it against any public API right now:

# GitHub API
npx mcp-openapi-doctor inspect https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json

# Petstore
npx mcp-openapi-doctor inspect https://petstore3.swagger.io/api/v3/openapi.json
Enter fullscreen mode Exit fullscreen mode

What's Coming Next

Phase 1 is shipped. On the roadmap for Phase 2:

  • Web UI — paste a spec URL, see issues highlighted inline, download the fixed spec
  • AI-powered description hints--ai-hints flag that uses an LLM to suggest better agent-oriented descriptions for vague endpoints
  • GitHub Action — gate your CI on a minimum agent-readiness score
  • VS Code extension — inline diagnostics while editing a spec file
  • Custom rule plugins — bring your own rules as JS modules for internal API conventions

The One-Line Summary

Your API spec passes Spectral. But will Claude use it safely?

mcp-openapi-doctor finds what linters miss.

If you're building anything in the MCP or AI agent space, give it a try and let me know what you find — especially if you hit a spec it handles badly or a check it's missing.

GitHub: github.com/yourname/mcp-openapi-doctor

If this saves you from a broken agent call, a ⭐ on the repo goes a long way. It helps other developers find it when they hit the same wall.


Built in TypeScript. Zero install via npx. MIT licensed.

Top comments (0)