Metadata-Version: 2.5
Name: mcp4api
Version: 0.1.0
Summary: Turn API docs into a working MCP server, then verify every generated tool against the real API.
Project-URL: Homepage, https://github.com/smusali/mcp4api
Project-URL: Repository, https://github.com/smusali/mcp4api
Project-URL: Issues, https://github.com/smusali/mcp4api/issues
Project-URL: Changelog, https://github.com/smusali/mcp4api/blob/main/CHANGELOG.md
Project-URL: Documentation, https://github.com/smusali/mcp4api/blob/main/docs/USAGE.md
Author-email: Samir Musali <samir.musali@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: agentic-ai,ai-agents,ai-infrastructure,cli,code-generation,developer-tools,llm,mcp,model-context-protocol,openapi,python
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Software Development :: Code Generators
Classifier: Topic :: Software Development :: Testing
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: anthropic<3,>=2.2.0
Requires-Dist: httpx2<3,>=2.16.0
Requires-Dist: hypothesis-jsonschema<1,>=0.23.1
Requires-Dist: hypothesis<7,>=6.170.8
Requires-Dist: jinja2<4,>=3.1.6
Requires-Dist: jsonschema<5,>=4.26.0
Requires-Dist: mcp<3,>=2.3
Requires-Dist: openapi-spec-validator<1,>=0.9.0
Requires-Dist: pydantic<3,>=2.14.1
Requires-Dist: pyyaml<7,>=6.0.3
Requires-Dist: rich<16,>=15.0.0
Requires-Dist: typer<1,>=0.27.3
Description-Content-Type: text/markdown

# mcp4api

mcp4api turns your API docs into a working MCP server, then calls every generated tool against your API and reports which ones work. Built for platform teams who want their product callable by agents.

[![CI](https://github.com/smusali/mcp4api/actions/workflows/ci.yml/badge.svg)](https://github.com/smusali/mcp4api/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/mcp4api.svg)](https://pypi.org/project/mcp4api/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/smusali/mcp4api/blob/main/LICENSE)
[![Python versions](https://img.shields.io/pypi/pyversions/mcp4api.svg)](https://pypi.org/project/mcp4api/)

![Offline run against the Shelf sample, from ingest through the verification summary](https://raw.githubusercontent.com/smusali/mcp4api/main/examples/demo.gif)

[Recording](https://github.com/smusali/mcp4api/blob/main/examples/demo.cast)

## Install

```bash
pip install mcp4api
uvx mcp4api
```

## Quickstart

These commands need no API key. They reuse the committed manifest and cassettes, regenerate the other artifacts in place, and exit 3. The sample's one known gap is `get_book`: `page_count` is a string in the API and an integer in the spec.

```bash
git clone https://github.com/smusali/mcp4api && cd mcp4api
uvx mcp4api examples/sample-api/openapi.yaml --offline --out examples/sample-api
cat examples/sample-api/report/verification.md
```

## Generated tool

`upload_book_file` from the Shelf sample is four calls composed into one tool.

```python
@mcp.tool(
    title="Upload Book File",
    annotations=ToolAnnotations(
        read_only_hint=False,
        destructive_hint=False,
        idempotent_hint=False,
        open_world_hint=True,
    ),
)
async def upload_book_file(
    book_id: Annotated[str, Field(description="book id")],
    content_type: Annotated[str, Field(description="content type")],
    data: Annotated[str, Field(description="data")],
    filename: Annotated[str, Field(description="filename")],
) -> UploadBookFileResult:
    """Upload a file and attach it to a book."""
    create_upload = await api.request(
        "POST",
        "/uploads",
        body={"content_type": content_type, "filename": filename},
        auth=(("api_key", "header", "X-API-Key"),),
    )
    _upload_part = await api.request(
        "PUT",
        "/uploads/{upload_id}/parts/{part_number}",
        path_params={
            "part_number": UPLOAD_BOOK_FILE_PART_NUMBER,
            "upload_id": api.pick(create_upload, "id"),
        },
        body={"data": data},
        auth=(("api_key", "header", "X-API-Key"),),
    )
    _complete_upload = await api.request(
        "POST",
        "/uploads/{upload_id}/complete",
        path_params={"upload_id": api.pick(create_upload, "id")},
        auth=(("api_key", "header", "X-API-Key"),),
    )
    attach_book_file = await api.request(
        "PUT",
        "/books/{book_id}/file",
        path_params={"book_id": book_id},
        body={"upload_id": api.pick(create_upload, "id")},
        auth=(("api_key", "header", "X-API-Key"),),
    )

    return UploadBookFileResult.model_validate(attach_book_file)
```

## Verification report

![Verification report for the Shelf sample, with get_book as the known gap](https://raw.githubusercontent.com/smusali/mcp4api/main/examples/verification.png)

## CI

`mcp/` holds the committed `tools.yaml` and cassettes. Exit 3 fails the job.

```yaml
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1  # v7.0.1
  with:
    persist-credentials: false
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e  # v10.3.2
- run: uvx mcp4api openapi.yaml --offline --out mcp/
```

## Limitations

- OpenAPI 3.0, 3.1, 3.2, and Swagger 2.0 only.
- API key or bearer token authentication only.
- A failing tool is a known gap. It is not repaired.
- Agent curation needs an Anthropic API key.

The full list is in [Limitations](https://github.com/smusali/mcp4api/blob/main/docs/limitations.md).

## Contributing

See [Contributing](https://github.com/smusali/mcp4api/blob/main/CONTRIBUTING.md).

## License

[MIT](https://github.com/smusali/mcp4api/blob/main/LICENSE)
