Skip to main content

pytest for MCP servers — the testing framework for the Model Context Protocol

Project description

pytest-mcp-plugin

pytest for MCP servers — the testing framework for the Model Context Protocol.

PyPI Python License: MIT

pip install pytest-mcp-plugin
mcp-test demo            # runs a bundled MCP server + tests in 5 seconds

Note on the name. This package is published on PyPI as pytest-mcp-plugin. The mcp-test name on PyPI is reserved by Anthropic for their official MCP SDK, and PyPI's name-similarity policy blocks close variants like mcptest. The CLI binary is still mcp-test, and the Python module is still mcp_test.


Why

MCP (Model Context Protocol) is the standard interface every AI agent now uses to talk to tools, files, databases, and APIs. Thousands of teams are shipping MCP servers in 2026. Almost none of them are tested.

pytest-mcp-plugin fixes that. Write tests for your MCP tools, resources, and prompts with the same developer experience you expect from pytest.

  • pytest plugin with auto-registered fixtures
  • stdio and HTTP/SSE transports
  • Schema validation, snapshot testing, coverage reports
  • Auth + policy assertions
  • Drop-in GitHub Action

60-second tour

pip install pytest-mcp-plugin
mcp-test demo

That spins up a bundled MCP server and runs a real test suite against it — no setup, no API keys, no servers to write first.

🚀 mcp-test demo
   server  : python -m mcp_test._demo_server
   workdir : /tmp/mcptest-demo-xxxx

test_demo.py::test_lists_tools         PASSED
test_demo.py::test_echo                PASSED
test_demo.py::test_add                 PASSED
test_demo.py::test_uppercase           PASSED
test_demo.py::test_fail_returns_error  PASSED

✅ Demo passed. Now write tests for your own MCP server:
   mcp-test init

Test your own server

cd my-mcp-server/
mcp-test init
pytest --mcp-command "python my_server.py" -v

Or pin the command in your pyproject.toml:

[tool.mcp-test]
command = "python my_server.py"
timeout = 10

[tool.mcp-test.timeouts]
"tools/list" = 5
"tools/call" = 30
"sampling/createMessage" = 60

…and just run:

mcp-test run

Write tests

# tests/test_my_server.py
from mcp_test import assert_tool_ok, assert_tool_error, assert_tool_text_contains


def test_search_returns_results(mcp_client):
    result = mcp_client.call_tool("search", query="machine learning")
    assert_tool_ok(result)
    assert len(result.content) > 0


def test_search_handles_empty_query(mcp_client):
    result = mcp_client.call_tool("search", query="")
    assert_tool_error(result)


def test_search_schema(mcp_client):
    tools = mcp_client.list_tools()
    search = tools.find("search")
    assert search.required == ["query"]
    assert search.properties["query"]["type"] == "string"

Use as a library

from mcp_test import MCPTestClient

with MCPTestClient.from_command("python my_server.py") as client:
    tools = client.list_tools()
    print(tools.names())

    result = client.call_tool("echo", message="hello")
    print(result.text())

Run on every PR (GitHub Action)

pytest-mcp-plugin ships as a composite action you can drop into any repo:

# .github/workflows/mcp-tests.yml
name: MCP Tests

on:
  pull_request:
  push:
    branches: [main]

jobs:
  mcp-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: yagna-1/mcp-test@v0.2.0
        with:
          command: "python my_server.py"
          test-dir: "tests"

That's it. The action installs pytest-mcp-plugin, runs your suite against your MCP server, and posts a JUnit XML report.


CLI reference

Command Description
mcp-test demo Run the bundled demo server + tests (zero setup)
mcp-test init Scaffold tests/ with example MCP tests
mcp-test run -c "python server.py" Run pytest against your server
mcp-test snapshot -c "..." Run snapshot tests (--update to refresh)
mcp-test coverage -c "..." Print coverage report (tools/prompts/resources)
mcp-test validate -c "..." Validate tool input schemas
mcp-test conformance --url "..." Run the upstream MCP conformance suite through npx
mcp-test bench -c "..." Run lightweight p50/p95/p99 regression probes

All commands accept --help for full options.


Fixtures

The pytest plugin auto-registers three fixtures:

Fixture Scope Use for
mcp_client session Fast — one server process for the whole test run
mcp_client_fresh function Clean state per test
sandboxed_client function Fresh server with cwd=tmp_path and DATA_DIR=tmp_path
snapshot function Snapshot testing helper
pytest --mcp-command "python my_server.py" --mcp-timeout 15 \
  --mcp-timeout-method tools/call=30 \
  --mcp-trace .mcp-test/trace.jsonl

