Recce recce-mcp-dev
Use when modifying recce/mcp_server.py, MCP tool handlers, error classification, or MCP-related tests. Also use when adding new MCP tools or changing tool response formats.
git clone https://github.com/DataRecce/recce
T=$(mktemp -d) && git clone --depth=1 https://github.com/DataRecce/recce "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/recce-mcp-dev" ~/.claude/skills/datarecce-recce-recce-mcp-dev && rm -rf "$T"
.claude/skills/recce-mcp-dev/SKILL.mdRecce MCP Server Development
Architecture
RecceMCPServer registers list_tools/call_tool handlers via MCP SDK Server. call_tool dispatches to _tool_* methods, classifies errors, logs/emits metrics, re-raises.
Entry point
run_mcp_server() pops single_env before passing kwargs to load_context().
Key Patterns
Error classification — Shared indicator lists defined in
recce/tasks/rowcount.py. Priority order (PERMISSION_DENIED > TABLE_NOT_FOUND > SYNTAX_ERROR) enforced by _classify_db_error() in mcp_server.py and _query_row_count() in rowcount.py. Classified → logger.warning() + sentry_metrics.count() (when sentry_sdk available). Unclassified → logger.error() + traceback.
MCP SDK quirk — Handler must raise for SDK to set
isError=True.
Response contracts — See CLAUDE.md. Additive
_meta only. summary.py: guard with is None, not dict.get(key, 0). N/A display includes reason: "N/A (table_not_found)".
Single-env —
_maybe_add_single_env_warning() adds _warning to diff results. Descriptions get conditional note.
Testing (Three Layers)
| Layer | File | Data Source | Runs In | Purpose |
|---|---|---|---|---|
| Unit | | Mock | CI () | Logic correctness — tool handlers, error classification, response format |
| Integration | | + DuckDB (fixed data) | CI () | MCP protocol works end-to-end via anyio memory streams |
| Smoke (E2E) | skill | User's real dbt project + real database | Manual | All 8 tools return valid results against real data |
Each new MCP feature or behavior change should be covered at all three layers.
Test Coverage Gap Analysis
After completing a round of MCP changes (see E2E Gate below for definition), proactively scan for missing test coverage across the three layers before asking about E2E verification.
How to check:
- Identify what changed — new tool handler? new error path? new response field?
- For each change, verify coverage exists at each layer:
- Unit: Does
have a test case for the new behavior? (happy path + error path)tests/test_mcp_server.py - Integration: Does
exercise the new tool/feature via MCP protocol?tests/test_mcp_e2e.py - Smoke: Will
template cover the new tool? (If a new tool was added, the template may need updating)/recce-mcp-e2e
- Unit: Does
If gaps are found, report them to the user before the E2E gate prompt:
Test coverage gaps found:
- Unit: missing test for
error path when table not found_tool_foo- Integration:
does not exercisetest_mcp_e2e.pytoolfoo- Smoke:
template does not include/recce-mcp-e2etoolfooWant to fill these gaps before running E2E?
Do NOT scan after: test-only changes, comment/doc edits, import reordering.
E2E Verification Gate
After each meaningful round of MCP changes, you MUST ask the user:
MCP changes complete for this round. Run
to verify?/recce-mcp-e2e
If the user says yes, invoke
/recce-mcp-e2e. If a dbt project path was used earlier in this session, reuse it automatically; otherwise ask.
What counts as "a round":
- A tool handler added or modified + its unit tests pass
- Error classification logic changed + tests pass
- Single-env or response format changed + tests pass
Do NOT ask after: test-only changes, comment/doc edits, import reordering.
This is separate from
— that file tests with DbtTestHelper + DuckDB in CI. tests/test_mcp_e2e.py
/recce-mcp-e2e verifies all 8 tools against a real dbt project with a real database.
Pitfalls
import:sentry_sdk
on except (CI always has it)# pragma: no cover- Python 3.9:
notUnion[X, Y]X | Y - Pre-commit: black/isort may reformat — re-stage and commit
run.py
try/except is intentional (ensures check creation)schema_diff_should_be_approved()
File Map
recce/mcp_server.py (server + handlers), recce/tasks/rowcount.py (error indicators, RowCountStatus), recce/run.py (CLI preset), recce/summary.py (display logic), recce/event/__init__.py (Sentry)