Skip to content

Commit 7718fba

Browse files
committed
fix: respect --project flag in background sync (fixes #434)
When starting the MCP server with --project flag, background sync and watch service now correctly constrain to only the specified project instead of syncing all active projects. Changes: - Filter active_projects by BASIC_MEMORY_MCP_PROJECT env var - Add logging when background sync is constrained - Add test to verify project constraint works correctly This fix ensures consistent project isolation across both MCP tools and background infrastructure, resolving resource waste when running with multiple configured projects. Fixes #434 Signed-off-by: Cedric Hurst <[email protected]>
1 parent ea2e93d commit 7718fba

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

src/basic_memory/services/initialization.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66

77
import asyncio
8+
import os
89
from pathlib import Path
910

1011
from loguru import logger
@@ -101,6 +102,12 @@ async def initialize_file_sync(
101102
# Get active projects
102103
active_projects = await project_repository.get_active_projects()
103104

105+
# Filter to constrained project if MCP server was started with --project
106+
constrained_project = os.environ.get("BASIC_MEMORY_MCP_PROJECT")
107+
if constrained_project:
108+
active_projects = [p for p in active_projects if p.name == constrained_project]
109+
logger.info(f"Background sync constrained to project: {constrained_project}")
110+
104111
# Start sync for all projects as background tasks (non-blocking)
105112
async def sync_project_background(project):
106113
"""Sync a single project in the background."""

tests/services/test_initialization.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,71 @@ async def test_initialize_file_sync_background_tasks(
178178

179179
# Watch service should still be started
180180
mock_watch_service.run.assert_called_once()
181+
182+
183+
@pytest.mark.asyncio
184+
@patch("basic_memory.services.initialization.db.get_or_create_db")
185+
@patch("basic_memory.cli.commands.sync.get_sync_service")
186+
@patch("basic_memory.sync.WatchService")
187+
@patch("basic_memory.services.initialization.asyncio.create_task")
188+
@patch.dict("os.environ", {"BASIC_MEMORY_MCP_PROJECT": "project1"})
189+
async def test_initialize_file_sync_respects_project_constraint(
190+
mock_create_task, mock_watch_service_class, mock_get_sync_service, mock_get_db, app_config
191+
):
192+
"""Test that file sync only syncs the constrained project when BASIC_MEMORY_MCP_PROJECT is set."""
193+
# Setup mocks
194+
mock_session_maker = AsyncMock()
195+
mock_get_db.return_value = (None, mock_session_maker)
196+
197+
mock_watch_service = AsyncMock()
198+
mock_watch_service.run = AsyncMock()
199+
mock_watch_service_class.return_value = mock_watch_service
200+
201+
mock_repository = AsyncMock()
202+
mock_project1 = MagicMock()
203+
mock_project1.name = "project1"
204+
mock_project1.path = "/path/to/project1"
205+
mock_project1.id = 1
206+
207+
mock_project2 = MagicMock()
208+
mock_project2.name = "project2"
209+
mock_project2.path = "/path/to/project2"
210+
mock_project2.id = 2
211+
212+
mock_project3 = MagicMock()
213+
mock_project3.name = "project3"
214+
mock_project3.path = "/path/to/project3"
215+
mock_project3.id = 3
216+
217+
mock_sync_service = AsyncMock()
218+
mock_sync_service.sync = AsyncMock()
219+
mock_get_sync_service.return_value = mock_sync_service
220+
221+
# Mock background tasks
222+
mock_task = MagicMock()
223+
mock_create_task.return_value = mock_task
224+
225+
# Mock the repository
226+
with patch("basic_memory.services.initialization.ProjectRepository") as mock_repo_class:
227+
mock_repo_class.return_value = mock_repository
228+
# Return all 3 projects from get_active_projects
229+
mock_repository.get_active_projects.return_value = [
230+
mock_project1,
231+
mock_project2,
232+
mock_project3,
233+
]
234+
235+
# Run the function
236+
result = await initialize_file_sync(app_config)
237+
238+
# Assertions
239+
mock_repository.get_active_projects.assert_called_once()
240+
241+
# Should only create 1 background task for project1 (the constrained project)
242+
assert mock_create_task.call_count == 1
243+
244+
# Verify the function returns None
245+
assert result is None
246+
247+
# Watch service should still be started
248+
mock_watch_service.run.assert_called_once()

0 commit comments

Comments
 (0)