fix(mcp): resolve projects by external_id, remove workspace from MCP tools (#777)

Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul Hernandez
2026-05-01 05:15:44 -05:00
committed by GitHub
parent 2fccc74a20
commit 0b335476d6
31 changed files with 688 additions and 447 deletions
+2 -6
View File
@@ -99,9 +99,7 @@ def _abort_if_mcp_processes_alive() -> None:
if not zombies:
return
console.print(
"[red]Refusing to reset:[/red] basic-memory MCP processes are still running."
)
console.print("[red]Refusing to reset:[/red] basic-memory MCP processes are still running.")
console.print(
"[yellow]On macOS/Linux these would keep reading the deleted memory.db inode "
"and return phantom search results (see #765).[/yellow]"
@@ -117,9 +115,7 @@ def _abort_if_mcp_processes_alive() -> None:
"Where-Object {$_.CommandLine -like '*basic-memory*mcp*'}[/green]"
)
else:
console.print(
" 2. Verify nothing remains: [green]pgrep -fa 'basic-memory mcp'[/green]"
)
console.print(" 2. Verify nothing remains: [green]pgrep -fa 'basic-memory mcp'[/green]")
console.print(" 3. Re-run [green]bm reset[/green].")
raise typer.Exit(1)
+54 -27
View File
@@ -62,9 +62,12 @@ def write_note(
help="The project to write to. If not provided, the default project will be used."
),
] = None,
workspace: Annotated[
project_id: Annotated[
Optional[str],
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
typer.Option(
"--project-id",
help="Project external_id (UUID). Takes precedence over --project; use to disambiguate same-named projects across cloud workspaces.",
),
] = None,
local: bool = typer.Option(
False, "--local", help="Force local API routing (ignore cloud mode)"
@@ -106,7 +109,7 @@ def write_note(
content=content,
directory=folder,
project=project,
workspace=workspace,
project_id=project_id,
tags=tags,
output_format="json",
)
@@ -132,9 +135,12 @@ def read_note(
Optional[str],
typer.Option(help="The project to use. If not provided, the default project will be used."),
] = None,
workspace: Annotated[
project_id: Annotated[
Optional[str],
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
typer.Option(
"--project-id",
help="Project external_id (UUID). Takes precedence over --project; use to disambiguate same-named projects across cloud workspaces.",
),
] = None,
local: bool = typer.Option(
False, "--local", help="Force local API routing (ignore cloud mode)"
@@ -156,7 +162,7 @@ def read_note(
mcp_read_note(
identifier=identifier,
project=project,
workspace=workspace,
project_id=project_id,
include_frontmatter=include_frontmatter,
output_format="json",
)
@@ -195,9 +201,12 @@ def edit_note(
help="The project to edit. If not provided, the default project will be used."
),
] = None,
workspace: Annotated[
project_id: Annotated[
Optional[str],
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
typer.Option(
"--project-id",
help="Project external_id (UUID). Takes precedence over --project; use to disambiguate same-named projects across cloud workspaces.",
),
] = None,
local: bool = typer.Option(
False, "--local", help="Force local API routing (ignore cloud mode)"
@@ -222,7 +231,7 @@ def edit_note(
operation=operation,
content=content,
project=project,
workspace=workspace,
project_id=project_id,
section=section,
find_text=find_text,
expected_replacements=expected_replacements,
@@ -260,9 +269,12 @@ def build_context(
Optional[str],
typer.Option(help="The project to use. If not provided, the default project will be used."),
] = None,
workspace: Annotated[
project_id: Annotated[
Optional[str],
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
typer.Option(
"--project-id",
help="Project external_id (UUID). Takes precedence over --project; use to disambiguate same-named projects across cloud workspaces.",
),
] = None,
local: bool = typer.Option(
False, "--local", help="Force local API routing (ignore cloud mode)"
@@ -284,7 +296,7 @@ def build_context(
mcp_build_context(
url=url,
project=project,
workspace=workspace,
project_id=project_id,
depth=depth,
timeframe=timeframe,
page=page,
@@ -317,9 +329,12 @@ def recent_activity(
Optional[str],
typer.Option(help="The project to use. If not provided, the default project will be used."),
] = None,
workspace: Annotated[
project_id: Annotated[
Optional[str],
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
typer.Option(
"--project-id",
help="Project external_id (UUID). Takes precedence over --project; use to disambiguate same-named projects across cloud workspaces.",
),
] = None,
local: bool = typer.Option(
False, "--local", help="Force local API routing (ignore cloud mode)"
@@ -346,7 +361,7 @@ def recent_activity(
page=page,
page_size=page_size,
project=project,
workspace=workspace,
project_id=project_id,
output_format="json",
)
)
@@ -408,9 +423,12 @@ def search_notes(
Optional[str],
typer.Option(help="The project to use. If not provided, the default project will be used."),
] = None,
workspace: Annotated[
project_id: Annotated[
Optional[str],
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
typer.Option(
"--project-id",
help="Project external_id (UUID). Takes precedence over --project; use to disambiguate same-named projects across cloud workspaces.",
),
] = None,
local: bool = typer.Option(
False, "--local", help="Force local API routing (ignore cloud mode)"
@@ -482,7 +500,7 @@ def search_notes(
mcp_search(
query=query or None,
project=project,
workspace=workspace,
project_id=project_id,
search_type=search_type,
output_format="json",
page=page,
@@ -592,9 +610,12 @@ def schema_validate(
Optional[str],
typer.Option(help="The project to use. If not provided, the default project will be used."),
] = None,
workspace: Annotated[
project_id: Annotated[
Optional[str],
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
typer.Option(
"--project-id",
help="Project external_id (UUID). Takes precedence over --project; use to disambiguate same-named projects across cloud workspaces.",
),
] = None,
local: bool = typer.Option(
False, "--local", help="Force local API routing (ignore cloud mode)"
@@ -629,7 +650,7 @@ def schema_validate(
note_type=note_type,
identifier=identifier,
project=project,
workspace=workspace,
project_id=project_id,
output_format="json",
)
)
@@ -660,9 +681,12 @@ def schema_infer(
Optional[str],
typer.Option(help="The project to use. If not provided, the default project will be used."),
] = None,
workspace: Annotated[
project_id: Annotated[
Optional[str],
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
typer.Option(
"--project-id",
help="Project external_id (UUID). Takes precedence over --project; use to disambiguate same-named projects across cloud workspaces.",
),
] = None,
local: bool = typer.Option(
False, "--local", help="Force local API routing (ignore cloud mode)"
@@ -686,7 +710,7 @@ def schema_infer(
note_type=note_type,
threshold=threshold,
project=project,
workspace=workspace,
project_id=project_id,
output_format="json",
)
)
@@ -714,9 +738,12 @@ def schema_diff(
Optional[str],
typer.Option(help="The project to use. If not provided, the default project will be used."),
] = None,
workspace: Annotated[
project_id: Annotated[
Optional[str],
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
typer.Option(
"--project-id",
help="Project external_id (UUID). Takes precedence over --project; use to disambiguate same-named projects across cloud workspaces.",
),
] = None,
local: bool = typer.Option(
False, "--local", help="Force local API routing (ignore cloud mode)"
@@ -738,7 +765,7 @@ def schema_diff(
mcp_schema_diff(
note_type=note_type,
project=project,
workspace=workspace,
project_id=project_id,
output_format="json",
)
)