Skip to content

Commit 567cd99

Browse files
phernandezclaude
andcommitted
refactor: convert search.py to context manager pattern
Converts search tool to use async with get_client() context manager: - Changed import from 'client' to 'get_client' - Wrapped function body at line 356 in async with block - Indented lines 357-384 inside context manager - Tests: 16/16 passing - Coverage: 96% for search.py Tool provides comprehensive search functionality: - Full-text search with FTS5 support - Title and permalink search modes - Advanced boolean operators (AND, OR, NOT) - Pattern matching and filtering - Helpful error messages with search syntax guidance Total tools converted: 11/16 (Phase 0.3) Updated SPEC-16 Phase 0.3 checklist to mark search.py as completed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
1 parent 6fd29d6 commit 567cd99

2 files changed

Lines changed: 28 additions & 27 deletions

File tree

specs/SPEC-16 MCP Cloud Service Consolidation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ Convert from `from async_client import client` to `async with get_client() as cl
455455
- [x] `tools/read_content.py` (20/20 tests passing)
456456
- [x] `tools/list_directory.py` (11/11 tests passing)
457457
- [x] `tools/move_note.py` (34/34 tests passing, 90% coverage)
458-
- [ ] `tools/search.py`
458+
- [x] `tools/search.py` (16/16 tests passing, 96% coverage)
459459
- [ ] `tools/recent_activity.py`
460460
- [ ] `tools/project_management.py`
461461
- [x] `tools/edit_note.py` (17/17 tests passing)

src/basic_memory/mcp/tools/search.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from loguru import logger
77
from fastmcp import Context
88

9-
from basic_memory.mcp.async_client import client
9+
from basic_memory.mcp.async_client import get_client
1010
from basic_memory.mcp.project_context import get_active_project
1111
from basic_memory.mcp.server import mcp
1212
from basic_memory.mcp.tools.utils import call_post
@@ -353,31 +353,32 @@ async def search_notes(
353353
if after_date:
354354
search_query.after_date = after_date
355355

356-
active_project = await get_active_project(client, project, context)
357-
project_url = active_project.project_url
356+
async with get_client() as client:
357+
active_project = await get_active_project(client, project, context)
358+
project_url = active_project.project_url
358359

359-
logger.info(f"Searching for {search_query} in project {active_project.name}")
360+
logger.info(f"Searching for {search_query} in project {active_project.name}")
360361

361-
try:
362-
response = await call_post(
363-
client,
364-
f"{project_url}/search/",
365-
json=search_query.model_dump(),
366-
params={"page": page, "page_size": page_size},
367-
)
368-
result = SearchResponse.model_validate(response.json())
369-
370-
# Check if we got no results and provide helpful guidance
371-
if not result.results:
372-
logger.info(
373-
f"Search returned no results for query: {query} in project {active_project.name}"
362+
try:
363+
response = await call_post(
364+
client,
365+
f"{project_url}/search/",
366+
json=search_query.model_dump(),
367+
params={"page": page, "page_size": page_size},
374368
)
375-
# Don't treat this as an error, but the user might want guidance
376-
# We return the empty result as normal - the user can decide if they need help
377-
378-
return result
379-
380-
except Exception as e:
381-
logger.error(f"Search failed for query '{query}': {e}, project: {active_project.name}")
382-
# Return formatted error message as string for better user experience
383-
return _format_search_error_response(active_project.name, str(e), query, search_type)
369+
result = SearchResponse.model_validate(response.json())
370+
371+
# Check if we got no results and provide helpful guidance
372+
if not result.results:
373+
logger.info(
374+
f"Search returned no results for query: {query} in project {active_project.name}"
375+
)
376+
# Don't treat this as an error, but the user might want guidance
377+
# We return the empty result as normal - the user can decide if they need help
378+
379+
return result
380+
381+
except Exception as e:
382+
logger.error(f"Search failed for query '{query}': {e}, project: {active_project.name}")
383+
# Return formatted error message as string for better user experience
384+
return _format_search_error_response(active_project.name, str(e), query, search_type)

0 commit comments

Comments
 (0)