Skip to content

feat(#489): fire the MCP-search advisory on Read/Glob/Grep for workspace paths#490

Merged
atlas-apex merged 1 commit into
me2resh:devfrom
atlas-apex:feature/GH-489-mcp-advisory-read-glob-grep
Jun 3, 2026
Merged

feat(#489): fire the MCP-search advisory on Read/Glob/Grep for workspace paths#490
atlas-apex merged 1 commit into
me2resh:devfrom
atlas-apex:feature/GH-489-mcp-advisory-read-glob-grep

Conversation

@atlas-apex

Copy link
Copy Markdown
Collaborator

Summary

  • Closes the Read/Glob/Grep bypass — the suggest-mcp-search advisory previously only fired on Bash tool calls. An agent could sidestep the nudge entirely by reaching for Read, Glob, or Grep against a workspace-clone path, which never triggered the banner. This PR extends the hook to cover all three tools when the target path is inside workspace/<project>/.
  • Workspace-scoped, not blanket — the new Read/Glob/Grep branch only fires when the resolved path contains workspace/. Framework file reads (e.g. Read roles/engineering/tech-lead.md) are untouched and stay silent, preserving the original behaviour's intent that the nudge only applies to managed-project code lookups.
  • Install-gate fully preserved for all tools — the load-bearing apexyard-search check in .mcp.json applies equally to the new Read/Glob/Grep branch. Free adopters who don't have the premium apexyard-search MCP configured will see nothing from this hook regardless of which tool they use. This was an explicit requirement and is verified by three dedicated test cases (one per tool in the no-MCP fixture).
  • settings.json wired — a new Read|Glob|Grep PreToolUse matcher block invokes the same ops-root-resolving hook wrapper already used by the Bash entry.

Testing

# All 23 cases pass, 0 failures
bash .claude/hooks/tests/test_suggest_mcp_search.sh

# Hook count unchanged (edited existing file, did not add one)
bash .claude/hooks/tests/test_site_counts.sh

# shellcheck clean
shellcheck .claude/hooks/suggest-mcp-search.sh

Test coverage added (#489 cases):

  • Read/Glob/Grep on workspace/<project>/... path WITH apexyard-search configured → advisory fires
  • Read/Glob/Grep on workspace/<project>/... path WITHOUT apexyard-search (free adopter) → silent
  • Read/Glob/Grep on paths OUTSIDE workspace/ (framework files, src/, etc.) → silent
  • Write/Edit tools on workspace paths → silent (only Bash/Read/Glob/Grep are in scope)
  • All original Bash cases unchanged and passing

Glossary

Term Definition
advisory hook A PreToolUse hook that emits guidance as hookSpecificOutput.additionalContext JSON on stdout and always exits 0 — never blocks the tool call
install-gate The .mcp.json check that ensures the hook stays silent for free adopters who don't have the apexyard-search premium MCP configured
workspace clone A local working copy of a registered managed project, living under workspace/<name>/ in the ops repo
MCP-first The framework guideline to prefer apexyard-search semantic search over grep/Read for managed-project code lookups (~3–5× fewer tokens)

Closes #489

…ace paths

Extends suggest-mcp-search.sh to also fire on Read, Glob, and Grep
PreToolUse events when the target path resolves inside a managed-project
workspace clone (workspace/<project>/). Previously an agent could sidestep
the nudge by using native read tools instead of Bash; this closes that gap.

- Hook tool gate: case-branch on Bash (original path) vs Read|Glob|Grep
  (new path); any other tool exits 0 immediately.
- Path extraction for Read/Glob/Grep: .tool_input.file_path // .tool_input.path
  covers all three tools in one jq query.
- Workspace guard: new branch exits 0 when the path is NOT under workspace/.
- Install-gate fully preserved: the apexyard-search .mcp.json check applies
  to ALL tools — free adopters without the premium MCP see nothing.
- settings.json: new Read|Glob|Grep PreToolUse matcher block wired to the
  same hook wrapper as Bash.
- Tests: 23 cases (up from 9) — Read/Glob/Grep fire on workspace paths
  (gate open), stay silent outside workspace/, stay silent with gate closed
  (the load-bearing free-adopter case), Write/Edit not triggered.

Closes #489

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@atlas-apex atlas-apex left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: PR #490

Commit: 8255f5bf72ef63dac1c7ea6ab22e1adfa8488714

Note: submitted as a comment because GitHub blocks self-approval on this PR. The Rex verdict is APPROVED and the 490-rex.approved marker has been written with the matching HEAD SHA.

Summary

Extends the suggest-mcp-search advisory hook from Bash-only to also fire on Read/Glob/Grep when the target path is inside a managed-project workspace clone (workspace/<project>/), closing the bypass where an agent could sidestep the MCP-first nudge by using native read tools. Bash behaviour is unchanged; the install-gate (only nudge when apexyard-search is in .mcp.json) is preserved for all tools.

Checklist Results

  • ✅ Architecture & Design: Pass — clean case/if branch dispatch, shared install-gate at the convergence point
  • ✅ Code Quality: Pass — shellcheck -S warning clean, well-commented field-layout rationale
  • ✅ Testing: Pass — 23/23 cases, incl. 3 load-bearing free-adopter no-banner cases
  • ✅ Security: Pass — advisory-only, no secrets, no injection surface
  • ✅ Performance: Pass — hot-path is a single jq + case match
  • ✅ PR Description & Glossary: Pass — narrative Summary calls out the free-adopter gate; Glossary present; Closes #489
  • ⚠ Summary Bullet Narrative: Pass — bullets answer what + why
  • ✅ Technical Decisions (AgDR):N/A — extends an existing hook, no new dependency/pattern
  • ✅ Adopter Handbooks: N/A — no handbooks triggered by this diff

Issues Found

None.

Verification performed (load-bearing checks)

  1. Install-gate preserved (the explicit CEO requirement). Read the hook end-to-end: the Read/Glob/Grep branch (lines 104-125) only does path filtering, then falls through to the shared install-gate $mcp_has_search || exit 0 at line 145 — it is NOT bypassed. Confirmed adversarially:
    • Read on workspace/... with apexyard-search ABSENT from .mcp.jsonSILENT (free adopter sees nothing). ✅
    • Read on workspace/... with apexyard-search PRESENT → banner fires. ✅
  2. Path extraction. .tool_input.file_path // .tool_input.path // empty correctly covers Read (file_path) and Glob/Grep (path); absent path → exit 0 (verified, no banner). Workspace check (*workspace/*) mirrors the Bash branch intent.
  3. Bash branch byte-identical in effectgrep -rn on a workspace path still fires; original framework/workspace pattern scanner untouched.
  4. Advisory/non-blocking — exit 0 in every path; banner emitted as hookSpecificOutput.additionalContext JSON on STDOUT, matching the #469 channel.
  5. settings.json — valid JSON; new Read|Glob|Grep matcher uses the identical ops-root-resolving bash -c wrapper; existing Bash/Edit-Write matchers undisturbed.
  6. Tests + linttest_suggest_mcp_search.sh 23 passed / 0 failed; test_site_counts.sh green (hooks count unchanged at 38 — edited existing file); shellcheck -S warning exit 0.

Suggestions

None blocking. Optional future thought: if Claude Code ever adds a tool that carries a path under a third field name, the file_path // path pattern would need extending — the inline comment already documents the schema, so this is covered for now.

Verdict

APPROVED


🤖 Reviewed by Rex (Code Reviewer Agent)
📌 Reviewed commit: 8255f5bf72ef63dac1c7ea6ab22e1adfa8488714

@atlas-apex atlas-apex merged commit 945d6f4 into me2resh:dev Jun 3, 2026
3 checks passed
me2resh added a commit that referenced this pull request Jun 5, 2026
…ace paths (#490)

Extends suggest-mcp-search.sh to also fire on Read, Glob, and Grep
PreToolUse events when the target path resolves inside a managed-project
workspace clone (workspace/<project>/). Previously an agent could sidestep
the nudge by using native read tools instead of Bash; this closes that gap.

- Hook tool gate: case-branch on Bash (original path) vs Read|Glob|Grep
  (new path); any other tool exits 0 immediately.
- Path extraction for Read/Glob/Grep: .tool_input.file_path // .tool_input.path
  covers all three tools in one jq query.
- Workspace guard: new branch exits 0 when the path is NOT under workspace/.
- Install-gate fully preserved: the apexyard-search .mcp.json check applies
  to ALL tools — free adopters without the premium MCP see nothing.
- settings.json: new Read|Glob|Grep PreToolUse matcher block wired to the
  same hook wrapper as Bash.
- Tests: 23 cases (up from 9) — Read/Glob/Grep fire on workspace paths
  (gate open), stay silent outside workspace/, stay silent with gate closed
  (the load-bearing free-adopter case), Write/Edit not triggered.

Closes #489

Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants