Paginate list reads; cap the MCP list_memories tool#70
Merged
Conversation
GET /api/v1/memories gains offset (0-10000) alongside limit, and responses carry a pagination object with has_more so the full store is enumerable. The MCP list_memories tool, previously unbounded (it returned the entire store into the model's context), now defaults to a page of 50 (max 100) with the same offset/has_more contract. mem0's get_all has no offset parameter, so list_paginated() in app/memory.py emulates it: over-fetch offset+limit+1, slice, and use the extra item as the has_more signal. This keeps mem0's result shaping intact and avoids coupling to private vector-store APIs; the offset cap bounds the per-request fetch. Closes #65 https://claude.ai/code/session_01H2Dbh6kD8bseWZZEf7kGhx
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 #65
What
list_memoriesis no longer unbounded. It previously returned the entire store into the model's context on every call; it now takeslimit(1–100, default 50) andoffset, with validation errors for out-of-range values.GET /api/v1/memoriesgainsoffset(0–10000) alongside the existinglimit, so the whole store is enumerable past the old 100-item ceiling."pagination": {"limit", "offset", "has_more"}; clients advanceoffsetbylimitwhilehas_moreis true.How
mem0's
get_all()has no offset parameter, solist_paginated()inapp/memory.pyemulates it: fetchoffset + limit + 1items, slice the page, and use the extra item purely as thehas_moresignal. This keeps mem0's result shaping byte-identical (no coupling to private vector-store APIs) at the cost of over-fetching on deep pages — bounded by theMAX_LIST_OFFSET = 10000cap, which is far beyond a single-user store's realistic depth.Documented behaviors (also in the user guide):
exclude_expired=truefilters after the page is cut, so a page may hold fewer thanlimititems whilehas_morestays true.agent_idfiltering was introduced (CLAUDE.md invariant).Compatibility
digest/,capture/, andimporters/all read only theresultskey from list responses, so the addedpaginationkey is non-breaking (verified during review). The only behavior change for existing callers is the MCP tool's default cap of 50 — which is the point of the issue.Tests
10 new tests across
tests/test_memory.py,tests/test_rest.py,tests/test_mcp.py: page boundaries,has_moreon last page, offset past end, validation rejections (REST 422s and MCP ToolErrors),exclude_expiredinteraction, and tolerance of bare-list /Noneget_allreturns (theNonecase was a real crash caught while writing tests). Full suite: 177 passed,ruffclean.Review
Adversarial review (line-by-line, removed-behavior, cross-file angles) found no defects; consumer compatibility in
digest/,capture/,importers/was explicitly traced.https://claude.ai/code/session_01H2Dbh6kD8bseWZZEf7kGhx
Generated by Claude Code