VeryGoodOpenSource / VeryGoodOpenSource/vgv-ai-flutter-plugin
fix: check-vgv-cli decides for every tool, not just Very Good CLI ones
Nobody has claimed this yet.
- Dominant language
- Shell
- Stars
- 162
- Forks
- 23
- Avg merge
- 2d 22h
- Merged PRs (30d)
- 4
Description
Description
check-vgv-cli.sh never reads its stdin payload. It runs check_vgv_cli and emits a
deny/allow decision for whatever tool invoked it, trusting the matcher in
hooks/hooks.json to scope it. On a host where that matcher does not select correctly, the
hook decides for every tool call — a Dart tool-version check blocking browser-automation MCP
tools in a TypeScript/Next.js project with no Dart in it.
Reported from Cursor, where the plugin's hooks are picked up from a global
~/.claude/plugins/ install. Three faults stack.
1. The matcher cannot match under Cursor's tool-naming convention
The matcher is written in Claude Code's MCP naming, mcp__<server>__<tool>:
{ "matcher": "mcp__.*very-good-cli__.*", "hooks": [{ "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/check-vgv-cli.sh" }] }
Cursor names MCP tools MCP:<tool>. Captured preToolUse payload from Cursor 3.20.17 for a
browser MCP call, with the hook logging its own stdin:
{
"tool_name": "MCP:browser_tabs",
"tool_input": { "action": "list" },
"hook_event_name": "preToolUse",
"cursor_version": "3.20.17"
}
mcp__.*very-good-cli__.* cannot match MCP:browser_tabs — different separator, no server
segment. And the hook ran anyway, which is how that payload was captured. So under Cursor a
non-matching matcher is not exclusionary.
Note tool_name carries no server name under Cursor — a Very Good CLI test call arrives as
MCP:test, indistinguishable by name from any other server's test.
2. Both PreToolUse hooks decide without checking tool identity
check-vgv-cli.sh reads no payload at all:
$ echo '{"tool_name":"MCP:browser_tabs","tool_input":{"action":"list"}}' | bash hooks/scripts/check-vgv-cli.sh
{"hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason":"Very Good CLI is not installed. ..."}}
The inverse is worse: when the CLI is present the same blind path returns allow, silently
auto-approving unrelated MCP tool calls and bypassing the permission prompt.
block-cli-workarounds.sh has the same class of bug with a narrower trigger. It filters on
.tool_input.command — a field name, not tool identity — so any MCP tool carrying a command
argument is inspected and can be denied:
$ echo '{"tool_name":"MCP:run_terminal_cmd","tool_input":{"command":"flutter test"}}' | bash hooks/scripts/block-cli-workarounds.sh
{"hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason":"Do not use 'flutter test' or 'dart test'. ..."}}
Its matcher: "Bash" cannot match Cursor's Shell tool either, so it is equally unscoped there.
analyze.sh and format.sh are the only hooks that reliably stand aside.
3. The CLI lookup fails on a restricted PATH even when the CLI is installed
check_vgv_cli() resolves the binary with command -v very_good and nothing else.
dart pub global activate installs to ~/.pub-cache/bin, which is added by an interactive shell
rc and is not in /etc/paths. On the affected machine very_good --version reports 1.5.0,
yet the hook reported it missing.
A pub-cache fallback alone is not sufficient. The installed very_good is a sh shim that execs
dart:
$ env -i HOME=$HOME PATH=/usr/bin:/bin:/usr/sbin:/sbin ~/.pub-cache/bin/very_good --version
~/.pub-cache/bin/very_good: line 8: dart: command not found (exit 127)
So an inconclusive check is currently indistinguishable from "not installed", and both produce a
deny.
Steps To Reproduce
- Install the plugin on a machine where
very_goodlives in~/.pub-cache/bin. - Open any project — a non-Dart one makes the point clearest.
- Call any MCP tool that is not a Very Good CLI tool (e.g. a browser MCP
navigate). - The call is denied with "Very Good CLI is not installed".
Driving the scripts directly reproduces each fault without a host:
$ echo '{"tool_name":"MCP:browser_tabs","tool_input":{"action":"list"}}' | bash hooks/scripts/check-vgv-cli.sh
$ echo '{"tool_name":"MCP:run_terminal_cmd","tool_input":{"command":"flutter test"}}' | bash hooks/scripts/block-cli-workarounds.sh
$ env -i HOME=$HOME PATH=/usr/bin:/bin:/usr/sbin:/sbin ~/.pub-cache/bin/very_good --version
Expected Behavior
A hook decides only for the tools it is responsible for. A Very Good CLI version check should
stand aside for any tool that is not a Very Good CLI tool, regardless of how a host applies
matcher, and should never deny — or silently auto-approve — an unrelated MCP call.
An inconclusive version check should not be reported as "not installed".
Additional Context
- Version:
vgv-ai-flutter-plugin0.0.5 viavery-good-claude-code-marketplace1.0.5. - Related but distinct: #147 is over-blocking in
block-cli-workarounds.shvia command-string
parsing; the fault here is that the script inspects tools that are not its business at all. - #48 places Cursor at experimental tier with no guaranteed hook parity. This is not a request
for parity — the hooks are already active on that host today and are blocking unrelated work.
Fault 2 makes the plugin safe there regardless of whether parity is ever pursued. - #126 workstream 4 covers factoring hooks for multi-host adaptation. Scoping every hook on
tool_nameis a prerequisite for that work. - Open question for a follow-up, not required for the fix: because Cursor's
preToolUse
tool_namehas no server segment, a*very-good-cli*guard stands aside for genuine Very Good
CLI calls under Cursor, so the auto-approve is lost there. That is fail-safe. Restoring it
needs either matching bare tool names (create,test, ...), which collide across MCP
servers, or Cursor's dedicatedbeforeMCPExecutionevent.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with hooks/hooks.json, hooks/scripts/check-vgv-cli.sh, and hooks/scripts/block-cli-workarounds.sh, then reproduce the supplied stdin cases under a restricted PATH. Trace how each script identifies tools and reports version-check outcomes. Done means unrelated tool calls are left alone and inconclusive CLI checks are not reported as missing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart, shell
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100