api2mcp
Turn any OpenAPI spec into a working MCP server. One command.
api2mcp https://petstore3.swagger.io/api/v3/openapi.json
That's it. You now have a runnable MCP server exposing every endpoint in that API as a tool an LLM agent can call — typed arguments, docstrings, auth wiring, all generated.
The problem
Want Claude (or any MCP-compatible agent) to use Stripe, GitHub, your internal REST API, whatever? Right now that means hand-writing an MCP server: read the docs, define a tool per endpoint, map params, wire up auth, keep it in sync when the API changes.
Almost every API already publishes an OpenAPI/Swagger spec describing exactly that shape. api2mcp reads it and generates the server for you.
Install
pip install spec2mcp
(The PyPI package is named spec2mcp — api2mcp was already taken. The CLI command and import name are still api2mcp.)
Usage
api2mcp <spec-url-or-file> [-o output-dir]
Works with a spec URL, a local .json file, or a local .yaml/.yml file.
Example
$ api2mcp https://petstore3.swagger.io/api/v3/openapi.json -o ./petstore-mcp
Fetching spec from https://petstore3.swagger.io/api/v3/openapi.json ...
Generated 19 tools for 'Swagger Petstore - OpenAPI 3.0'
-> petstore-mcp/server.py
-> petstore-mcp/README.md
Run it:
cd petstore-mcp && pip install "mcp[cli]" requests && python server.py
Run the generated server, then point any MCP client at it — Claude Desktop, Claude Code, or your own agent — and every endpoint (findPetsByStatus, addPet, deletePet, …) is now a callable tool.
Point Claude Desktop / Claude Code at it
Add to your MCP client config (e.g. claude_desktop_config.json):
{
"mcpServers": {
"petstore": {
"command": "python",
"args": ["/absolute/path/to/petstore-mcp/server.py"],
"env": {
"API_BASE_URL": "https://petstore3.swagger.io/api/v3",
"API_KEY": "your-key-if-needed"
}
}
}
}
Auth
Set env vars before running the generated server:
API_BASE_URL— overrides the base URL detected from the specAPI_KEY— sent asAuthorization: Bearer <API_KEY>on every request
Use it as a library instead of the CLI
from api2mcp import parse_spec, write_server
spec = parse_spec("https://petstore3.swagger.io/api/v3/openapi.json")
write_server(spec, "./out")
What gets generated
For every operation in the spec, one @mcp.tool()-decorated function:
@mcp.tool()
def findpetsbystatus(status: str = "") -> dict:
"""Finds Pets by status."""
...
resp = requests.request("GET", url, params=params, json=json_body, headers=_headers(), timeout=30)
resp.raise_for_status()
return resp.json()
- Path, query, and JSON body params become typed Python arguments (required params ordered before optional ones, so it's always valid Python)
- The
summary/descriptionfrom the spec becomes the tool's docstring — that's what the LLM sees when deciding whether to call it - A
README.mdlisting every generated tool ships alongsideserver.py
The output is plain, readable code — not a black box. Generate it, read it, edit it by hand if you need something custom.
How it works
- Parse (
api2mcp/parser.py) — loads the spec (JSON or YAML, URL or file), walkspaths, flattens each operation's parameters and request body into a simple typedOperationmodel. - Generate (
api2mcp/generator.py+templates/server.py.j2) — renders a Jinja2 template into a single-file MCP server using the officialmcpPython SDK. - Run — the generated server is a normal Python script;
mcp.run()speaks the MCP protocol over stdio.
No LLM calls involved in generation — it's pure codegen from the spec's structure, so it's fast, free, and deterministic.
Development
git clone https://github.com/azamoviich/api2mcp
cd api2mcp
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,serve]"
pytest
Limitations (v1)
- No OAuth2 flows — only static bearer token auth via
API_KEY $refresolution for request bodies is shallow (one level)- No pagination helpers — generated tools return raw responses as-is
Contributions welcome for any of the above.
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spec2mcp-0.1.0.tar.gz.
File metadata
- Download URL: spec2mcp-0.1.0.tar.gz
- Upload date:
- Size: 8.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef651bf19d9ac5e179842d297ae257f2425f941d05a6d9905238a18345424ac1
|
|
| MD5 |
2479740eb801a93e752ec8264d8f9886
|
|
| BLAKE2b-256 |
2613c57381677f3b5dcaa5c1de9fd5f96d7a34aec4be798553780813f1e8c038
|
File details
Details for the file spec2mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: spec2mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
583af45306bc146b5e21a2e7c1b239cf8d970a86160f5afabb9214efd0d69a36
|
|
| MD5 |
cd4415af267445bc917e499fef4e78da
|
|
| BLAKE2b-256 |
bb2befc1e4548f9179f16a21f093ac76e768739696c1682c7c11f03bbc18072c
|