RUNLOCALAIv38
->Will it run?Best GPUCompareTroubleshootStartLearnPulseModelsHardwareToolsBench
Run check
RUNLOCALAI

Independently operated catalog for local-AI hardware and software. Hand-written verdicts. Source-cited claims. Reproducible commands when we have them.

OP·Fredoline Eruo
DIR
  • Models
  • Hardware
  • Tools
  • Benchmarks
TOOLS
  • Will it run?
  • Compare hardware
  • Cost vs cloud
  • Choose my GPU
  • Prompting kits
  • Quick answers
REF
  • All buyer guides
  • Learn local AI
  • Methodology
  • Glossary
  • Errors KB
  • Trust
EDITOR
  • About
  • Author
  • How we make money
  • Editorial policy
  • Contact
LEGAL
  • Privacy
  • Terms
  • Sitemap
MAIL · MONTHLY DIGEST
Get monthly local AI changes
Monthly recap. No spam.
DISCLOSURE

Some links on this site are affiliate links (Amazon Associates and other first-class retailers). When you buy through them, we earn a small commission at no extra cost to you. Affiliate links do not influence our verdicts — there are cards we rate highly that we don't have affiliate relationships with, and cards that sell well that we refuse to recommend. Read more →

© 2026 runlocalai.coIndependently operated
RUNLOCALAI · v38
  1. >
  2. Home
  3. /Learn
  4. /Courses
  5. /MCP Server Implementation
  6. /Ch. 18
MCP Server Implementation

18. Testing MCP

Chapter 18 of 22 · 20 min
KEY INSIGHT

Thorough MCP testing covers protocol compliance, tool behavior, and integration scenariosΓÇöeach layer reveals different defects that tests must catch. Unit tests verify individual tool behavior in isolation: ```python import pytest @pytest.fixture def mcp_server(): return create_test_server() @pytest.mark.asyncio async def test_file_tool_read(mcp_server): # Arrange create_test_file("/tmp/test.txt", "hello world") # Act result = await mcp_server.call_tool("read_file", {"path": "/tmp/test.txt"}) # Assert assert result == "hello world" @pytest.mark.asyncio async def test_file_tool_not_found(mcp_server): with pytest.raises(ToolError) as exc_info: await mcp_server.call_tool("read_file", {"path": "/nonexistent"}) assert "not found" in str(exc_info.value) ``` Protocol tests verify JSON-RPC message handling: ```python @pytest.mark.asyncio async def test_protocol_invalid_json(): response = await test_client.post( "/mcp", data="not valid json", headers={"Content-Type": "application/json"} ) assert response.status_code == 400 @pytest.mark.asyncio async def test_protocol_missing_method(): response = await test_client.post( "/mcp", json={"jsonrpc": "2.0", "params": {}, "id": 1} ) assert response.status_code == 400 assert "method" in response.json()["error"]["message"] ``` Integration tests verify the full request-response cycle: ```python @pytest.mark.asyncio async def test_full_tool_invocation(): # Start server in test mode async with TestServer() as server: client = MCPClient(transport=stdio()) # Initialize await client.initialize() # List tools tools = await client.list_tools() assert any(t.name == "read_file" for t in tools) # Call tool result = await client.call_tool("read_file", {"path": "/etc/hostname"}) assert isinstance(result, str) # Cleanup await client.close() ``` Property-based testing validates edge cases: ```python from hypothesis import given, strategies as st @given(path=st.text(min_size=1, max_size=1000)) @pytest.mark.asyncio async def test_path_handling(path): server = create_server() # Should either succeed or raise proper error try: result = await server.call_tool("read_file", {"path": path}) assert isinstance(result, str) except ToolError as e: # Errors should be informative assert len(str(e)) > 0 ``` Contract tests ensure compatibility with MCP protocol versions: ```python @pytest.mark.asyncio async def test_protocol_version_handshake(): client = TestClient() init_response = await client.send_request({ "jsonrpc": "2.0", "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "test", "version": "1.0"} }, "id": 1 }) assert "protocolVersion" in init_response assert "capabilities" in init_response ```

EXERCISE

Write a test suite covering three scenarios: successful tool execution, validation errors, and protocol-level malformed requests. Run tests with coverage reporting and identify untested code paths.

← Chapter 17
Debugging MCP Servers
Chapter 19 →
Error Handling