Problem
When no container tag is supplied—neither by the caller nor by the OAuth props—the MCP tools disagree about what they're operating on. Reads and writes go to the default project, but the listing and graph tools read across every project.
SupermemoryClient falls back to the default project in its constructor:
// apps/mcp/src/client.ts:148
this.containerTag = containerTag || DEFAULT_PROJECT_ID // "sm_project_default"
So memory and recall, which go through client.createMemory() / client.search() (both of which pass containerTag: this.containerTag), are always scoped.
But listMemories and memory-graph don't use that field—they pass containerTags to getDocuments() explicitly, and pass undefined when there's no tag:
// apps/mcp/src/server.ts:769-777 — handleListMemories
const effectiveContainerTag = containerTag || this.props?.containerTag // undefined
const result = await client.getDocuments(
effectiveContainerTag ? [effectiveContainerTag] : undefined,
page,
limit,
)
Since containerTags: undefined is omitted from the request body, the API returns documents across all projects.
The same pattern exists in:
memory-graph (server.ts:350-358)
fetch-graph-data (server.ts:422-432)
The user-visible result is that listMemories—whose tool description tells the model to use it "to audit what is on file"—enumerates documents from projects that recall can never surface and that memory never writes to. memory-graph renders those foreign documents too.
An agent auditing memories before forgetting stale ones is shown a superset of what it can actually act on.
This is the same class of scoping bug that #1215 fixed in the browser extension.
Steps to reproduce
Connect to the MCP server without a root containerTag on the OAuth props, and with memories stored in more than one project.
- Call
memory with:
{
"action": "save",
"content": "..."
}
The document is written to sm_project_default.
- Call
recall.
Only sm_project_default memories are returned.
- Call
listMemories with no containerTag.
Documents from all projects are listed, including ones that recall cannot reach.
Expected behavior
All four tools should agree on scope.
When no container tag is supplied, listMemories, memory-graph, and fetch-graph-data should read from sm_project_default, matching where memory writes and recall reads.
Actual behavior
listMemories, memory-graph, and fetch-graph-data read across every project, while memory and recall are confined to sm_project_default.
Suggested fix
Default the container tag in these handlers the same way the client constructor already does, rather than passing undefined through to the API.
The cleanest approach would be to centralize this logic in one place. SupermemoryClient already knows its own containerTag, so getDocuments() could fall back to that instead of requiring each handler to resolve it independently. That also prevents future handlers from reintroducing the same inconsistency.
Happy to open a PR.
Environment
- Repo:
main @ 2cebe815
apps/mcp (server v4.0.0)
- Not platform-specific
Problem
When no container tag is supplied—neither by the caller nor by the OAuth props—the MCP tools disagree about what they're operating on. Reads and writes go to the default project, but the listing and graph tools read across every project.
SupermemoryClientfalls back to the default project in its constructor:So
memoryandrecall, which go throughclient.createMemory()/client.search()(both of which passcontainerTag: this.containerTag), are always scoped.But
listMemoriesandmemory-graphdon't use that field—they passcontainerTagstogetDocuments()explicitly, and passundefinedwhen there's no tag:Since
containerTags: undefinedis omitted from the request body, the API returns documents across all projects.The same pattern exists in:
memory-graph(server.ts:350-358)fetch-graph-data(server.ts:422-432)The user-visible result is that
listMemories—whose tool description tells the model to use it "to audit what is on file"—enumerates documents from projects thatrecallcan never surface and thatmemorynever writes to.memory-graphrenders those foreign documents too.An agent auditing memories before forgetting stale ones is shown a superset of what it can actually act on.
This is the same class of scoping bug that #1215 fixed in the browser extension.
Steps to reproduce
Connect to the MCP server without a root
containerTagon the OAuth props, and with memories stored in more than one project.memorywith:{ "action": "save", "content": "..." }The document is written to
sm_project_default.recall.Only
sm_project_defaultmemories are returned.listMemorieswith nocontainerTag.Documents from all projects are listed, including ones that
recallcannot reach.Expected behavior
All four tools should agree on scope.
When no container tag is supplied,
listMemories,memory-graph, andfetch-graph-datashould read fromsm_project_default, matching wherememorywrites andrecallreads.Actual behavior
listMemories,memory-graph, andfetch-graph-dataread across every project, whilememoryandrecallare confined tosm_project_default.Suggested fix
Default the container tag in these handlers the same way the client constructor already does, rather than passing
undefinedthrough to the API.The cleanest approach would be to centralize this logic in one place.
SupermemoryClientalready knows its owncontainerTag, sogetDocuments()could fall back to that instead of requiring each handler to resolve it independently. That also prevents future handlers from reintroducing the same inconsistency.Happy to open a PR.
Environment
main @ 2cebe815apps/mcp(server v4.0.0)