fix(mcp): forget ignores scope "global" when the env pins read scopes (#109) - #142
Merged
Merged
Conversation
…#109) `scope: "global"` was documented as the override that lets `forget` act on a memory in any scope. `handleForget` passed it straight through to `assertScope` and used it to widen the query-mode candidate search, so a stdio child pinned by ENGRAM_READ_SCOPES (the Hermes memory-provider transport) could delete another tenant's memories. The override now applies only when `getTenantScoping(process.env).readScopes` is undefined, i.e. the server itself is unrestricted — the one case where the override changed nothing before. Env-pinned callers get the ordinary read_scopes refusal on memory_id and see no cross-tenant candidates on query. `forgetMemory` itself is unchanged; the CLI never passes `scope`. Regression test in forget-tool.test.ts; the tool description states the rule, so the tool-schemas snapshot is re-recorded for that sentence. `read_scopes` replacing the env (rather than intersecting) is #108 and is not addressed here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyK4uwXAVufWKdSRc7VRey
…lets in CHANGELOG Conflict was only CHANGELOG.md: main added the #87 bullet under Unreleased/Fixed, this branch added the #109 bullet. Both kept. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xo3z3uv6caDhR8zjrv5QF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #109.
Problem
forgetacceptedscope: "global"from any client as an override that skipsassertScopeand widens the query-mode candidate search to every scope. A stdio child pinned byENGRAM_READ_SCOPES(the Hermes memory-provider transport) could therefore delete, or search for and delete, another tenant's memories. On an unrestricted server the override changed nothing (readScopesis alreadyundefined), so it only ever added escalation.Fix
handleForget(src/interfaces/mcp/server.ts) now honours the override only when the server's own env does not pin reads:scopefeeds bothforgetMemoryand the candidate-searchscopes.forgetMemoryitself is unchanged — the MCP handler is its only caller that can passscope(the CLI never does). The tool description states the rule, so the #119tool-schemassnapshot is re-recorded for that sentence only. README, CHANGELOG and theScopeGate.scopedoc comment updated.Not addressed:
read_scopesreplacing the env instead of intersecting (#108). Until that lands an env-pinned caller can still widen viaread_scopes; the intersection fix subsumes this guard.Tests
scope: "global" is no override when ENGRAM_READ_SCOPES pins the process (#109)intests/interfaces/mcp/forget-tool.test.ts—memory_idpath refused withoutside read_scopes, no change-log row, memory still active;query+confirmpath returnsforgotten="none"and does not list the other tenant's id.npm run test:run: 132 files / 1690 tests pass.npm run lintclean.Note: the matching one-line
CLAUDE.mdedit is deliberately not in this branch.🤖 Generated with Claude Code
https://claude.ai/code/session_01HyK4uwXAVufWKdSRc7VRey