feat(mcp): add drt_doctor tool + drt_run_sync(compute_diff=True) CLI parity#628
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…parity
The MCP server picked up two pieces that had been shipped on the CLI
for months but weren't reachable from Claude / Cursor:
1. **`drt_doctor`** — mirrors `drt doctor` (v0.7.0+) and returns a
structured `{"passed": bool, "checks": [...]}` report. Categories:
- runtime (Python version + drt version)
- project (drt_project.yml, profile, syncs/)
- extras (per-extra install status)
- env (relevant env vars + masked values)
``passed`` is False only when a required check fails (project file
/ profile / Python version); missing optional extras don't flip it.
Implementation reuses the ``_check_*`` helpers in ``drt/cli/doctor.py``
to avoid duplicating orchestration logic. No CLI changes.
2. **`drt_run_sync(compute_diff=True, diff_limit=20)`** — matches the
`drt run --dry-run --diff` CLI (#413, v0.7.1+). When set with
``dry_run=True``, the response carries a structured ``diff`` field
serialised via the existing ``cli/output.diff_to_dict`` helper, so
the LLM can preview added / updated / deleted / unchanged records
for queryable destinations before committing.
``compute_diff=True`` without ``dry_run=True`` returns a structured
error rather than silently running against a live destination —
matches the CLI's `--diff requires --dry-run` contract.
Docstring + README catch-up:
- Module docstring lists the now-complete tool surface (9 tools)
- `drt_get_history` — registered in code since #445 but missing from
the docstring — is now listed there too
- README.md + README.ja.md MCP tool tables updated to the 9-tool list
(was 6, missing run_test / get_history / doctor)
- CHANGELOG `[Unreleased] → Changed (Internal)` entry
Tests:
5 new tests in tests/unit/test_mcp.py:
- `test_server_lists_drt_doctor_tool` — registration check
- `test_run_sync_compute_diff_requires_dry_run` — contract error path
- `test_doctor_returns_structured_report` — shape contract
- `test_doctor_passes_on_well_formed_project` — happy path on the
fixture project + a fake HOME with profiles.yml
- `test_doctor_fails_without_project_file` — `passed=False` path
Existing 14 MCP tests unchanged. Full unit + contracts suite: 1466
passed. lint + mypy clean.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…ge above codecov target) codecov/patch on the prior commit hit 81.81% (target 85.86%) — the gate passed but below the bar. All uncovered lines were in ``drt_run_sync``: the existing tests only exercised error paths (``compute_diff requires dry_run`` + the unknown-sync error path wasn't even tested at all), so the success branch (load_project / run_sync / response with optional diff) ran zero times. Adds 3 tests that drive the success branch via monkeypatched engine + factory + serializer doubles: 1. `test_run_sync_returns_error_for_unknown_sync` — unknown sync_name short-circuit (line 114). Needed a load_profile mock too because the profile check fires before the sync match in the flow. 2. `test_run_sync_compute_diff_threads_diff_into_response` — compute_diff=True + dry_run=True success path. Verifies the diff field is built via diff_to_dict and the value flows through to the response. 3. `test_run_sync_dry_run_without_compute_diff_omits_diff_field` — compute_diff=False (default) success path. Verifies the diff branch is skipped and ``response`` doesn't carry a diff key. drt/mcp/server.py file coverage: 71% → 83%. My patch diff coverage should now hit ~100% — remaining unhit lines are all pre-existing untested tools (drt_run_test internals at 206-224, drt_get_history body at 300-305, drt_list_connectors body at 360, outer ``def run()`` at 473-474, fastmcp ImportError fallback at 29-30) — none of which are in this PR's diff. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
7c07b85 to
8b175f8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two MCP tools that had been shipped on the CLI for months but weren't reachable from Claude / Cursor:
drt_doctor— mirrorsdrt doctor(v0.7.0, good first issue: add drt doctor command (environment check) #264)drt_run_sync(compute_diff=True)— mirrorsdrt run --dry-run --diff(v0.7.1, feat: drt diff — show record-level diff in dry-run mode #413)This closes the visible part of the MCP-vs-CLI gap. Part of the broader skill/MCP refresh sequence triggered by "skillやMCPに最新の情報が載っていないのは困ります".
What
drt_doctorreturns{ "passed": true, "checks": [ {"category": "runtime", "name": "Python version", "ok": true, "message": "3.12.12 ✅"}, {"category": "runtime", "name": "drt version", "ok": true, "message": "0.7.8"}, {"category": "project", "name": "Project file", "ok": true, "message": "✅"}, {"category": "project", "name": "Profile", "ok": true, "message": "✅ default"}, {"category": "project", "name": "Syncs", "ok": true, "message": "✅ 1 sync file"}, {"category": "extras", "name": "bigquery", "ok": false, "message": "❌ not installed (pip install drt-core[bigquery])"}, ... ] }passedis False only when a required check fails (project file / profile / Python version); missing optional extras don't flip it. Reuses the_check_*helpers indrt/cli/doctor.py— no CLI changes, no duplicated orchestration.What
drt_run_syncaddsTwo new parameters, both default
False/20:When set with
dry_run=True, the response carries a structureddifffield via the existingcli/output.diff_to_dictserialiser, so an LLM can preview added / updated / deleted / unchanged records for queryable destinations before committing.Contract:
compute_diff=Truewithoutdry_run=Truereturns a structured error rather than running against a live destination. Matches the CLI's--diff requires --dry-runcontract.Docstring + README catch-up
run_test+get_history+ newdoctor)drt_get_history— registered in code since feat: sync execution history — drt status --history + drt_get_history MCP tool (#276) #445 but missing from the docstring — is now listed there[Unreleased] → Changed (Internal)entryTests
5 new tests in
tests/unit/test_mcp.py:test_server_lists_drt_doctor_tooltest_run_sync_compute_diff_requires_dry_runtest_doctor_returns_structured_report{passed, checks}+ per-check keystest_doctor_passes_on_well_formed_project~/.drt/profiles.ymltest_doctor_fails_without_project_filepassed=FalsepathTest plan
pytest tests/unit/test_mcp.py— 19 passed (14 existing + 5 new)make lint— ruff + mypy cleanOut of scope (deliberate)
drt_list_connectorsdoesn't yet enumerate Mixpanel / Amazon S3 / Twilio / Intercom / Email SMTP / Salesforce Bulk / Staged Upload / Google Ads / Amplitude / Zendesk — a separate drift. Keeping this PR focused on the two flagged gaps.Sequence
This is the MCP leg of the skill / MCP refresh:
🤖 Generated with Claude Code