Skip to content

MCP: listMemories and memory-graph read across every project while memory and recall are scoped to the default project #1246

Description

@rajarshidattapy

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.

  1. Call memory with:
{
  "action": "save",
  "content": "..."
}

The document is written to sm_project_default.

  1. Call recall.

Only sm_project_default memories are returned.

  1. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions