Skip to main content

mcp-evals

Behavioral evaluation and description linting for Model Context Protocol (MCP) servers.

PyPI License: MIT Python 3.11+ CI

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 runnermcp-evals run with --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

  1. Add linter rules in src/mcp_evals/linter/
  2. Add runner logic in src/mcp_evals/runner/
  3. Add tests in tests/
  4. Update examples in examples/

Roadmap

  • MCP client: stdio discover + lint --live
  • LLM eval runner (mock + OpenAI-compatible)
  • HTTP JSON-RPC MCP transport
  • name-description-mismatch linter 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/list only (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.yaml is intentionally dirty so mcp-evals lint can show findings

Contributing

See CONTRIBUTING.md.

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_tool_evals-0.8.0.tar.gz (127.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_tool_evals-0.8.0-py3-none-any.whl (25.0 kB view details)

Uploaded Python 3

File details

Details for the file mcp_tool_evals-0.8.0.tar.gz.

File metadata

  • Download URL: mcp_tool_evals-0.8.0.tar.gz
  • Upload date:
  • Size: 127.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.14

File hashes

Hashes for mcp_tool_evals-0.8.0.tar.gz
Algorithm Hash digest
SHA256 8e565589d267e79dad44af678a6cb2b38d6248261bedacc22bf9dccc3ee2d702
MD5 f767a6626433ab73c6ba04271db8419e
BLAKE2b-256 f5af6f57da7b2d429261c718bbe8fbcf0c6d6ea3e25a2f57692d8da1ac7a4dee

See more details on using hashes here.

File details

Details for the file mcp_tool_evals-0.8.0-py3-none-any.whl.

File metadata

  • Download URL: mcp_tool_evals-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 25.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.14

File hashes

Hashes for mcp_tool_evals-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 75d89b409a1c9b7ac4e223431d139b9ead303f697f76d5bac5de64554406a8fd
MD5 21acd301bf1766643872cb29643fcc07
BLAKE2b-256 7f7185a8f3fda5202e817e2be04a0b32c326cf97ed32fb5c75259496bbef19b8

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.8.0 This release

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page