Modern QA2026Surface 1: Contract Testing MCP Tool Integrations — tiles
Log inJoin
101 / 108 · 03 Agentic Testing Architectures · Testing Agentic Systems: MCP, A2A, and Agent Evals← prev⊞ allnext →☰ Read as one page

14.2Surface 1: Contract Testing MCP Tool Integrations

An agent's tools are exposed through MCP (Model Context Protocol) servers, each publishing a list of tools with JSON schemas. This is a contract surface, and it deserves the same treatment you give REST contracts: schema validation plus breaking-change detection.

import json
import pytest
from mcp_client import connect  # any MCP client library

EXPECTED_TOOLS_SNAPSHOT = "contracts/payments_mcp_tools.json"

@pytest.fixture
def mcp_session():
    with connect("http://localhost:8931/mcp") as session:
        yield session

def test_tool_list_matches_contract(mcp_session):
    """Detect tools appearing, disappearing, or changing shape."""
    tools = {t.name: t.input_schema for t in mcp_session.list_tools()}
    expected = json.load(open(EXPECTED_TOOLS_SNAPSHOT))

    assert set(tools) == set(expected), (
        f"Tool set changed. Added: {set(tools) - set(expected)}, "
        f"Removed: {set(expected) - set(tools)}"
    )
    for name, schema in expected.items():
        assert tools[name] == schema, f"Schema drift in tool '{name}'"

def test_required_params_are_enforced(mcp_session):
    """The server must reject calls missing required parameters."""
    result = mcp_session.call_tool("refund_payment", arguments={})
    assert result.is_error, "Server accepted a refund call with no arguments"

def test_tool_errors_are_structured(mcp_session):
    """Errors must come back as structured results, not stack traces --
    the agent will read this text and act on it."""
    result = mcp_session.call_tool(
        "refund_payment", arguments={"payment_id": "nonexistent"}
    )
    assert result.is_error
    assert "Traceback" not in result.content[0].text

Why schema drift matters more than in REST: a human developer reads changelogs; an agent does not. If a tool renames a parameter, the agent will keep calling it the old way, fail, and then improvise -- often by picking a different tool. A silent contract break does not produce a clean error; it produces weird behavior three steps later. Snapshot the tool list in version control and fail CI on any diff.

The same idea applies when you are the tool vendor: teams shipping MCP servers (as Playwright does with Playwright MCP, published to the official MCP Registry on every release) need these contract tests on the server side.