pytest-mcp-honesty
Bidirectional contract testing for FastMCP servers, in your own pytest suite.
A tool's schema is a contract, and servers break it in both directions:
- The schema promises less than the implementation demands. A param is
str | None = Nonein the signature — so the generated schema calls it optional — but the handler errors without it. Every agent that trusts the schema burns a failed call to learn the truth. (Found in the wild: a server whoseresolve_teamdeclaredrequired: []and then errored "provide club_name or org_id".) - The implementation enforces less than the schema promises. Required params can be omitted, or structurally wrong values are accepted, and garbage flows into your handler.
check_contracts probes every tool over FastMCP's in-memory client — no network, no auth,
hermetic — so a failed probe is a finding about your contract, not your environment:
from pytest_mcp_honesty import check_contracts
from my_app import server # your FastMCP instance
async def test_tool_contracts():
report = await check_contracts(server)
assert not report.violations, report.summary()
Three probe families, all deterministic (same schema → same probe):
| Probe | Catches |
|---|---|
| minimal valid call (declared-required args only) | schemas that under-declare what the tool needs |
| drop one required arg | schemas that over-declare, or missing validation |
| structurally wrong value (uncoercible — a dict where a scalar belongs) | declared types that are not enforced |
The wrong-value probe deliberately avoids values Pydantic's lax coercion legally repairs
("5" → 5 is not a violation); it sends values nothing can coerce.
What this is not
- Not protocol conformance — the transport/spec layer is a different job (see the official MCP Inspector, or mcp-java-testkit on the JVM).
- Not a fuzzer — probes are deterministic transcriptions of the contract, not random inputs (see mcp-fuzzer for security-style fuzzing).
- Not schema portability — whether your schema survives specific clients is mcp-portability-lint's job; this checks whether your schema tells the truth about your own server.
Development
Maintained by one person with AI assistance; where AI tooling contributed is logged per commit in docs/ai-maintenance-log.md.
License
Apache-2.0
Metadata
Release files for pytest-mcp-honesty 0.1.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 | Provenance | Actions |
|---|---|---|---|---|
| pytest_mcp_honesty-0.1.0.tar.gz | 11.3 kB | Without provenance | Details for pytest_mcp_honesty-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pytest_mcp_honesty-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for pytest_mcp_honesty-0.1.0-py3-none-any.whl |
Total release size: 22.7 kB
Release files / pytest_mcp_honesty-0.1.0.tar.gz
| Download URL | pytest_mcp_honesty-0.1.0.tar.gz |
|---|---|
| Size | 11.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b823b0b645bfd9a90a32bd2d6180938aa6afc1d1345db4db9a51c34d9f48d151
|
|
BLAKE2b-256 checksum How to use checksums |
0db213cd5b05e48342212c3bdfe2f7677630ed0d58e0be913f40a7304890e99b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / pytest_mcp_honesty-0.1.0-py3-none-any.whl
| Download URL | pytest_mcp_honesty-0.1.0-py3-none-any.whl |
|---|---|
| Size | 11.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dde194261e9ac759b4c18845da7b0550e7f8272151e22d414caf54ced95e23a3
|
|
BLAKE2b-256 checksum How to use checksums |
3de96281f7dd56f30c4d94d9a18703c2f50efda09181de408e20e4139e1e8634
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Security for pytest-mcp-honesty 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.