Generate MCP servers from OpenAPI 3.0/3.1 with structured outputs (Pydantic v2).
MCP Toolbox
Generate production-ready MCP servers from OpenAPI specs in one command.

Quick Start
pip install -e ".[dev]"
mcp-toolbox generate --spec tests/fixtures/petstore.yaml -o ./output
cd output && pip install -e .
Features
- OpenAPI 3.0/3.1 validation with clear error reporting
- YAML, JSON, local files, and URL inputs
$refresolution withprance(including external refs)- Typed OpenAPI parsing with
openapi-pydantic - Deterministic tool/model ordering and snapshot-backed generation checks
- Structured JSON tool outputs using Pydantic v2
TypeAdapter - Generated Pydantic models from
components/schemas - Request-body generation for JSON,
multipart/form-data, andapplication/x-www-form-urlencoded - Retry/backoff-aware HTTP client with env-configurable timeout + retry settings
- Auth scaffolding for bearer, oauth2, api key (header/query/cookie), and basic
- Tool curation with explainable selection (
preview --explain-selection) - Template override support with
--template-dir - Config precedence: CLI > env (
MCP_TOOLBOX_*) >pyproject.toml([tool.mcp_toolbox]) > defaults - Optional watch mode for local specs (
mcp-toolbox watch)
Example Generated Output
@mcp.tool(structured_output=True)
async def list_pets(limit: int | None = 20, offset: int | None = 0) -> list[dict[str, Any]]:
"""List pets"""
response = await request_with_retry(
ctx.client,
"GET",
"/pets",
max_retries=ctx.max_retries,
backoff_seconds=ctx.backoff_seconds,
request_kwargs={"params": {"limit": limit, "offset": offset}},
)
response.raise_for_status()
return TypeAdapter(list[dict[str, Any]]).validate_python(response.json())
CLI Options (generate)
| Option | Description | Default |
|---|---|---|
| <spec> or --spec | Path or URL to OpenAPI spec | required (provide one) |
| -o, --output | Output directory for generated server | ./output |
| -n, --name | Override auto-detected server name | auto |
| --max-tools | Maximum number of generated tools | 12 |
| --tag, --filter-tags | Include only matching tags (repeatable) | none |
| --include-tags | Include tools by tag (repeatable) | none |
| --exclude-tags | Exclude tools by tag (repeatable) | none |
| --prefer-tags | Prioritize these tags during tool trimming | none |
| --body-style | Preferred request body style (auto/json/form/multipart) | auto |
| --enums | Enum style (literal/strenum) | literal |
| --dry-run | Analyze only, do not write files | false |
| --transport-default, --transport | Default transport embedded in generated server.py | stdio |
| --template-dir | Override built-in templates with local files | none |
watch command is available for local specs:
mcp-toolbox watch --spec tests/fixtures/petstore.yaml -o ./output
CI-Friendly Commands
python -m pip install -e ".[dev]"
python -m ruff check .
python -m ruff format . --check
python -m pytest -q
Docs
- Gap analysis:
docs/v2-gap-analysis.md - Template authoring:
docs/template-authoring.md - Troubleshooting:
docs/troubleshooting.md
Comparison
| Capability | MCP Toolbox | Hand-written MCP server | Generic OpenAPI client generator | |---|---|---|---| | One-command MCP server generation | ✅ | ❌ | ❌ | | MCP tool naming + descriptions | ✅ | manual | ❌ | | OpenAPI validation + parsing pipeline | ✅ | manual | partial | | FastMCP-ready async server scaffold | ✅ | manual | ❌ | | Customizable templates | ✅ | n/a | limited |
Current Limitations
oneOf/anyOfare mapped to Python unions but complex discriminator behavior is still best-effort.- XML/custom media types are not deeply modeled (JSON/form flows are primary).
- OAuth2 client-credentials generation provides scaffold/env wiring; full token lifecycle automation is left to integrators.
Contributing
- Fork the repo
- Create a branch:
git checkout -b feature/my-change - Run checks:
python -m ruff check . && python -m pytest -q - Open a pull request
License
MIT — see LICENSE.