--- name: mcp-test-suite description: Generates a comprehensive mock-based pytest test suite for a FastMCP server in pi_mcps. Use this skill when adding test coverage to a new or existing MCP server — produces conftest.py and test_server.py with 100% tool coverage and proper mock isolation. --- # MCP Test Suite ## When to use - New MCP server needs a test suite - Existing server has missing coverage - Adding new tools to an existing server ## When NOT to use - Non-MCP Python code (use standard pytest patterns) - Integration tests that actually hit external APIs (mock instead) ## Inputs required - **Server name** — `mcp-{name}` - **Tool list** — each tool's name, parameters, and return type - **External dependencies** — HTTP clients, SDKs, env vars ## Workflow ### Step 1 — Write `tests/conftest.py` ```python import sys from pathlib import Path import pytest # Make src/ importable sys.path.insert(0, str(Path(__file__).parent.parent / "src")) @pytest.fixture def mock_env(monkeypatch): """Set required environment variables.""" monkeypatch.setenv("API_KEY", "test-key") monkeypatch.setenv("API_URL", "https://test.example.com") ``` ### Step 2 — Write `tests/test_server.py` Structure per tool: ```python import pytest from unittest.mock import patch, MagicMock from server import tool_name # import directly from server module class TestToolName: def test_happy_path(self, mock_env): with patch("server.httpx.get") as mock_get: mock_get.return_value = MagicMock( status_code=200, json=lambda: {"key": "value"} ) result = tool_name("test-param") assert "expected" in result def test_error_handling(self, mock_env): with patch("server.httpx.get") as mock_get: mock_get.side_effect = Exception("Connection refused") result = tool_name("test-param") assert "error" in result.lower() def test_empty_input(self, mock_env): # edge case — empty string, None, etc. result = tool_name("") assert result is not None ``` ### Step 3 — Coverage checklist For each tool, cover: - [ ] Happy path with expected response - [ ] Network/API error (exception raised) - [ ] Empty or invalid input - [ ] Edge case specific to the tool's logic ### Step 4 — Run and verify ```bash cd mcp/{name} uv run pytest tests/ -v --tb=short ``` Expected: all tests pass, no warnings about missing coverage ### Step 5 — Store result in BigMind ``` memory_store_fact("codebase", "mcp-{name} test suite: N tests, all passing. Coverage: happy path + error + edge cases per tool.") ``` ## Troubleshooting - **ImportError on `from server import ...`:** Check `conftest.py` sys.path insert - **Mock not intercepting:** Patch the name as used in server.py, not the library's own namespace - ✅ `patch("server.httpx.get")` — patches where it's used - ❌ `patch("httpx.get")` — patches library origin (may not intercept) - **Env var not set in test:** Add to `mock_env` fixture in conftest.py