import pytest@pytest.mark.asyncioasync def test_your_feature(client): """Test description following the pattern test_<functionality>_<expected_behavior>""" # Arrange key = "test_key" value = "test_value" # Act response = await client.process_query( f"Store the key '{key}' with value '{value}'" ) # Assert assert key in response, f"Key '{key}' not found in response: {response}" assert value in response, f"Value '{value}' not found in response: {response}" print(f"✅ Test passed: {key}={value}")
The client fixture is automatically provided by conftest.py and gives you access to test client methods:
@pytest.mark.asyncioasync def test_with_client(client): # Send natural language query to LLM that uses your MCP tools response = await client.process_query("List all stored data") # Make assertions about the response assert "data" in response.lower()
The test client uses Claude (via Anthropic API) to interact with your MCP server naturally. You need ANTHROPIC_API_KEY in your .env file.
@pytest.mark.asyncioasync def test_store_data(client): """Test the store-data tool""" key = "test_key" value = "test_value" response = await client.process_query( f"Store the key '{key}' with value '{value}'" ) # Simple verification: check if both key and value appear in response assert key in response, f"Key '{key}' not found in response: {response}" assert value in response, f"Value '{value}' not found in response: {response}" print(f"✅ Data stored successfully: {key}={value}")@pytest.mark.asyncioasync def test_retrieve_existing_data(client): """Test retrieving existing data""" key = "test_key" expected = "test_value" # First store the data await client.process_query( f"Store the key '{key}' with value '{expected}'" ) # Then retrieve it response = await client.process_query(f"Get the value for key '{key}'") assert expected in response, \ f"Expected value '{expected}' not found in response: {response}" print(f"✅ Retrieved existing data: {key}={expected}")@pytest.mark.asyncioasync def test_retrieve_nonexistent_data(client): """Test retrieving non-existent data""" key = "non_existent_key" response = await client.process_query( f"Get the value for key '{key}'. " f"Respond with 'not found' if it couldn't be found." ) assert "not found" in response.lower(), \ f"Expected 'not found' message, got: {response}" print(f"✅ Correctly handled non-existent key: {key}")
from tests.clients.LocalMCPTestClient import LocalMCPTestClientclient = LocalMCPTestClient()await client.connect_to_server_by_name("your-server")# Interactive chat loop starts# Type queries to test your server
The tests/servers/conftest.py provides pytest configuration:
import pytestimport pytest_asynciodef pytest_addoption(parser): """Add command-line options for tests""" parser.addoption( "--remote", action="store_true", help="Run tests in remote mode", ) parser.addoption( "--endpoint", action="store", default=None, help="URL for the remote server endpoint", )@pytest_asyncio.fixture(scope="function")async def client(request): """Fixture to provide a connected client for all tests""" # Automatically provides LocalMCPTestClient or RemoteMCPTestClient # based on --remote flag
# Good: Descriptive error messagesassert key in response, f"Key '{key}' not found in response: {response}"# Good: Clear expectationsassert response.status_code == 200, f"Expected 200, got {response.status_code}"# Good: Check specific conditionsassert "error" not in response.lower(), "Unexpected error in response"
# Bad: No error messageassert key in response# Bad: Vague assertionassert response# Bad: Testing too many things at onceassert key in response and value in response and "success" in response