mcpgen MCP Server

CLI tool that generates MCP servers from OpenAPI/Postman specs — pip install mcpgen-cli

Documentation

mcpgen

Turn any API into an MCP server in 30 seconds.

PyPI version Python License: MIT MCP GitHub stars CI


mcpgen demo

Point mcpgen at an OpenAPI spec or Postman collection. Get back a complete Python MCP server you own — no runtime dependency on mcpgen, no proxy, no lock-in. Read it. Modify it. Ship it.


Install

pip install mcpgen-cli

Quickstart

# From a URL
mcpgen https://petstore3.swagger.io/api/v3/openapi.json

# From a local OpenAPI file (JSON or YAML)
mcpgen stripe.yaml

# From a Postman collection
mcpgen postman_collection.json

# Preview without writing anything
mcpgen openapi.json --dry-run

# Custom output directory and server name
mcpgen openapi.json --output ~/my-mcp-servers --name "My API"

That's it. mcpgen reads your spec and writes a Python MCP server to disk.


What you get

A self-contained directory with source code you own:

stripe_api_mcp/
├── server.py          ← the MCP server (read it, edit it, it's yours)
└── requirements.txt   ← httpx, mcp

Run it immediately:

cd stripe_api_mcp
pip install -r requirements.txt
export STRIPE_API_TOKEN="sk_live_..."
python server.py

The generated server.py looks like this:

#!/usr/bin/env python3
"""
Stripe API MCP Server
Generated by mcpgen — https://github.com/JnanaSrota/mcpgen
This file is yours. Modify it freely.
"""
import os, asyncio, httpx
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types

BASE_URL = "https://api.stripe.com"
AUTH_TOKEN = os.environ.get("STRIPE_API_TOKEN", "")

app = Server("stripe-api")

@app.call_tool()
async def _handle_get_customers(name: str, arguments: dict):
    if name != "get_customers":
        raise ValueError(f"Unknown tool: {name}")
    url = BASE_URL + "/v1/customers"
    query_params = {}
    if "limit" in arguments:
        query_params["limit"] = arguments["limit"]
    async with httpx.AsyncClient(timeout=30.0) as client:
        response = await client.get(url, params=query_params,
            headers={"Authorization": f"Bearer {AUTH_TOKEN}"})
        response.raise_for_status()
        return [types.TextContent(type="text", text=response.text)]

# ... one function per API endpoint

@app.list_tools()
async def list_tools(): ...

if __name__ == "__main__":
    asyncio.run(stdio_server(app))

No black box. No dependencies at runtime. Just Python.


Add to Claude Desktop

mcpgen prints the exact config snippet to paste into your claude_desktop_config.json:

{
  "mcpServers": {
    "stripe-api-mcp": {
      "command": "python",
      "args": ["/path/to/stripe_api_mcp/server.py"],
      "env": { "STRIPE_API_TOKEN": "your-key-here" }
    }
  }
}

Config file location:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Why source code instead of a proxy?

Most API-to-MCP tools are runtime proxies — they sit between Claude and your API forever, and you depend on them to stay running.

mcpgen generates source code you own. The output is a plain Python file. You can:

  • Read every line of what's happening
  • Modify auth logic, add retries, adjust error handling
  • Deploy it anywhere without any dependency on mcpgen
  • Commit it to your own repo, version it, review it in PRs

mcpgen is a build tool. Needed once, at generation time. Never at runtime.


Supported inputs

FormatExample
OpenAPI 3.x JSONmcpgen openapi.json
OpenAPI 3.x YAMLmcpgen api.yaml
URL pointing to OpenAPI specmcpgen https://api.example.com/openapi.json
Postman Collection v2.1mcpgen collection.json

Tested with:

  • Petstore — 19 endpoints → 19 tools
  • GitHub REST API (subset)
  • Stripe API (subset)
  • Any valid OpenAPI 3.x spec

Auth support

mcpgen auto-detects your API's auth scheme from the spec:

SchemeOpenAPI declarationGenerated env var
Bearer tokentype: http, scheme: bearerYOUR_API_TOKEN
API Keytype: apiKeyYOUR_API_API_KEY
Basic Authtype: http, scheme: basicYOUR_API_CREDENTIALS
NoneNo securitySchemes

OAuth2 flows are approximated as bearer token — you supply the token manually.


CLI reference

Usage: mcpgen [OPTIONS] INPUT

  Turn any API into an MCP server in 30 seconds.

Arguments:
  INPUT  OpenAPI JSON/YAML file, Postman collection, or URL  [required]

Options:
  -o, --output PATH   Output directory (default: current directory)
  -n, --name TEXT     Override the generated server name
  --dry-run           Print generated code without writing files
  --no-color          Disable colored output
  -v, --version       Show version and exit
  --help              Show this message and exit

Roadmap

  • TypeScript output (--lang ts) using @modelcontextprotocol/sdk
  • Swagger 2.x support (auto-detected, separate parser)
  • Auto-detect OpenAPI URL from base domain (/.well-known/openapi.json, /api-docs, etc.)
  • --update-claude-config flag to patch claude_desktop_config.json automatically
  • Recursive $ref resolution for deeply nested schemas

PRs welcome. See CONTRIBUTING.md.


Contributing

git clone https://github.com/JnanaSrota/mcpgen
cd mcpgen
pip install -e ".[dev]"
pytest tests/ -v

The codebase has three clean layers:

Input (file / URL)
    ↓
loader.py              ← detects format, routes to correct parser
    ↓
openapi.py / postman.py   ← parse to MCPSpec (internal IR)
    ↓
generator/python.py       ← renders Jinja2 templates → server.py

To add a new input format: write a parser that returns MCPSpec. Nothing else changes. To add a new output language: write a generator that consumes MCPSpec. Nothing else changes.


License

MIT — the generated code is yours to do whatever you want with.