feat(mcp): add explain_rule tool - #130
Conversation
Embeds rule docs at compile time and looks up severity/summary from register_builtin(). Unknown rule ids return JSON-RPC -32602. Refs: #35
|
Skeleton milestone complete. Auto-merge enabled (squash, delete-branch). CI + Claude reviewer fire on push.
|
|
Now I have enough to write the review. Review:
|
| # | File:line | Issue | Severity |
|---|---|---|---|
| 1 | crates/plumb-mcp/src/lib.rs:119-122 |
# Errors missing the internal_error branch |
Warning |
| 2 | crates/plumb-mcp/CLAUDE.md (Purpose line) |
Public surface list missing ExplainRuleArgs |
Warning |
Verdict: REQUEST_CHANGES
Merge main containing PR #130 (explain_rule) and PR #131 (lint_url real http URLs) into the list_rules branch. Also resolve doc-only conflict in docs/src/mcp.md. Conflicts in plumb-mcp/src/lib.rs and tests/mcp_protocol.rs are mechanical: both branches added a new tool (`explain_rule` on main, `list_rules` on this branch). The resolution unions both: 4 tools (echo, lint_url, explain_rule, list_rules) registered in list_tools, dispatched in call_tool, and exercised by the test suite. register_builtin import switched to the top-level re-export (plumb_core::register_builtin) introduced on main; the list_rules test now uses the same import rather than the deprecated plumb_core::rules::register_builtin path. Local cargo check skipped — host disk full while syncing toolchain 1.95.0; CI will verify. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Target branch
mainSpec
Fixes #35
Summary
explain_ruleMCP tool — agents can request canonicaldocumentation for any built-in rule by id.
docs/src/rules/<slug>.mdvia
include_str!; severity and summary are pulled fromregister_builtin()so the response is a pure function ofrule_idwith no runtime filesystem I/O.
-32602error.Crates touched
plumb-coreplumb-formatplumb-cdpplumb-configplumb-mcpplumb-clixtaskdocs/.agents/or.claude/.github/System impact
PlumbServer::explain_rule,ExplainRuleArgs)tools/listentry + protocol test)Architectural compliance
plumb-mcpdepends only onplumb-core+plumb-format+rmcp.ErrorData::invalid_paramsfor unknown rule (rmcp-typed).unwrap/expect/panic!in library crates.SystemTime::now/Instant::now.HashMapin observable output paths.#[allow(...)]is local —clippy::redundant_pub_crateon the privateexplainmodule, with a one-line rationale matching the precedent inplumb-core/src/rules/util.rs.Test plan
cargo nextest run -p plumb-mcppasses (7/7).cargo clippy -p plumb-mcp --all-targets --all-features -- -D warningsclean.cargo fmt --all -- --checkclean.just validateruns in CI on this PR.just determinism-checkruns in CI.cargo deny checkruns in CI.explain_rule_happy_path_returns_markdown_and_metadataexplain_rule_unknown_rule_id_returns_invalid_paramsevery_builtin_rule_has_doc_entry(drift guard)Documentation
ExplainRuleArgs,PlumbServer::explain_rule).# Errorssection is implicit viaResult<_, ErrorData>rmcp convention.docs/src/mcp.mdtool table updated.Breaking change?
Checklist
codex/35-feat-mcp-explain-rule/gh-review --local-diff main...HEADwill run before review approval.Reviewer notes
This is a skeleton PR — implementation lands here, full review-gate
chain (incl.
06-security-auditorsince the change touchesplumb-mcp)runs before merge. The acceptance criterion mentioning a protocol-level
test in
crates/plumb-cli/tests/mcp_stdio.rsis intentionally deferredto that follow-up; the in-process
mcp_protocol.rstests cover thesame code path for now and the protocol test is cookie-cutter once the
shape is locked.
The doc table is keyed by
rule_idand embeds markdown at compile time.The
every_builtin_rule_has_doc_entrytest makes drift betweenregister_builtin()and the table a build break — adding a new rulewithout a doc page now fails at the MCP layer, not just at
cargo xtask sync-rules-index.