Skip to content

fix(mcp): scope recall_query to the current project#42

Merged
tznthou merged 1 commit into
mainfrom
fix/recall-query-project-scope
May 24, 2026
Merged

fix(mcp): scope recall_query to the current project#42
tznthou merged 1 commit into
mainfrom
fix/recall-query-project-scope

Conversation

@tznthou
Copy link
Copy Markdown
Owner

@tznthou tznthou commented May 24, 2026

What

The recall_query MCP tool was searching across all projects instead of the current one. This scopes it to the current project, matching the other three entry points.

Root cause

recall_query was born in the MCP skeleton (1238d98) before the project_id mechanism existed. Scoping arrived in phase-4b (c2b8262); when query handlers were rewired in phase-4c (14debcc), recall_context picked up projectId but recall_query was missed — it called db.queryMemories(query, limit) with no projectId, hitting the no-filter (all-project) branch.

The project-scoped contract was an explicit early-development decision: cross-project visibility ("global") was rejected as unacceptable for an open-source tool — users expect project isolation. recall_context / recall_save / HTTP /memory/query all honor it; recall_query was the lone gap.

Change

  • recallQueryInput: add required projectId (z.string().min(1), mirrors recall_context verbatim)
  • recallQueryHandler: thread projectId into db.queryMemories + appendRecallTelemetry (telemetry projectId was hardcoded null, which also broke per-project grouping)
  • tests: add cross-project isolation test (proj-a/proj-b — verified red when scoping is removed); scope existing recall_query + touch-integration tests to proj-a

Side effect (intended)

Cross-project "accidental hits" disappear, so cold-rate figures may rise. But the prior baseline was inflated by this bug — post-fix numbers reflect true project-scoped recall.

Quality gate (gogo)

  • Codex adversarial review: 2 findings, both judged out-of-scope — no code change
  • Simplify: diff already minimal (projectId mirrors recall_context)
  • Security (OWASP Top 10:2025): A01 scoping logic / A05 SQL parameterization / A09 log injection / A10 fail-closed — all secure
  • Verify: build / lint / test (599) all green

Follow-up

Codex flagged that client-supplied projectId could be forged (server-side binding would be stronger). Pre-existing all-MCP design question, outside the current local / trusted-caller threat model. Tracked in #41.

🤖 Generated with Claude Code

recall_query called db.queryMemories without projectId, searching across
ALL projects instead of the current one. This violates the project-scoped
contract: cross-project visibility was explicitly rejected early in
development as unacceptable for an open-source tool. recall_context,
recall_save and HTTP /memory/query all pass projectId — recall_query was
the lone gap (it predates the project_id mechanism and was missed when
query handlers were later rewired).

- recallQueryInput: add required projectId (mirrors recall_context)
- handler: thread projectId into queryMemories + telemetry (was hardcoded
  null, which also broke per-project telemetry grouping)
- tests: add cross-project isolation test; scope existing tests to proj-a

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tznthou tznthou merged commit 4bf9271 into main May 24, 2026
3 checks passed
@tznthou tznthou deleted the fix/recall-query-project-scope branch May 24, 2026 07:18
tznthou added a commit that referenced this pull request May 24, 2026
Scope recall_query to the current project (#42). The MCP recall_query
tool was searching across all projects; it now takes a required
projectId like the other entry points. Follow-up on client-supplied
projectId trust tracked in #41.

Co-Authored-By: Claude Opus 4.7 (1M context) <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.

1 participant