mcp-evals
Behavioral evaluation and description linting for Model Context Protocol (MCP) servers.
Status: v0.8 — stdio/HTTP/SSE discovery, description lint, mock/OpenAI evals with argument scoring, GitHub Action PR comments.
60-second try
pip install mcp-tool-evals
mcp-evals health
mcp-evals run examples/eval-suite.yaml --catalog examples/tools.yaml --model mock
# or with Docker (no local Python):
docker compose run --rm run-example
Why this vs alternatives
| Approach | Strength | Gap |
|---|---|---|
| mcp-evals | Lint + YAML evals + mock CI runner | Not a full agent harness |
| MCP Inspector | Interactive debugging | No CI lint/eval suite |
| Protocol conformance tests | JSON-RPC correctness | Do not test tool selection |
| Hand-written LLM mocks | Full control | Drift from real descriptions |
Problem
Protocol conformance tests verify JSON-RPC correctness. They do not verify whether an LLM agent selects the right tool, passes sensible arguments, or completes the task. Tool descriptions are now load-bearing API design, and there is no standard way to test them.
mcp-evals fills the behavioral layer: lint tool descriptions, define eval cases in YAML, and (next) measure tool-selection accuracy in CI.
Key features (v0.8)
- Description linter — missing descriptions, undocumented required params, overlapping tools, ambiguous verbs,
name-description-mismatch,missing-examples - Live discover — handshake a stdio, HTTP JSON-RPC, or Streamable HTTP/SSE MCP server (or load a catalog fixture)
- Eval runner —
mcp-evals runwith--model mock(CI; tool + args),--live SERVER.yaml, or an OpenAI-compatible endpoint - CLI + Docker + GitHub Action — lint and optional eval in CI without a cloud key (mock selector); PR comment or job summary with accuracy
Architecture
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ CLI │────▶│ Linter / Runner │────▶│ Models (Pydantic)│
│ mcp-evals │ │ spec_loader │ │ EvalSuite, etc. │
└─────────────┘ └──────────────────┘ └─────────────────┘
│
(next) MCP client + LLM
| Component | Technology | Why |
|---|---|---|
| Language | Python 3.11+ | MCP SDK ecosystem, pytest integration |
| CLI | Click | Mature, composable commands |
| Schemas | Pydantic v2 | Strict validation, good errors |
| Logging | structlog | Structured, JSON-capable |
| Config | pydantic-settings | Env-based, typed |
| Tests | pytest + ruff + mypy | Standard Python OSS stack |
Installation
pip install mcp-tool-evals
# or from source:
pip install -e ".[dev]"
Local development
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
mcp-evals health
mcp-evals lint examples/tools.yaml
mcp-evals discover examples/server.yaml
mcp-evals lint --live examples/server.yaml
mcp-evals validate-spec examples/eval-suite.yaml
mcp-evals run examples/eval-suite.yaml --catalog examples/tools.yaml --model mock
pytest tests/ -v
Docker
# Health check
docker compose run --rm dev
# Run tests
docker compose run --rm test
# Lint a live stdio server (this example passes)
docker compose run --rm lint-example
# Discover tools from the example calc server
docker compose run --rm discover-example
# Mock eval run (no API key)
docker compose run --rm run-example
Configuration
Copy .env.example to .env:
| Variable | Default | Description |
|---|---|---|
MCP_EVALS_LOG_LEVEL |
INFO |
Log level |
MCP_EVALS_LOG_JSON |
false |
JSON log output |
MCP_EVALS_DEFAULT_MODEL |
gpt-4o-mini |
Model for eval runs (future) |
MCP_EVALS_PASS_THRESHOLD |
0.8 |
Minimum selection accuracy |
Usage
Lint tool descriptions
mcp-evals lint examples/tools.yaml
mcp-evals lint --live examples/server.yaml
mcp-evals discover examples/server.yaml
mcp-evals lint examples/tools.yaml --format json
mcp-evals lint examples/tools.yaml --fail-on-warning
Run behavioral evals
mcp-evals run examples/eval-suite.yaml --catalog examples/tools.yaml --model mock
mcp-evals run examples/eval-suite.yaml --catalog examples/tools.yaml \
--model llama3.2 --base-url http://localhost:11434/v1 --pass-threshold 0.8
# or discover tools from a live server that matches the suite:
# mcp-evals run suite.yaml --live server.yaml --model mock
Validate eval suite
mcp-evals validate-spec examples/eval-suite.yaml
Health check
mcp-evals health
GitHub Action
On pull_request, the composite action posts (or updates) a comment with selection accuracy and a per-case table. On other events it writes the same markdown to $GITHUB_STEP_SUMMARY. Set comment: false to skip PR comments.
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: yashshah9/mcp-evals@v0.7
with:
catalog: examples/tools.yaml
suite: examples/eval-suite.yaml
model: mock
threshold: "0.8"
# comment: false # optional; default true
Example eval suite
See examples/eval-suite.yaml:
name: document-server-behavior
cases:
- id: search-by-keyword
request: Find documents about quarterly revenue
expected_tool:
name: search_documents
arguments:
query: quarterly revenue
Running tests
pytest tests/ -v
ruff check src tests
mypy src
Development workflow
- Add linter rules in
src/mcp_evals/linter/ - Add runner logic in
src/mcp_evals/runner/ - Add tests in
tests/ - Update examples in
examples/
Roadmap
- MCP client: stdio discover + lint --live
- LLM eval runner (mock + OpenAI-compatible)
- HTTP JSON-RPC MCP transport
-
name-description-mismatchlinter rule - Streamable HTTP/SSE MCP transport
- GitHub Action PR comments (accuracy + per-case table; deltas later)
- Mock selector argument inference + argument_validity scoring
Known limitations (v0.8)
- Streamable HTTP/SSE discovery is initialize +
tools/listonly (no long-lived GET stream / resume) - Mock argument filling is heuristic (schema property names + request text), not an LLM
- Live Ollama/OpenAI evals need a reachable
--base-url; CI uses--model mock examples/tools.yamlis intentionally dirty somcp-evals lintcan show findings
Contributing
See CONTRIBUTING.md.
License
MIT — see LICENSE.
Metadata
Release files for mcp-tool-evals 0.8.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_tool_evals-0.8.0.tar.gz | 127.3 kB | Without provenance | Details for mcp_tool_evals-0.8.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mcp_tool_evals-0.8.0-py3-none-any.whl | Python 3 | none | any | Details for mcp_tool_evals-0.8.0-py3-none-any.whl |
Total release size: 152.3 kB
Release files / mcp_tool_evals-0.8.0.tar.gz
| Download URL | mcp_tool_evals-0.8.0.tar.gz |
|---|---|
| Size | 127.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8e565589d267e79dad44af678a6cb2b38d6248261bedacc22bf9dccc3ee2d702
|
|
BLAKE2b-256 checksum How to use checksums |
f5af6f57da7b2d429261c718bbe8fbcf0c6d6ea3e25a2f57692d8da1ac7a4dee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / mcp_tool_evals-0.8.0-py3-none-any.whl
| Download URL | mcp_tool_evals-0.8.0-py3-none-any.whl |
|---|---|
| Size | 25.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
75d89b409a1c9b7ac4e223431d139b9ead303f697f76d5bac5de64554406a8fd
|
|
BLAKE2b-256 checksum How to use checksums |
7f7185a8f3fda5202e817e2be04a0b32c326cf97ed32fb5c75259496bbef19b8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Security for mcp-tool-evals 0.8.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.