mcpify
English | Türkçe
Turn any OpenAPI REST API into an MCP server — so Claude Code, Cursor, and every other MCP client can call your API directly. One command. Zero dependencies.
Your company has a REST API. Your AI agent needs to call it. Until now that meant hand-writing a custom MCP server for every API. With mcpify:
mcpify serve https://your-company.com/openapi.json
That's it — every endpoint just became a tool your AI agent can discover, understand, and call.
Deep docs: Usage guide — auth patterns, scoping, Docker, troubleshooting · Architecture · Contributing · Changelog · Security
The launch story: How a live weather API broke this tool — and made it better
Why you'll like it
- 60 seconds to working — point it at any OpenAPI 3.x spec (file or URL)
- Credentials never touch the spec or the model — pulled from your
environment at call time (
--auth-env), sent asAuthorization: Bearer, a custom header, or a query parameter - Every operation becomes a first-class MCP tool — input schemas are
generated from
parameters+requestBody, internal$refs are resolved - Scope it down —
--read-only(GET only),--tag payments,--include /v1/orders,--exclude /admin, plus a policy layer for real-world APIs:--deny REGEXhides mutating GETs,--allow REGEXre-includes read-style POST endpoints. Deny always wins. mcpify doctor— tells you if your spec is agent-friendly before you ship- Operational, not just functional.
mcpify initwizard +.mcpify.tomlconfigs with per-environment sections, GET response caching (--cache-ttl), safe retries (--retry— idempotent methods only, 502/503/504 only), verbose/log-file logging with masked credentials, XML→JSON conversion, strict argument mode, origin auto-discovery, legacy batch tolerance, and a health probe (mcpify status/mcpify_health) - Zero dependencies — one pure-Python file tree; YAML specs need an
optional
pip install 'mcpify[yaml]' - Agent-grade surface. Tool annotations derived from HTTP semantics
(clients auto-approve read-only tools), structured output via MCP
outputSchema/structuredContent, remediation-grade errors that teach the next call, dry-run request previews, and a--lazysearch-then-call mode that cut api.weather.gov's listing by 95.5% (38,882 → 1,741 chars) - 162 tests across eleven suites — including a full MCP protocol run over stdio against a real local HTTP API and the live api.weather.gov document (69 tools, 16 enum'd parameters)
Quick start
# run without installing (uvx — pulls from PyPI on demand)
uvx --from mcpify-openapi mcpify list ./openapi.json --read-only
# first time? the wizard writes a config for you
uvx --from mcpify-openapi mcpify init
# or install (installs the `mcpify` command)
pipx install mcpify-openapi
# ...as a container (GHCR, published on every release)
docker run -i ghcr.io/furkan708/mcpify:latest serve ./openapi.json --read-only
# ...or from source
git clone https://github.com/furkan708/mcpify.git
cd mcpify && pip install .
# 1. preview the tools that will be generated
mcpify list examples/petstore.json
# 2. validate the spec is agent-friendly
mcpify doctor examples/petstore.json
# 3. serve it over MCP
mcpify serve examples/petstore.json --base-url https://petstore.example.com/v1
With authentication
# Bearer token read from the environment (never hardcoded)
export PETSTORE_KEY="sk-..."
mcpify serve petstore.json \
--base-url https://petstore.example.com/v1 \
--auth-env PETSTORE_KEY \
--auth-style bearer \
--read-only
| Flag | Meaning |
|---|---|
--auth-env VAR |
environment variable holding the credential |
--auth-style bearer|header|query |
how it is sent |
--auth-name NAME |
header / query name for non-bearer styles (e.g. X-API-Key) |
Plug it into your agent
Claude Code:
claude mcp add my-api -- mcpify serve openapi.json --read-only
Claude Desktop / Cursor / any MCP client (claude_desktop_config.json):
{
"mcpServers": {
"petstore": {
"command": "mcpify",
"args": ["serve", "~/specs/petstore.json", "--auth-env", "PETSTORE_KEY"]
}
}
}
Now ask your agent: "list the pets, then create one named Milo" — it discovers list_pets and create_pet, fills the arguments, and performs real HTTP calls.
How operations become tools
| OpenAPI | mcpify |
|---|---|
operationId |
tool name (sanitized; falls back to method_path) |
summary / description |
tool description the agent reads |
deprecated: true |
shown by mcpify list before you expose old endpoints |
parameters (path/query/header) |
individual typed arguments with enums |
requestBody (JSON) |
a body object argument |
$ref pointers |
resolved inline (components → real schemas) |
servers[0].url |
default base URL (override: --base-url) |
The agent only ever sees the tool list and your API's JSON responses — mcpify adds no middleware, caches nothing, and sends credentials nowhere except your API.
Doctor
$ mcpify doctor my-api.json
openapi: 3.0.3
title: Acme API
paths: 23
tools: 41 operations
servers: https://api.acme.com
warning: 12/41 operations have no operationId (names fall back to method_path)
warning: 30/41 operations have no summary (agents see no description)
CLI reference
mcpify list <spec> [--tag T] [--include P] [--exclude P] [--read-only] [--json]
mcpify serve <spec> [--base-url URL] [--name N] [--auth-env VAR]
[--auth-style bearer|header|query] [--auth-name NAME]
[--timeout S] [--read-only] [--tag T] [--include P] [--exclude P]
mcpify doctor <spec>
Notes & limitations
- JSON specs work out of the box; YAML specs need
pip install 'mcpify[yaml]' - Only local
$refpointers are resolved (bundle external docs first — most tools do anyway) - Request bodies are exposed as a single
bodyobject argument — predictable over clever - Spec versions: OpenAPI 3.x and Swagger 2.x roots are accepted; 3.x is the happy path
Hardened against the real world
mcpify is audited on every release against a 10-category checklist of MCP best practices and published production failure modes — not just our own examples:
- Hostile-spec corpus (12/12): circular
$refs, multipart uploads,allOfschemas, server URL variables, relative base URLs, oversized responses — every scenario derived from a documented real-world failure, fixed, and locked in by a regression test. Sources include the arXiv study of REST→MCP generation across 18 real APIs. - Live integration: the real api.weather.gov spec loads in CI — the case that found (and fixed) our last crash-class bug.
- MCP lifecycle enforced: tools are unreachable until the client
completes the
initializehandshake. - Blast-radius controls: read-only mode, deny/allow policy layer,
40k-char response truncation,
--timeout, credentials never logged.
Full checklist with per-item status: docs/AUDIT-CHECKLIST.md
Tests
162 passing, plus one live-integration test that loads the real
api.weather.gov document (auto-skipped when offline). Every suite runs on
Python 3.10–3.12 across Linux and Windows; ruff, strict mypy and
CodeQL gate every push.
| Suite | Tests | What it pins down |
|---|---|---|
| Spec parsing & resolution | 13 | OpenAPI 3.x + YAML loading, $ref chains, allOf merge, server variables, malformed input |
| Tool translation | 19 | operationId naming with collision suffixing, input schemas, enums, body handling, annotation & output-schema derivation |
| Agent surface | 31 | HTTP-derived annotations, structured output contract, remediation errors, --lazy search, dry-run previews |
| CLI | 15 | list / doctor / serve flags, --json output, deprecated badges |
| Hostile corpus | 11 | circular $refs, multipart bodies, relative base URLs, 300 KB truncation, 500-op performance — each traced to a documented real-world failure |
| Lifecycle & hygiene | 8 | initialize handshake (-32002), byte-pure stdio, credentials never logged |
| Protocol end-to-end | 9 | real JSON-RPC over stdio against a live local HTTP API, wire-level assertions |
| Policy layer | 7 | --read-only, --allow / --deny precedence, mutating-GET protection |
$ref parameters |
4 | parameter schemas resolved against the full spec — the weather.gov bug class (one test hits the live document) |
| Ops & configuration | 41 | config files + env precedence, init wizard, cache TTL & bounds, retry safety, XML conversion, discovery, batching, status/health |
| Protocol version compat | 5 | 2026-07-28 stateless _meta requests and the legacy 2025-06-18 handshake, on the same wire |
Policy on failures: every bug found in the wild becomes a pinned regression test before the fix ships — the suite only grows.
Run it locally:
pip install pytest pyyaml
pytest -v
Project Structure
mcpify/
├── mcpify/
│ ├── spec.py # OpenAPI loading, $ref resolution, operation walking
│ ├── tools.py # operation -> MCP tool, argument -> HTTP request
│ ├── http_client.py # execution (urllib, HTTP errors become tool results)
│ ├── api_server.py # MCP stdio server (JSON-RPC 2.0)
│ └── cli.py # list / serve / doctor
├── examples/petstore.json
└── tests/
Roadmap
-
--output-server FILE— generate a standalone, shareable server script - Per-operation rate limiting
- OAuth2 client-credentials flow
License
MIT — see the LICENSE file for details.
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 mcpify_openapi-1.5.1.tar.gz.
File metadata
- Download URL: mcpify_openapi-1.5.1.tar.gz
- Upload date:
- Size: 60.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
126c2f4a48d8d582f18c635f150ab2eb8bb9938a69954bf277421f94d5bdf43d
|
|
| MD5 |
8d859a7edea458dbf0ea3c3cfabd0f6f
|
|
| BLAKE2b-256 |
4dffb0840e93787e0e7f2788f45e2077955356b87c79689b7ecd0c1ca98ccdaa
|
Provenance
The following attestation bundles were made for mcpify_openapi-1.5.1.tar.gz:
Publisher:
release.yml on furkan708/mcpify
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcpify_openapi-1.5.1.tar.gz -
Subject digest:
126c2f4a48d8d582f18c635f150ab2eb8bb9938a69954bf277421f94d5bdf43d - Sigstore transparency entry: 2640857646
- Sigstore integration time:
-
Permalink:
furkan708/mcpify@13c6a46fc4f106f9dfa4efd4c8fb7f6584cb4b74 -
Branch / Tag:
refs/tags/v1.5.1 - Owner: https://github.com/furkan708
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@13c6a46fc4f106f9dfa4efd4c8fb7f6584cb4b74 -
Trigger Event:
push
-
Statement type:
File details
Details for the file mcpify_openapi-1.5.1-py3-none-any.whl.
File metadata
- Download URL: mcpify_openapi-1.5.1-py3-none-any.whl
- Upload date:
- Size: 39.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ec7a858d5577621f4766f8f2050ad220b64295e47d5c189cb3040f34db7c8f1
|
|
| MD5 |
02bdaa526e5f148e4101d14923ab2480
|
|
| BLAKE2b-256 |
a19929a313a0382302e3bb3a6b81b4275c68b19633fb75cb36af40164a549b01
|
Provenance
The following attestation bundles were made for mcpify_openapi-1.5.1-py3-none-any.whl:
Publisher:
release.yml on furkan708/mcpify
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcpify_openapi-1.5.1-py3-none-any.whl -
Subject digest:
6ec7a858d5577621f4766f8f2050ad220b64295e47d5c189cb3040f34db7c8f1 - Sigstore transparency entry: 2640857675
- Sigstore integration time:
-
Permalink:
furkan708/mcpify@13c6a46fc4f106f9dfa4efd4c8fb7f6584cb4b74 -
Branch / Tag:
refs/tags/v1.5.1 - Owner: https://github.com/furkan708
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@13c6a46fc4f106f9dfa4efd4c8fb7f6584cb4b74 -
Trigger Event:
push
-
Statement type: