feat(roo): add Patrick-persona custom modes, skills, and mode-specific rules
Add 4 new custom modes with BigMind guidance: - rules-bigmind/: Introspective Patrick mode (BigMind development) - rules-homelab/: Tinkerer Patrick mode (TrueNAS, Docker, infra) - rules-mcp-builder/: Craftsman Patrick mode (pi_mcps MCP servers) - rules-paisy/: Professional Patrick mode (ADP Germany payroll) Add reusable skills: - skills/assessment-first/: structured assessment.md before implementation - skills/bigmind-session-ritual/: mandatory session start/end ritual - skills/gitea-push/: conventional commit + Gitea push workflow - skills/new-mcp-server/: FastMCP scaffold procedure - skills-bigmind/, skills-homelab/, skills-mcp-builder/, skills-paisy/: mode-specific skill dirs Update existing rules: - rules-architect, rules-ask, rules-code, rules-debug, rules-orchestrator: add BigMind session guidance (search before task, announce focus, hypotheses) Add plans/MODES_AND_SKILLS_PLAN.md: full architecture document
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
---
|
||||
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
|
||||
Reference in New Issue
Block a user