Skip to content

Surface over-limit MCP search as a tool error - #371

Open
PoisonGodv wants to merge 1 commit into
redis:mainfrom
PoisonGodv:fix-308-search-limit-error
Open

PoisonGodv wants to merge 1 commit into
redis:mainfrom
PoisonGodv:fix-308-search-limit-error

Conversation

@PoisonGodv

@PoisonGodv PoisonGodv commented Oct 26, 2026 •

Copy link
Copy Markdown

Problem

SearchRequest.limit is capped at 100 (le=100). The REST endpoint already rejects limit > 100 with a 422 response, and the Python client raises MemoryServerError. The MCP search_long_term_memory tool is different: it builds SearchRequest inside a broad try/except Exception that returns MemoryRecordResults(total=0, memories=[]). So limit=101 comes back as a successful, empty result (isError=false), which looks exactly like "no matching memories" (#308).

Reproduced on main:

MCP  search_long_term_memory {"text": "x", "limit": 101}
  -> isError: False, {"memories": [], "total": 0, "next_offset": null}
REST POST /v1/long-term-memory/search {"limit": 101}
  -> 422 "Input should be less than or equal to 100"

Fix

  • mcp.py: build SearchRequest before the try block, so validation errors reach the caller as a tool error. This matches memory_prompt and the REST endpoint. Errors raised during the search itself still use the existing fallback.
  • I chose a clear error over silent clamping. Clamping would hide the fact that fewer results came back than were requested, and REST already treats this as a client error.
  • Documented the 1-100 range in SearchRequest.limit (which feeds the OpenAPI schema), in docs/api.md, in the MCP tool docstring, and in the client's search_long_term_memory docstring.

Tests

  • New tests/test_mcp.py::TestMCP::test_search_long_term_memory_rejects_limit_above_maximum. It fails on main (isError=False) and passes with the fix.
  • New tests/test_api.py::TestSearchEndpoint::test_search_rejects_limit_above_maximum, which locks in the REST 422 behavior.
  • uv run pytest: 864 passed, 109 skipped.
  • uv run pytest tests/test_api.py -k TestSearchEndpoint --run-api-tests: 8 passed. All search calls are mocked; a dummy OPENAI_API_KEY was set.
  • agent-memory-client: uv run pytest tests: 88 passed, 9 skipped.
  • ruff check/format (v0.14.8) and typos on the changed files: clean.

Fixes #308

Notes

  • Moving SearchRequest construction out of the try also turns other SearchRequest validation failures (e.g. negative offset, hybrid_alpha outside 0-1) into tool errors instead of empty results.
  • The new REST test only runs with --run-api-tests, so default CI skips it.
  • docs/api.md was edited by hand; the SearchRequest.limit field description in models.py is the source of truth.
  • Possible follow-up, not in this PR: the client's LLM tool schema advertises max_results maximum 20, and validate_memory_search_filters only checks the lower bound.

Note

Low Risk
Targeted validation-order fix and documentation; search execution error handling is unchanged. Low risk aside from callers that relied on silent empty results for invalid limits.

Overview
Fixes #308: MCP search_long_term_memory no longer returns a successful empty result when limit exceeds the server cap.

MCP behavior: SearchRequest is built before the broad try/except in mcp.py, so Pydantic validation (e.g. limit > 100) fails as a tool error instead of being caught and turned into {total: 0, memories: []}. Runtime search failures still use the existing empty-result fallback.

Docs: Clarifies that search limit is 1–100 in SearchRequest (models.py), docs/api.md, the MCP tool docstring, and the Python client search_long_term_memory docstring (422 / MemoryServerError on REST).

Tests: Adds MCP test asserting limit=101 is an error with no search call, and REST test asserting 422 on limit=101.

Reviewed by Cursor Bugbot for commit e4c3d4b. Bugbot is set up for automated code reviews on this repo. Configure here.

The MCP search_long_term_memory tool built its SearchRequest inside the
broad try/except that turns failures into an empty MemoryRecordResults.
A limit above 100 therefore came back as "no results" with isError=false
instead of a validation error. Build the request before the try block so
parameter validation errors reach the caller, matching memory_prompt and
the REST endpoint (which already returns 422).

Also document the 1-100 range on SearchRequest.limit, the REST API docs,
and the Python client's search_long_term_memory docstring.

Fixes redis#308

This branch has not been deployed

No deployments
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.

docs/UX: search limit hard-capped at 100 — over-limit reads as empty results, not an error

1 participant