Skip to content

Commit bc36d3c

Browse files
committed
fix(mcp): handle workspace discovery fallback
Signed-off-by: Drew Cain <groksrc@gmail.com>
1 parent 1460535 commit bc36d3c

6 files changed

Lines changed: 150 additions & 134 deletions

File tree

src/basic_memory/mcp/project_context.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,10 +1357,22 @@ async def detect_project_from_identifier_prefix(
13571357
return None
13581358

13591359
if _workspace_identifier_discovery_available(identifier, config):
1360-
workspace_resolution = await resolve_workspace_qualified_identifier(
1361-
identifier,
1362-
context=context,
1360+
workspace_discovery_fallback_errors = (
1361+
"not found",
1362+
"no accessible workspaces",
1363+
"unable to discover",
13631364
)
1365+
try:
1366+
workspace_resolution = await resolve_workspace_qualified_identifier(
1367+
identifier,
1368+
context=context,
1369+
)
1370+
except ValueError as exc:
1371+
message = str(exc).lower()
1372+
if any(error in message for error in workspace_discovery_fallback_errors):
1373+
return None
1374+
raise
1375+
13641376
if workspace_resolution is not None:
13651377
return workspace_resolution.project_identifier
13661378

@@ -1375,7 +1387,7 @@ async def detect_project_from_identifier_prefix(
13751387
)
13761388
except ValueError as exc:
13771389
message = str(exc).lower()
1378-
if "not found" in message or "no accessible workspaces" in message:
1390+
if any(error in message for error in workspace_discovery_fallback_errors):
13791391
return None
13801392
raise
13811393

tests/mcp/conftest.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,31 @@ def mcp() -> FastMCP:
2020
return cast(Any, mcp_server)
2121

2222

23+
class ContextState:
24+
"""Minimal FastMCP context-state stub for MCP tests."""
25+
26+
def __init__(self):
27+
self._state: dict[str, object] = {}
28+
29+
async def get_state(self, key: str):
30+
return self._state.get(key)
31+
32+
async def set_state(self, key: str, value: object, **kwargs) -> None:
33+
self._state[key] = value
34+
35+
async def info(self, message: str) -> None:
36+
self._state["info_message"] = message
37+
38+
39+
def ctx(context: ContextState) -> Any:
40+
return cast(Any, context)
41+
42+
43+
@pytest.fixture
44+
def context_state() -> ContextState:
45+
return ContextState()
46+
47+
2348
@pytest.fixture(scope="function")
2449
def app(
2550
app_config, project_config, engine_factory, config_manager

0 commit comments

Comments
 (0)