{"slug": "show-hn-mcpgen-turn-openapi-postman-specs-into-python-mcp-servers", "title": "Show HN: Mcpgen – Turn OpenAPI/Postman Specs into Python MCP Servers", "summary": "Mcpgen, a new open-source CLI tool, generates a complete Python MCP server from an OpenAPI spec or Postman collection, producing source code users own with no runtime dependency on mcpgen. The tool, installable via pip install mcpgen-cli, outputs a self-contained directory with server.py and requirements.txt that can be run immediately, and it supports OpenAPI 3.x JSON/YAML, Postman Collection v2.1, and auto-detects auth schemes like Bearer token, API Key, and Basic Auth.", "body_md": "Point `mcpgen`\n\nat 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.\n\n```\npip install mcpgen-cli\n# From a URL\nmcpgen https://petstore3.swagger.io/api/v3/openapi.json\n\n# From a local OpenAPI file (JSON or YAML)\nmcpgen stripe.yaml\n\n# From a Postman collection\nmcpgen postman_collection.json\n\n# Preview without writing anything\nmcpgen openapi.json --dry-run\n\n# Custom output directory and server name\nmcpgen openapi.json --output ~/my-mcp-servers --name \"My API\"\n```\n\nThat's it. `mcpgen`\n\nreads your spec and writes a Python MCP server to disk.\n\nA self-contained directory with source code you own:\n\n```\nstripe_api_mcp/\n├── server.py          ← the MCP server (read it, edit it, it's yours)\n└── requirements.txt   ← httpx, mcp\n```\n\n**Run it immediately:**\n\n```\ncd stripe_api_mcp\npip install -r requirements.txt\nexport STRIPE_API_TOKEN=\"sk_live_...\"\npython server.py\n```\n\n**The generated server.py looks like this:**\n\n``` bash\n#!/usr/bin/env python3\n\"\"\"\nStripe API MCP Server\nGenerated by mcpgen — https://github.com/JnanaSrota/mcpgen\nThis file is yours. Modify it freely.\n\"\"\"\nimport os, asyncio, httpx\nfrom mcp.server import Server\nfrom mcp.server.stdio import stdio_server\nfrom mcp import types\n\nBASE_URL = \"https://api.stripe.com\"\nAUTH_TOKEN = os.environ.get(\"STRIPE_API_TOKEN\", \"\")\n\napp = Server(\"stripe-api\")\n\n@app.call_tool()\nasync def _handle_get_customers(name: str, arguments: dict):\n    if name != \"get_customers\":\n        raise ValueError(f\"Unknown tool: {name}\")\n    url = BASE_URL + \"/v1/customers\"\n    query_params = {}\n    if \"limit\" in arguments:\n        query_params[\"limit\"] = arguments[\"limit\"]\n    async with httpx.AsyncClient(timeout=30.0) as client:\n        response = await client.get(url, params=query_params,\n            headers={\"Authorization\": f\"Bearer {AUTH_TOKEN}\"})\n        response.raise_for_status()\n        return [types.TextContent(type=\"text\", text=response.text)]\n\n# ... one function per API endpoint\n\n@app.list_tools()\nasync def list_tools(): ...\n\nif __name__ == \"__main__\":\n    asyncio.run(stdio_server(app))\n```\n\nNo black box. No dependencies at runtime. Just Python.\n\n`mcpgen`\n\nprints the exact config snippet to paste into your `claude_desktop_config.json`\n\n:\n\n```\n{\n  \"mcpServers\": {\n    \"stripe-api-mcp\": {\n      \"command\": \"python\",\n      \"args\": [\"/path/to/stripe_api_mcp/server.py\"],\n      \"env\": { \"STRIPE_API_TOKEN\": \"your-key-here\" }\n    }\n  }\n}\n```\n\n**Config file location:**\n\n- macOS:\n`~/Library/Application Support/Claude/claude_desktop_config.json`\n\n- Windows:\n`%APPDATA%\\Claude\\claude_desktop_config.json`\n\nMost API-to-MCP tools are **runtime proxies** — they sit between Claude and your API forever, and you depend on them to stay running.\n\n`mcpgen`\n\ngenerates **source code you own**. The output is a plain Python file. You can:\n\n- Read every line of what's happening\n- Modify auth logic, add retries, adjust error handling\n- Deploy it anywhere without any dependency on\n`mcpgen`\n\n- Commit it to your own repo, version it, review it in PRs\n\n`mcpgen`\n\nis a build tool. Needed once, at generation time. Never at runtime.\n\n| Format | Example |\n|---|---|\n| OpenAPI 3.x JSON | `mcpgen openapi.json` |\n| OpenAPI 3.x YAML | `mcpgen api.yaml` |\n| URL pointing to OpenAPI spec | `mcpgen https://api.example.com/openapi.json` |\n| Postman Collection v2.1 | `mcpgen collection.json` |\n\n**Tested with:**\n\n[Petstore](https://petstore3.swagger.io/api/v3/openapi.json)— 19 endpoints → 19 tools- GitHub REST API (subset)\n- Stripe API (subset)\n- Any valid OpenAPI 3.x spec\n\n`mcpgen`\n\nauto-detects your API's auth scheme from the spec:\n\n| Scheme | OpenAPI declaration | Generated env var |\n|---|---|---|\n| Bearer token | `type: http, scheme: bearer` |\n`YOUR_API_TOKEN` |\n| API Key | `type: apiKey` |\n`YOUR_API_API_KEY` |\n| Basic Auth | `type: http, scheme: basic` |\n`YOUR_API_CREDENTIALS` |\n| None | No `securitySchemes` |\n— |\n\nOAuth2 flows are approximated as bearer token — you supply the token manually.\n\n```\nUsage: mcpgen [OPTIONS] INPUT\n\n  Turn any API into an MCP server in 30 seconds.\n\nArguments:\n  INPUT  OpenAPI JSON/YAML file, Postman collection, or URL  [required]\n\nOptions:\n  -o, --output PATH   Output directory (default: current directory)\n  -n, --name TEXT     Override the generated server name\n  --dry-run           Print generated code without writing files\n  --no-color          Disable colored output\n  -v, --version       Show version and exit\n  --help              Show this message and exit\n```\n\n- TypeScript output (\n`--lang ts`\n\n) using`@modelcontextprotocol/sdk`\n\n- Swagger 2.x support (auto-detected, separate parser)\n- Auto-detect OpenAPI URL from base domain (\n`/.well-known/openapi.json`\n\n,`/api-docs`\n\n, etc.) -\n`--update-claude-config`\n\nflag to patch`claude_desktop_config.json`\n\nautomatically - Recursive\n`$ref`\n\nresolution for deeply nested schemas\n\nPRs welcome. See [CONTRIBUTING.md](/JnanaSrota/mcpgen/blob/main/CONTRIBUTING.md).\n\n```\ngit clone https://github.com/JnanaSrota/mcpgen\ncd mcpgen\npip install -e \".[dev]\"\npytest tests/ -v\n```\n\nThe codebase has three clean layers:\n\n```\nInput (file / URL)\n    ↓\nloader.py              ← detects format, routes to correct parser\n    ↓\nopenapi.py / postman.py   ← parse to MCPSpec (internal IR)\n    ↓\ngenerator/python.py       ← renders Jinja2 templates → server.py\n```\n\nTo add a new input format: write a parser that returns `MCPSpec`\n\n. Nothing else changes.\nTo add a new output language: write a generator that consumes `MCPSpec`\n\n. Nothing else changes.\n\nMIT — the generated code is yours to do whatever you want with.", "url": "https://wpnews.pro/news/show-hn-mcpgen-turn-openapi-postman-specs-into-python-mcp-servers", "canonical_source": "https://github.com/JnanaSrota/mcpgen", "published_at": "2026-07-23 05:09:47+00:00", "updated_at": "2026-07-23 05:22:17.586784+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools"], "entities": ["mcpgen", "OpenAPI", "Postman", "Python", "Claude", "Stripe", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/show-hn-mcpgen-turn-openapi-postman-specs-into-python-mcp-servers", "markdown": "https://wpnews.pro/news/show-hn-mcpgen-turn-openapi-postman-specs-into-python-mcp-servers.md", "text": "https://wpnews.pro/news/show-hn-mcpgen-turn-openapi-postman-specs-into-python-mcp-servers.txt", "jsonld": "https://wpnews.pro/news/show-hn-mcpgen-turn-openapi-postman-specs-into-python-mcp-servers.jsonld"}}