mcpgate
Automated quality gate for MCP servers — ruff + pytest for MCP.
The problem
When an MCP tool description is vague, the AI agent misuses the tool — even though the code behind it is perfect. This failure is invisible to unit tests because it happens at the AI-interpretation layer. Research documents the scale:
- An arXiv study of 103 major MCP servers (856 tools) found tool descriptions systematically "smelly and costly" (arXiv:2602.14878).
- An AWS-led study found 97.1% of MCP tool descriptions contain at least one quality defect.
mcpgate catches these defects before agents hit them in production. It speaks the
real protocol, so it works with any server — FastMCP, the official Python SDK, or
TypeScript servers — over stdio or HTTP.
Quickstart
uv tool install mcp-gatekeeper # or: pip install mcp-gatekeeper
mcpgate lint "uvx mcp-server-fetch"
mcpgate doctor "uvx mcp-server-fetch"
Exit codes are CI-friendly: 0 clean, 1 findings (fail the build), 2 connection
or protocol error.
Example output
warning MCP101 Tool `delete_record`: description too short (7 words; minimum 8) src: tools/delete_record
warning MCP105 Tool `delete_record`: description does not state error/return behavior src: tools/delete_record
warning MCP303 Tool `delete_record`: destructive operation without a confirmation parameter src: tools/delete_record
error MCP301 Tool `run_command`: suggests command execution without a safety note src: tools/run_command
warning MCP101 Tool `run_command`: description too short (7 words; minimum 8) src: tools/run_command
warning MCP105 Tool `run_command`: description does not state error/return behavior src: tools/run_command
warning MCP101 Tool `search`: description too short (2 words; minimum 8) src: tools/search
warning MCP105 Tool `search`: description does not state error/return behavior src: tools/search
info MCP204 Tool `search`: description repeats the tool name (wasted tokens) src: tools/search
———
found 9 problems (1 errors, 7 warnings)
run `mcpgate lint --explain CODE` for details
Formats: --format text|json|sarif (SARIF plugs into GitHub code scanning).
Filter with --select MCP3xx --ignore MCP401; inspect a rule with
--explain MCP101; fail on warnings with --strict.
Rules (v0.1)
| Code | Severity | What it checks |
|---|---|---|
| MCP101 | warning | Tool description missing or shorter than 8 words |
| MCP102 | warning | Description is vague ("does stuff", "handles things", "various") |
| MCP103 | warning | Description just restates the tool name |
| MCP104 | warning | Tools with 2+ parameters where parameters lack descriptions |
| MCP105 | warning | Description does not state error/return behavior |
| MCP106 | warning | Description longer than 1024 chars (token bloat) |
| MCP201 | error | Input schema missing or not a JSON object schema |
| MCP202 | warning | Required parameter is not described |
| MCP203 | info | additionalProperties: false schema but description states no constraints |
| MCP204 | info | Description repeats the tool name (wasted tokens) |
| MCP205 | error | Declared output schema is invalid |
| MCP301 | error | Command-execution tool without a safety note |
| MCP302 | warning | Parameter name looks like a secret (api_key, token, …) |
| MCP303 | warning | Destructive operation without a confirmation parameter |
| MCP401 | info | Full definition snapshot costs more than ~10k tokens |
Pytest plugin
Install with the test extra, then contract-test your tools over the real protocol:
pip install "mcp-gatekeeper[test]"
import pytest
from my_server import mcp # your FastMCP / MCP server object
@pytest.mark.parametrize("mcp_server", [mcp], indirect=True)
def test_search(mcp_server):
result = mcp_server.call_tool("search", {"query": "hello"})
assert result.is_error is False
@pytest.mark.parametrize("mcp_server", [mcp], indirect=True)
def test_contract(mcp_server):
mcp_server.tool_contract("search")
# asserts: described, valid object schema, described required params,
# and the error path returns is_error instead of crashing
Or point a whole suite at one server: pytest --mcp-server "uvx mcp-server-fetch".
Works in-memory for server objects (fully offline), stdio/HTTP for commands and URLs.
How it compares
| MCP Inspector | mcplint-cli | mcp-doctor | mcpgate | |
|---|---|---|---|---|
| Purpose | interactive debugger | description lint | diagnostics | unified quality gate |
| CLI-first, CI exit codes | ✗ | ✓ | partial | ✓ (0/1/2) |
| Definition lint rules | ✗ | ✓ | ✗ | ✓ (15 rules) |
| Doctor / health check | ✓ | ✗ | ✓ | ✓ |
| pytest plugin | ✗ | ✗ | ✗ | ✓ |
| JSON + SARIF output | ✗ | ✗ | ✗ | ✓ |
| Framework-agnostic (speaks MCP) | ✓ | ✓ | ✓ | ✓ |
Roadmap
- v0.2 —
--fix: LLM-assisted rewriting of weak descriptions (the engine already carries the context needed per finding) - Declarative YAML test suites and
--baselinefiles - Custom user rule plugins and a pre-commit hook package
- GitHub Action and official MCP servers registry integration
Contributing
See CONTRIBUTING.md. MIT licensed — see LICENSE.
Metadata
Release files for mcp-gatekeeper 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 |
|---|---|---|---|---|
| mcp_gatekeeper-0.1.0.tar.gz | 135.0 kB | With provenance | Details for mcp_gatekeeper-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mcp_gatekeeper-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for mcp_gatekeeper-0.1.0-py3-none-any.whl |
Total release size: 153.4 kB
Release files / mcp_gatekeeper-0.1.0.tar.gz
| Download URL | mcp_gatekeeper-0.1.0.tar.gz |
|---|---|
| Size | 135.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7167960e02230d3fff17ad703243e4e93594bc98124a976233774a36d974b302
|
|
BLAKE2b-256 checksum How to use checksums |
86434396f9a67ff5f772513b71bfca702789ebf2fe3c25a8d27c3c32393b3773
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logRelease files / mcp_gatekeeper-0.1.0-py3-none-any.whl
| Download URL | mcp_gatekeeper-0.1.0-py3-none-any.whl |
|---|---|
| Size | 18.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
59fc5a1c9c7bb95531ae6ad75e79fce838c32e6bd2def83ea68234358af9461b
|
|
BLAKE2b-256 checksum How to use checksums |
1e32e730d76790e1f8e9bf5888bf948a5bbb99ee93ff28615c966da5da53ecd5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logSecurity for mcp-gatekeeper 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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for mcp_gatekeeper-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logA 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.