Review: Hook + MCP fix: GroupMe send_message requires name-based resolution + user approval
Verdict: READY
Template Completeness
Assessed against consolidated spec (original issue body + Scope Expansion v1 + v2 + v3):
- [x] Lineage -- standalone incident-fix, no plan phase
- [x] Repo -- two repos identified: claude-custom (hook + settings) and groupme-mcp (tool interface)
- [x] User Story -- clear operator story about preventing data exposure
- [x] Context -- incident details, root cause analysis, fix approach all documented
- [x] File Targets -- all files specified with change descriptions (expanded across v1/v2/v3)
- [x] Acceptance Criteria -- 9 consolidated criteria covering all 5 tools, hook, tests, deploy order
- [x] Test Expectations -- unit tests for MCP tools + hook shell tests specified with location
- [x] Constraints -- patterns, live API requirement, SDK layer boundary, pagination, deploy ordering, hook test location
- [x] Checklist -- PRs, tests, doc update all listed
- [x] Related -- project pages and SOPs referenced
File Targets
claude-custom:
- [x]
hooks/block-groupme-send.sh-- NEW. Verifiedhooks/directory exists with 39 existing hooks. Pattern referenceblock-mcp-merge.shverified: reads stdin JSON, extracts fields with jq, returnspermissionDecision: "ask". 19 lines, clean pattern to follow. - [x]
settings.json-- Verified. PreToolUse section exists (lines 50-145) with pipe-delimited matcher pattern already used (e.g., line 121:mcp__forgejo__create_issue|mcp__forgejo__create_issue_and_branch). New entry formcp__groupme__send_message|mcp__groupme__add_member|mcp__groupme__remove_memberfollows established convention. - [x]
tests/directory -- Confirmed does NOT exist yet. Scope expansion v3 specifies creating it with shell-based hook tests. Clear pattern specified.
groupme-mcp:
- [x]
src/groupme_mcp/tools/messages.py-- Verified.send_message(group_id=...)at line 13. 26-line file, straightforward param rename + resolution logic. - [x]
src/groupme_mcp/tools/members.py-- Verified. Three tools:add_member(group_id=...)line 14,remove_member(group_id=...)line 51,list_members(group_id=...)line 67. All takegroup_idas first param. - [x]
src/groupme_mcp/tools/groups.py-- Verified.get_group(group_id=...)at line 42. 5th tool with stale-ID vulnerability, added in scope expansion v2. - [x]
src/groupme_mcp/server.py-- Verified. 60-line file with shared helpers (get_client,_error_response,_ok). Natural home for_resolve_group()helper. - [x] SDK layer (
groupme-sdk) -- Confirmed NOT to touch. SDK'slist_groups(page=1, per_page=10)andget_group(group_id=...)keep raw ID interface. MCP resolves above it.
Existing tests verified:
- [x]
tests/test_messages.py-- 3 tests, all usegroup_id="12345". Will need update togroup_name+ mock resolution. - [x]
tests/test_members.py-- 8 tests, all usegroup_id="12345". Same update needed. - [x]
tests/test_groups.py-- 8 tests.TestGetGroupusesgroup_id="12345". Will need update.
Repo Placement
OK. Two repos correctly identified:
forgejo_admin/claude-custom-- hook + settings.json (enforcement layer)forgejo_admin/groupme-mcp-- tool interface change (MCP layer)
Forgejo issue filed on
claude-custom which is the primary repo (hook is the enforcement gate). The groupme-mcp changes are the prerequisite dependency. Deploy ordering documented in constraints.Dependencies
- Deploy ordering (documented): groupme-mcp must deploy before claude-custom hook. Hook expects
group_nameintool_input; deploying hook first would show empty group name in prompt. - SDK pagination (documented): SDK
list_groups(page=1, per_page=10)defaults to 10 results. Currently at 10 groups -- already at the edge. Constraint added:_resolve_group()must useper_page=100or paginate. - Board dependencies: Item #357 is in
todocolumn. No blocking dependencies found on the board. No other GroupMe-related items exist.
Acceptance Criteria
All 9 consolidated criteria are testable by an implementing agent:
- "All 5 group-scoped tools accept group_name" -- testable via pytest with mock resolution
- "Shared _resolve_group() helper" -- testable via import + call
- "Ambiguous/missing group name returns helpful error" -- testable with mock list_groups returning similar names
- "PreToolUse hook fires on 3 write tools" -- testable via settings.json matcher inspection
- "Read-only tools excluded from hook" -- testable by verifying matcher pattern
- "Hook shows group name and tool-specific summary" -- testable via piping mock JSON through hook
- "Hook unit tests for all 3 write tool input shapes" -- testable by running shell test scripts
- "groupme-mcp tests updated for all 5 tools" -- testable via
pytest tests/ - "Deploy order: groupme-mcp first" -- documented constraint, verified by human
Test commands are real:
cd ~/groupme-mcp && pytest tests/ (tests directory exists with conftest.py + 3 test files). Hook tests: bash tests/test_block_groupme_send.sh (new directory, location specified in scope expansion v3).Blast Radius
- No other MCP servers affected. Grep for
group_idin claude-custom returned zero matches. The GroupMe stale-ID pattern is isolated to groupme-mcp. - create_group unaffected. Takes
name(notgroup_id) already. Correctly excluded. - list_groups unaffected. Takes no parameters. Correctly excluded.
- Downstream: pal-e-docs project page. Checklist item to update
project-groupme-westside(remove stale ID table). Low risk. - 19 existing tests will break. All use
group_id="12345". Scope correctly identifies these need updating. No silent breakage -- pytest fails immediately.
Recommendation
No action needed. The consolidated spec (original body + 3 scope expansions) is complete and agent-executable. All file targets verified against the codebase. All three prior review rounds' issues have been addressed:
- v1: all 5 group-scoped tools included, hook handles different input shapes
- v2: get_group added, hook test restored, deploy ordering documented, read-only exclusion rationale
- v3: SDK pagination constraint added, hook test location specified
Points assessment: 5 points is appropriate. Two repos, 7 files modified/created, 5 tool interfaces changed, shared helper extracted, hook with 3 input shapes, new test directory, 19+ existing tests rewritten, deploy coordination.