From cf041d11d120e0093b24a9c96bca2eaab974b3ef Mon Sep 17 00:00:00 2001 From: phernandez Date: Sun, 30 Aug 2026 12:03:53 -0500 Subject: [PATCH] fix(mcp): correct the search_notes docstring examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The examples were wrong in two ways: - Argument order. The signature is search_notes(query, project, ...) but all 27 examples read search_notes("my-project", "keyword"), which binds the project name to `query` and the keyword to `project`. Anyone who copies them searches for the project name inside a project named after the query. Examples now pass the query positionally and the project as a keyword. - Escapes. The phrase-and-keyword example was written with \"exact phrase\" escapes, which Python resolves at module load, so the runtime docstring read search_notes(""exact phrase" AND keyword", ...) — not valid Python. Single outer quotes keep the rendered call valid. Scope note: the decorator passes its own short description=, so MCP clients never received this docstring. It is the developer reference and what any documentation generator reads (the Codex review of #1380 found both bugs through exactly that path — thanks @FBISiri). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014pmKq6bqCi6Zp6BTHuZjrp Signed-off-by: phernandez --- src/basic_memory/mcp/tools/search.py | 54 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/basic_memory/mcp/tools/search.py b/src/basic_memory/mcp/tools/search.py index 161c5597d..1795f1eb8 100644 --- a/src/basic_memory/mcp/tools/search.py +++ b/src/basic_memory/mcp/tools/search.py @@ -806,45 +806,45 @@ async def search_notes( ## Search Syntax Examples ### Basic Searches - - `search_notes("my-project", "keyword")` - Find any content containing "keyword" - - `search_notes("work-docs", "'exact phrase'")` - Search for exact phrase match + - `search_notes("keyword", project="my-project")` - Find any content containing "keyword" + - `search_notes("'exact phrase'", project="work-docs")` - Search for exact phrase match ### Advanced Boolean Searches - - `search_notes("my-project", "term1 term2")` - Strict implicit-AND first; retries with + - `search_notes("term1 term2", project="my-project")` - Strict implicit-AND first; retries with relaxed OR terms only if strict search returns no results - - `search_notes("my-project", "term1 AND term2")` - Explicit AND search (both terms required) - - `search_notes("my-project", "term1 OR term2")` - Either term can be present - - `search_notes("my-project", "term1 NOT term2")` - Include term1 but exclude term2 - - `search_notes("my-project", "(project OR planning) AND notes")` - Grouped boolean logic + - `search_notes("term1 AND term2", project="my-project")` - Explicit AND search (both terms required) + - `search_notes("term1 OR term2", project="my-project")` - Either term can be present + - `search_notes("term1 NOT term2", project="my-project")` - Include term1 but exclude term2 + - `search_notes("(project OR planning) AND notes", project="my-project")` - Grouped boolean logic ### Content-Specific Searches - - `search_notes("research", "tag:example")` - Search within specific tags (if supported by content) - - `search_notes("work-project", "req", entity_types=["observation"], categories=["requirement"])` + - `search_notes("tag:example", project="research")` - Search within specific tags (if supported by content) + - `search_notes("req", project="work-project", entity_types=["observation"], categories=["requirement"])` - Return only observations whose category is exactly "requirement" - - `search_notes("team-docs", "author:username")` - Find content by author (if metadata available) + - `search_notes("author:username", project="team-docs")` - Find content by author (if metadata available) **Note:** `tag:` shorthand is automatically converted to a `tags` filter, so it works with any search type (text, hybrid, vector). You can also use the `tags` parameter - directly: `search_notes("project", "query", tags=["my-tag"])` + directly: `search_notes("query", project="project", tags=["my-tag"])` ### Search Type Examples - - `search_notes("my-project", "Meeting", search_type="title")` - Search only in titles - - `search_notes("work-docs", "docs/meeting-*", search_type="permalink")` - Pattern match permalinks + - `search_notes("Meeting", project="my-project", search_type="title")` - Search only in titles + - `search_notes("docs/meeting-*", project="work-docs", search_type="permalink")` - Pattern match permalinks Note: Permalink patterns match the full path (e.g., "project/folder/chapter-13*", not just "chapter-13*"). - - `search_notes("research", "keyword")` - Default search (hybrid when semantic is enabled, + - `search_notes("keyword", project="research")` - Default search (hybrid when semantic is enabled, text when disabled) ### Filtering Options - - `search_notes("my-project", "query", note_types=["note"])` - Search only notes - - `search_notes("work-docs", "query", note_types=["note", "person"])` - Multiple note types - - `search_notes("research", "query", entity_types=["observation"])` - Filter by entity type - - `search_notes("research", "query", entity_types=["observation"], categories=["requirement"])` + - `search_notes("query", project="my-project", note_types=["note"])` - Search only notes + - `search_notes("query", project="work-docs", note_types=["note", "person"])` - Multiple note types + - `search_notes("query", project="research", entity_types=["observation"])` - Filter by entity type + - `search_notes("query", project="research", entity_types=["observation"], categories=["requirement"])` - Filter observations to an exact category - - `search_notes("team-docs", "query", after_date="2024-01-01")` - Recent content only - - `search_notes("my-project", "query", after_date="1 week")` - Relative date filtering - - `search_notes("my-project", "query", tags=["security"])` - Filter by frontmatter tags - - `search_notes("my-project", "query", status="in-progress")` - Filter by frontmatter status - - `search_notes("my-project", "query", metadata_filters={"priority": {"$in": ["high"]}})` + - `search_notes("query", project="team-docs", after_date="2024-01-01")` - Recent content only + - `search_notes("query", project="my-project", after_date="1 week")` - Relative date filtering + - `search_notes("query", project="my-project", tags=["security"])` - Filter by frontmatter tags + - `search_notes("query", project="my-project", status="in-progress")` - Filter by frontmatter status + - `search_notes("query", project="my-project", metadata_filters={"priority": {"$in": ["high"]}})` ### Structured Metadata Filters Filters are exact matches on frontmatter metadata. Supported forms: @@ -867,10 +867,10 @@ async def search_notes( metadata_filters, that value wins. ### Advanced Pattern Examples - - `search_notes("work-project", "project AND (meeting OR discussion)")` - Complex boolean logic - - `search_notes("research", "\"exact phrase\" AND keyword")` - Combine phrase and keyword search - - `search_notes("dev-notes", "bug NOT fixed")` - Exclude resolved issues - - `search_notes("archive", "docs/2024-*", search_type="permalink")` - Year-based permalink search + - `search_notes("project AND (meeting OR discussion)", project="work-project")` - Complex boolean logic + - `search_notes('"exact phrase" AND keyword', project="research")` - Combine phrase and keyword search + - `search_notes("bug NOT fixed", project="dev-notes")` - Exclude resolved issues + - `search_notes("docs/2024-*", project="archive", search_type="permalink")` - Year-based permalink search Args: query: Optional search query string (supports boolean operators, phrases, patterns).