create-mcp
The create-next-app for production MCP servers.
One command scaffolds a typed, tested, auth-ready Python MCP server you can ship — not just run.
uvx create-mcp my-server
Why
The official MCP SDK quickstart and create-mcp-server hand you a single
hello-world tool and stop. You still have to add tests, typing, linting, CI, a
Dockerfile, config, and — the hard one — spec-compliant OAuth 2.1. Most MCP
servers in the wild are hello-world demos that never reach production.
create-mcp generates the whole repo, green on the first run:
- ⚡
uvx create-mcp— zero install. Same ergonomics ascreate-next-app. - 🧱 Production defaults, not a toy. Tests, CI, Docker, ruff, mypy, pre-commit,
.env, a real README. - 🔐 OAuth 2.1 in one flag.
--auth oauthscaffolds an RFC 9728 resource server (Protected Resource Metadata +401/WWW-Authenticatediscovery + JWT validation). Timed for the 2026 MCP authorization spec. - 🌊 Streamable HTTP first. The modern transport (SSE is deprecated), plus a stdio preset for Claude Desktop / Cursor.
- 🧪 Tests pass out of the box. Generated tests use FastMCP's in-memory client — no network, milliseconds.
- 🎯 Presets, not questionnaires. Scaffold a use case:
minimal,api-wrapper,db,agent-tools. - 📄
--from-openapi. Point it at a spec and get one typed tool per operation — enums asLiteral, request bodies flattened into named arguments, descriptions carried into the docstrings. - 🐍 Typed end-to-end. Pydantic models for tool I/O; ruff- and mypy-clean.
Usage
# Interactive
uvx create-mcp
# Scripted / non-interactive
uvx create-mcp pay-tools --preset api-wrapper --auth oauth --yes
# From an OpenAPI document — one typed tool per operation
uvx create-mcp stripe-tools --from-openapi ./openapi.json --yes
Then:
cd pay-tools
uv sync
uv run pay_tools # start the server
uv run pytest # green ✓
Options
| Flag | Values | Default | Description |
|---|---|---|---|
--preset -p |
minimal, api-wrapper, db, agent-tools |
minimal |
Starting set of tools/resources/prompts |
--from-openapi |
file path or URL | — | Generate one typed tool per operation from a spec |
--openapi-tag |
tag name (repeatable) | — | Only include operations carrying that OpenAPI tag |
--transport -t |
streamable-http, stdio |
streamable-http |
MCP transport |
--auth -a |
none, oauth |
none |
OAuth 2.1 resource server (RFC 9728) |
--package-name |
identifier | derived | Override the Python package name |
--output-dir -o |
path | . |
Where to create the project |
--no-git / --git |
--git |
Initialise a git repo + first commit | |
--no-install / --install |
--install |
Run uv sync after scaffolding |
|
--no-precommit / --precommit |
--precommit |
Install pre-commit hooks | |
--force |
off | Overwrite a non-empty target directory | |
--yes -y |
off | Accept all defaults; never prompt (CI) |
Presets
| Preset | What you get |
|---|---|
| minimal | A clean typed server: one tool (structured output), a resource, a prompt. |
| api-wrapper | Wrap an HTTP/JSON API as MCP tools, with the network call isolated for easy mocking. |
| db | A SQLite-backed store exposed as CRUD tools (swap in your real DB). |
| agent-tools | A toolbox for agents: safe calculator, scratchpad memory, clock. |
From an OpenAPI document
Point --from-openapi at a JSON or YAML spec — a local file or a URL — and every
operation becomes a typed MCP tool:
uvx create-mcp petstore-tools --from-openapi https://petstore3.swagger.io/api/v3/openapi.json --yes
# src/petstore_tools/tools.py — generated
@mcp.tool
async def find_pets_by_status(status: Literal["available", "pending", "sold"]) -> Any:
"""Finds Pets by status.
Args:
status: Status values that need to be considered for filter.
"""
return await _request("GET", "/pet/findByStatus", query={"status": status})
What it carries over from the spec:
- Real types.
integer→int,array→list[str], and anenumbecomes aLiteral— so the client validates the argument instead of the API rejecting it. - Required vs optional. Optional parameters get
| None = Noneand are dropped from the request when unset, rather than sent as literalnull. - Request bodies, flattened. A JSON object body becomes named arguments, so the model
can see what the endpoint wants. Non-object bodies fall back to a single
bodyargument. - Descriptions. Operation summaries and parameter descriptions become the docstring — which is exactly what an MCP client shows the model when it picks a tool.
- Auth. A declared
bearerorapiKeyscheme wires upAPI_TOKEN/API_KEYfrom the environment.
Every call routes through one _request function, so the generated tests/test_tools.py
patches that and runs offline — no key, no network, still green on the first run.
YAML specs
JSON works on the standard library. YAML needs PyYAML:
uvx --from 'create-mcp[yaml]' create-mcp my-server --from-openapi ./openapi.yaml
Big specs
A 200-operation API makes a bad MCP server: long tool lists eat the model's context and measurably hurt tool selection. Narrow it at generation time —
uvx create-mcp stripe-tools --from-openapi ./stripe.json --openapi-tag Invoice --openapi-tag Customer
— and delete what you don't need from tools.py afterwards. It's ordinary Python; the
generator hands you a starting point, not a binding.
Scope, honestly. This is a pragmatic subset, not a full OpenAPI implementation. Local
$refs, scalars, arrays and enums are resolved; remote$refs,allOfmerging and polymorphic discriminators degrade todict[str, Any]rather than failing. Deprecated operations are skipped. Responses are returned as decoded JSON, not modelled.
What the generated project looks like
my-server/
├── src/my_server/
│ ├── server.py # FastMCP instance (+ /health, + auth when enabled)
│ ├── tools.py # your tools, resources, prompts
│ ├── settings.py # typed config (pydantic-settings)
│ ├── app.py # FastAPI host mounting MCP at /mcp
│ ├── auth.py # OAuth 2.1 resource server (only with --auth oauth)
│ └── __main__.py # `uv run my_server`
├── tests/ # in-memory tests, green out of the box
├── Dockerfile # uv-based image
├── .github/workflows/ci.yml
├── .pre-commit-config.yaml
├── .env.example
└── pyproject.toml
Requirements
uv(foruvxand the generated projects)- Python 3.11+
Contributing
See CONTRIBUTING.md. Every release runs the full matrix — generating a project for each preset × auth mode, then installing, linting, type-checking and testing it — so the templates can't rot silently.
License
MIT © Shaxzodbek Qambaraliyev / Blaze
Release files for create-mcp 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| create_mcp-0.2.0.tar.gz | 35.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| create_mcp-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 79.7 kB
Release files / create_mcp-0.2.0.tar.gz
| Download URL | create_mcp-0.2.0.tar.gz |
|---|---|
| Size | 35.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
224b7159618b86a20cf575f925eef363db31ef1a48a4944f650cae90946aeb1a
|
|
BLAKE2b-256 checksum How to use checksums |
d3ccd9deaf4ec8a84f53a2c46e62cc367d7620cf628474e92daf726a5a697b41
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.3
|
Release files / create_mcp-0.2.0-py3-none-any.whl
| Download URL | create_mcp-0.2.0-py3-none-any.whl |
|---|---|
| Size | 44.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b087527e3b39015a4af08c303beb5fd32810a165dfdfb7f2bc2c1ea4de00b082
|
|
BLAKE2b-256 checksum How to use checksums |
48c927d6e70134d44a2b50990d95f0f10cf14946c5a560d28046bc2918a5a589
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.3
|