Rename the read-only scan verb to `vigiles audit` — a local, zero-config Lighthouse-style report scoring a harness across four deterministic rings (Truthfulness/Triggering/Structure/Tested) with each finding's fix inline + a shareable HTML report and a versioned AuditReport JSON.
audit is a local report, not a CI step (CI uses `vigiles lint`). The executing checks (live MCP resolution + trigger-rate + the adoption preview) run only behind one interactive consent; there is no execution flag. The safety battery is not an audit ring — it lives in the vigiles/testing API.
Adds the adoption-gateway preview ("what would vigiles catch in your repo?"): the model drafts a spec from the instruction file, the cross-reference engine verifies every drafted ref deterministically.
BREAKING CHANGE: the `scan` verb is renamed to `audit` (no alias); the `--check-hooks`/`--verify-mcp`/`--trigger`/`--fix-plan`/`--explain`/`--deep`/`--measure`/`--fast`/`--no-measure` flags are removed.
2.8 KiB
mcp-hook-target-resolves
Cross-reference a type: "mcp_tool" hook action against the plugin's declared
MCP servers. Claude Code hooks support five action types (command / http /
mcp_tool / prompt / agent); an mcp_tool action calls a tool on an
already-connected MCP server and requires a server + tool field. This rule
flags two ways it silently never dispatches. Same detector vigiles audit uses
(verifyMcpHookTargets in src/core/mcp-hook.ts).
It extends the tool cross-reference to the hook surface — sibling of
mcp-tool-resolves (a subagent's mcp__server__tool) and
mcp-config (a server that can't start).
What it flags
"hooks": {
"PreToolUse": [{ "matcher": "Bash", "hooks": [
{ "type": "mcp_tool", "server": "github", "tool": "search" }, // ✓ declared
{ "type": "mcp_tool", "server": "linear", "tool": "create" }, // ✗ undeclared server
{ "type": "mcp_tool", "server": "github" } // ✗ incomplete (no tool)
]}]
}
- Incomplete — an
mcp_toolaction missingserverortool. Unambiguous (it can't dispatch), so always flagged, likemcp-config. - Undeclared server — the
serverisn't in the plugin'smcpServers. High-precision: only flagged when the plugin ships a declared set (else the server may be user-global/project, unknowable), and harness built-ins (ide) are allowlisted — exactly themcp-tool-resolvescalibration.
A command/http/prompt/agent action is ignored. The matcher surface (a
mcp__server__.* matcher naming an undeclared server) is a separate regex-shaped
concern left to a future hook-matcher rule.
Configuration
{ "rules": { "mcp-hook-target-resolves": "warn" } }
Severity
| Value | Behavior |
|---|---|
"error" |
vigiles lint exits non-zero (2) on an offending hook action |
"warn" (default) |
Prints a warning, exits 0 |
false |
Skip the check |
Scope
Hook actions in .claude/settings.json and the plugin manifest
(.claude-plugin/plugin.json); declared servers read from .mcp.json + the
manifest mcpServers.
Why
An mcp_tool hook is deterministic machinery that depends on an MCP server being
present; one pointed at a server the plugin never declares (or missing its target
fields) is a silent no-op — the author believes the automation runs when it can't.
See also
- mcp-tool-resolves — the same cross-reference for a
subagent's
tools:. - mcp-config — a declared MCP server that can't start.