Skip to content

Commit 7696fca

Browse files
committed
fix: restore MCP telemetry compatibility and outcomes
Signed-off-by: phernandez <paul@basicmachines.co>
1 parent 98a2a3c commit 7696fca

16 files changed

Lines changed: 370 additions & 59 deletions

src/basic_memory/api/v2/routers/search_router.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ async def search(
5757
page_size=page_size,
5858
retrieval_mode=query.retrieval_mode.value,
5959
has_query=bool(
60-
(query.text and query.text.strip()) or query.title or query.permalink or query.permalink_match
60+
(query.text and query.text.strip())
61+
or query.title
62+
or query.permalink
63+
or query.permalink_match
6164
),
6265
has_filters=bool(query.note_types or query.entity_types or query.metadata_filters),
6366
):

src/basic_memory/api/v2/utils.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ async def to_graph_context(
3939
entity_ids_needed: set[int] = set()
4040
for context_item in context_result.results:
4141
for item in (
42-
[context_item.primary_result] + context_item.observations + context_item.related_results
42+
[context_item.primary_result]
43+
+ context_item.observations
44+
+ context_item.related_results
4345
):
4446
if item.type == SearchItemType.ENTITY:
4547
# Entity's own ID for its external_id
@@ -100,9 +102,7 @@ def to_summary(item: SearchIndexRow | ContextResultRow):
100102
created_at=item.created_at,
101103
)
102104
case SearchItemType.RELATION:
103-
from_title = (
104-
entity_title_lookup.get(item.from_id) if item.from_id else None
105-
) # pyright: ignore
105+
from_title = entity_title_lookup.get(item.from_id) if item.from_id else None # pyright: ignore
106106
to_title = entity_title_lookup.get(item.to_id) if item.to_id else None
107107
from_ext_id = (
108108
entity_external_id_lookup.get(item.from_id) if item.from_id else None
@@ -154,7 +154,8 @@ def to_summary(item: SearchIndexRow | ContextResultRow):
154154
generated_at=context_result.metadata.generated_at,
155155
primary_count=context_result.metadata.primary_count,
156156
related_count=context_result.metadata.related_count,
157-
total_results=context_result.metadata.primary_count + context_result.metadata.related_count,
157+
total_results=context_result.metadata.primary_count
158+
+ context_result.metadata.related_count,
158159
total_relations=context_result.metadata.total_relations,
159160
total_observations=context_result.metadata.total_observations,
160161
)

src/basic_memory/mcp/tools/build_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ async def build_context(
206206
"mcp.tool.build_context",
207207
entrypoint="mcp",
208208
tool_name="build_context",
209-
project_name=project,
209+
requested_project=project,
210210
workspace_id=workspace,
211211
depth=depth or 1,
212212
timeframe=timeframe,

src/basic_memory/mcp/tools/edit_note.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ async def edit_note(
275275
"mcp.tool.edit_note",
276276
entrypoint="mcp",
277277
tool_name="edit_note",
278-
project_name=project,
278+
requested_project=project,
279279
workspace_id=workspace,
280280
edit_operation=operation,
281281
output_format=output_format,

src/basic_memory/mcp/tools/read_note.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
resolve_project_and_path,
1717
)
1818
from basic_memory.mcp.server import mcp
19+
from basic_memory.mcp.tools.search import search_notes
1920
from basic_memory.schemas.memory import memory_url_path
20-
from basic_memory.schemas.search import SearchQuery
2121
from basic_memory.utils import validate_project_path
2222

2323

@@ -144,7 +144,7 @@ async def read_note(
144144
"mcp.tool.read_note",
145145
entrypoint="mcp",
146146
tool_name="read_note",
147-
project_name=project,
147+
requested_project=project,
148148
workspace_id=workspace,
149149
output_format=output_format,
150150
page=page,
@@ -199,12 +199,11 @@ async def read_note(
199199
)
200200

201201
# Import here to avoid circular import
202-
from basic_memory.mcp.clients import KnowledgeClient, ResourceClient, SearchClient
202+
from basic_memory.mcp.clients import KnowledgeClient, ResourceClient
203203

204204
# Use typed clients for API calls
205205
knowledge_client = KnowledgeClient(client, active_project.external_id)
206206
resource_client = ResourceClient(client, active_project.external_id)
207-
search_client = SearchClient(client, active_project.external_id)
208207

209208
async def _read_json_payload(entity_id: str) -> dict:
210209
with telemetry.scope(
@@ -214,7 +213,9 @@ async def _read_json_payload(entity_id: str) -> dict:
214213
phase="shape_response",
215214
):
216215
entity = await knowledge_client.get_entity(entity_id)
217-
response = await resource_client.read(entity_id, page=page, page_size=page_size)
216+
response = await resource_client.read(
217+
entity_id, page=page, page_size=page_size
218+
)
218219
content_text = response.text
219220
body_content, parsed_frontmatter = _parse_opening_frontmatter(content_text)
220221
return {
@@ -241,15 +242,22 @@ def _search_results(payload: object) -> list[dict]:
241242
return results if isinstance(results, list) else []
242243

243244
async def _search_candidates(identifier_text: str, *, title_only: bool) -> dict:
244-
query = SearchQuery(title=identifier_text) if title_only else SearchQuery(
245-
text=identifier_text
246-
)
247-
response = await search_client.search(
248-
query.model_dump(mode="json", exclude_none=True),
245+
# Trigger: direct entity resolution failed for the caller's identifier.
246+
# Why: search_notes applies the same memory:// normalization and tool-level
247+
# query handling as the rest of MCP routing, which raw client calls skip.
248+
# Outcome: unresolved memory URLs still fall back through normalized search.
249+
search_type = "title" if title_only else "text"
250+
response = await search_notes(
251+
project=active_project.name,
252+
workspace=workspace,
253+
query=identifier_text,
254+
search_type=search_type,
249255
page=page,
250256
page_size=page_size,
257+
output_format="json",
258+
context=context,
251259
)
252-
return response.model_dump(mode="json")
260+
return response if isinstance(response, dict) else {}
253261

254262
def _result_title(item: dict) -> str:
255263
return str(item.get("title") or "")

src/basic_memory/mcp/tools/search.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ async def search_notes(
528528
"mcp.tool.search_notes",
529529
entrypoint="mcp",
530530
tool_name="search_notes",
531-
project_name=project,
531+
requested_project=project,
532532
workspace_id=workspace,
533533
search_type=search_type or "default",
534534
output_format=output_format,
@@ -537,7 +537,9 @@ async def search_notes(
537537
has_query=bool(query and query.strip()),
538538
note_type_filter_count=len(note_types),
539539
entity_type_filter_count=len(entity_types),
540-
has_filters=bool(metadata_filters or tags or status or note_types or entity_types or after_date),
540+
has_filters=bool(
541+
metadata_filters or tags or status or note_types or entity_types or after_date
542+
),
541543
has_tags_filter=bool(tags),
542544
has_status_filter=bool(status),
543545
):

0 commit comments

Comments
 (0)