--mcp-timeout-method METHOD=SECONDS may be passed multiple times, and the same values can live in [tool.mcp-test.timeouts]. --mcp-trace records JSONL wire frames; in CI, failing tests also dump recent frames to mcp-traces/.

Use mcp-test conformance --url ... --pytest-items when you want each parsed upstream scenario re-emitted as a normal pytest test item.

Spec-version markers

Mark tests by required MCP spec version; the plugin auto-skips tests against older servers.

import pytest

@pytest.mark.mcp_v3  # requires spec >= 2025-06-18
def test_uses_recent_feature(mcp_client):
    ...

Available markers: mcp_v2, mcp_v3, mcp_v4.

Assertion helpers

from mcp_test import (
    assert_tool_ok,
    assert_tool_error,
    assert_tool_error_code,
    assert_tool_text_contains,
    assert_tool_text_equals,
    assert_tool_content_count,
    assert_policy_allows,
    assert_policy_blocks,
    assert_task_completes_within,
    assert_task_cancelled,
    assert_task_failed,
)

Architecture

pytest-mcp-plugin runs your MCP server as a subprocess and speaks JSON-RPC 2.0 over stdio (or HTTP/SSE for the HTTP transport). A background message pump handles response routing, notification dispatching, and concurrent request support — so your tests just work.

Source modules:

mcp_test/
  client.py            # stdio JSON-RPC client
  http_client.py       # HTTP + SSE client
  plugin.py            # pytest plugin (fixtures, options, markers)
  cli.py               # mcp-test CLI
  assertions.py        # assert_tool_*, assert_policy_*, assert_task_*
  schema_validator.py  # JSON Schema validation for tool inputs
  coverage.py          # tools/prompts/resources coverage tracker
  snapshot.py          # snapshot testing
  auth.py              # OAuth / PKCE / RFC 9728 helpers
  bench.py             # lightweight regression benchmark probes
  conformance.py       # bridge to @modelcontextprotocol/conformance
  compliance.py        # conformance score helpers
  fastmcp.py           # in-process FastMCP harness adapter
  replay.py            # deterministic wire-trace replay lookup
  pagination.py        # cursor pagination helpers
  test_packs.py        # reusable server-shape test packs
  timeouts.py          # per-method timeout policy
  wire_trace.py        # JSONL wire trace recorder
  types.py             # ToolResult, ToolSchema, MCPError, ...
  _demo_server.py      # bundled demo server (used by `mcp-test demo`)

Status

pytest-mcp-plugin is beta. The CLI surface and plugin API are stable; minor internals (schema validator details, snapshot format) may still change.

Roadmap

See ROADMAP.md for what's next, what we explicitly won't build, and how we plan to complement (not compete with) Anthropic's official @modelcontextprotocol/conformance and @modelcontextprotocol/inspector.

Contributing

Bug reports, feature requests, and PRs welcome at github.com/yagna-1/mcp-test.

License

MIT

Project details


Download files

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

Source Distribution

pytest_mcp_plugin-0.2.3.tar.gz (70.2 kB view details)

Uploaded Source

Built Distribution

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

pytest_mcp_plugin-0.2.3-py3-none-any.whl (54.9 kB view details)

Uploaded Python 3

File details

Details for the file pytest_mcp_plugin-0.2.3.tar.gz.

File metadata

  • Download URL: pytest_mcp_plugin-0.2.3.tar.gz
  • Upload date:
  • Size: 70.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for pytest_mcp_plugin-0.2.3.tar.gz
Algorithm Hash digest
SHA256 5d862c24adcdaa33187e17651f5bd17530e4cf13a00d103a529e7936db6044f0
MD5 71ad74c583e732b1387d34b7b9959dd8
BLAKE2b-256 c5ba3b8141477bb63a1a4b07ac145d3ca8c74c558af2133b558e23d6b0df59f1

See more details on using hashes here.

File details

Details for the file pytest_mcp_plugin-0.2.3-py3-none-any.whl.

File metadata

File hashes

Hashes for pytest_mcp_plugin-0.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 3817593d0f0110c373cd5d85bce15a391afb602a411955a0c53ce533af58c2a1
MD5 6c5259c83bba612fef37ceca14fed0d4
BLAKE2b-256 cae287254fcc0c0b3141ffdbd87319f7bf95353934d8ce58246b1ed442a7e1e9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page