feat(mcp): get_config tool - #132
Conversation
Resolve `<working_dir>/plumb.toml` and return the resolved Config as JSON, memoized per (path, mtime). When no config exists at the path, return Config::default() so a fresh checkout stays usable. Reject empty or relative `working_dir` with a JSON-RPC -32602 (invalid_params). Cache lives behind Arc<Mutex<HashMap<PathBuf, ConfigCacheEntry>>>; poisoned mutex maps to internal_error rather than panicking, and the cache map is read-only at the public surface so its iteration order never reaches observable output. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Spawn `plumb mcp` against an empty tempdir and assert the response text mentions the missing config, `structuredContent.source == "default"`, and the default config exposes its viewports map. Extends `mcp_initialize_and_tools_list` to assert `get_config` is advertised with the documented description and JSON Schema. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a row to the walking-skeleton tools table covering the tool's purpose and (path, mtime) memoization contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No description provided. |
|
PR #132 has merge conflicts with main (#131 |
Resolves the conflicts that arose after PR #131 (lint_url over real http(s)://) and PR #133 (delegation-guard merge bypass) merged into main while this branch carried PR #132 (get_config tool). - crates/plumb-mcp/src/lib.rs: keep both new use lines — plumb_cdp::{BrowserDriver, ChromiumDriver, ChromiumOptions, Target, is_fake_url} from main and plumb_config::ConfigError from this branch. Bring in ViewportKey alongside Config/PlumbSnapshot/etc. - Cargo.lock: union plumb-cdp and plumb-config under plumb-mcp. Note: local cargo check is blocked by a disk-space failure in the sandbox toolchain ('No space left on device' while syncing the 1.95.0 channel). Verification deferred to CI.
|
I have everything I need for a complete review. Code review summaryPR #132 — BlockersNone per the workflow-contract list. All hard-check items clear:
Warnings1. Missing invalid-args tests —
The subprocess test in 2. 3. 4. Unbounded cache growth — Architecture compliance
Anti-pattern scan
Quality assessmentThe implementation is clean: error handling is thorough, rustdoc is complete (including Scope checkAll changed files are within the declared crates ( Punch list (file:line)
Verdict: REQUEST_CHANGES |
|
Resolved the merge conflicts with
Local |
PR #129 (list_rules) merged into main while #132 (get_config) was open. Both tools touched the same MCP server surface in: - crates/plumb-mcp/src/lib.rs (tool registration, call dispatch, args) - crates/plumb-cli/tests/mcp_stdio.rs (tools/list assertion + new test) - docs/src/mcp.md (tool table) Resolution preserves both tools side-by-side: the merged ServerHandler exposes echo, lint_url, explain_rule, list_rules, and get_config. Local cargo check skipped (toolchain install blocked by sandbox disk quota); CI will validate the merge.
|
Resolved the conflicts from PR #129 ( |
Target branch
mainSpec
Fixes #37
Summary
get_configMCP tool returns the resolvedplumb.tomlfor a caller-supplied working directory as JSON-serialized [Config].(path, mtime)via anArc<Mutex<HashMap<PathBuf, ConfigCacheEntry>>>shared acrossCloneinstances ofPlumbServer. Cache is internal-only — never iterated, so the determinism rule banningHashMapin observable output is preserved.plumb.tomlexists at the requested path, the tool returnsConfig::default()withsource = "default"so a fresh checkout still gets a usable answer.Crates touched
plumb-coreplumb-formatplumb-cdpplumb-configplumb-mcpplumb-cli(test only)xtaskdocs/.agents/or.claude/.github/System impact
PlumbServer::get_config,GetConfigArgs) — rustdoc +# Errorssection included.tools/listentry + happy-path protocol test added.plumb-mcpnow depends onplumb-config(which depends only onplumb-core; layering preserved).Architectural compliance
plumb-mcp→plumb-config→plumb-coreis allowed; no cycles, nounsafeintroduced, noprintln!outsideplumb-cli.ErrorData::invalid_paramsfor empty / non-absoluteworking_dir;ErrorData::internal_errorfor stat / parse / serialize / poisoned-mutex paths. Noanyhowadded.unwrap/expect/panic!in library crates — everyMutex::lockandserde_json::to_valueis mapped to a typed error.SystemTime::now/Instant::now.metadata.modified()is a filesystem read used only for cache-equality, not a clock read.HashMapin observable output. The internal cache is never iterated; output ordering of the JSON config comes fromConfig'sIndexMapfields.#[allow(...)]attributes added.Test plan
cargo fmt --all -- --checkclean.cargo clippy -p plumb-mcp -p plumb-cli --all-targets --all-features -- -D warningsclean.cargo nextest run -p plumb-mcp -p plumb-cli— 58/58 pass, including the newmcp_get_config_returns_default_when_no_fileprotocol test and the extendedmcp_initialize_and_tools_listassertion.just validate— will run as part of CI / final test gate; not yet executed locally (skeleton milestone).cargo xtask pre-release— N/A (no rule or schema change).just determinism-check— will run in CI.cargo deny check— will run in CI (one new internal dep edge:plumb-mcp→plumb-config).Documentation
GetConfigArgsandPlumbServer::get_config, including a# Errorssection.# Errorssection on every new public fallible fn — covered.docs/src/mcp.mdtool table extended.feat(mcp):Conventional Commits.Breaking change?
Checklist
codex/37-feat-mcp-get-config./gh-review --local-diff main...HEAD— will run after this initial PR is up so reviewers see the same scope as CI.Reviewer notes
working_dirargument is required and must be absolute. This avoids reading process state (current dir / env) inside a tool call and keepsget_configdeterministic.PathBuf, so two distinct working directories cohabit. There is no eviction yet; an MCP session lives for a CLI run, so the cache stays small in practice.source = "default"is surfaced explicitly so an agent can distinguish "no config exists" from "config exists and happens to match defaults" without a separate probe.