Skip to content

Commit a3cae10

Browse files
committed
add background migration task and status tool/prompt
Signed-off-by: phernandez <paul@basicmachines.co>
1 parent c5c70cb commit a3cae10

11 files changed

Lines changed: 542 additions & 9 deletions

File tree

src/basic_memory/mcp/prompts/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
from basic_memory.mcp.prompts import recent_activity
1111
from basic_memory.mcp.prompts import search
1212
from basic_memory.mcp.prompts import ai_assistant_guide
13+
from basic_memory.mcp.prompts import migration_status
1314

1415
__all__ = [
1516
"ai_assistant_guide",
1617
"continue_conversation",
18+
"migration_status",
1719
"recent_activity",
1820
"search",
1921
]
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
"""Migration status prompt for Basic Memory MCP server."""
2+
3+
from typing import Optional
4+
5+
from basic_memory.mcp.server import mcp
6+
7+
8+
@mcp.prompt(
9+
description="""Get migration status with recommendations for AI assistants.
10+
11+
This prompt provides both current migration status and guidance on how
12+
AI assistants should respond when migration is in progress or completed.
13+
""",
14+
)
15+
async def migration_status_prompt(
16+
) -> str:
17+
"""Get migration status with AI assistant guidance.
18+
19+
This prompt provides detailed migration status information along with
20+
recommendations for how AI assistants should handle different migration states.
21+
22+
Returns:
23+
Formatted migration status with AI assistant guidance
24+
"""
25+
try:
26+
from basic_memory.services.migration_service import migration_manager
27+
28+
state = migration_manager.state
29+
30+
# Build status report
31+
lines = [
32+
"# Basic Memory Migration Status",
33+
"",
34+
f"**Current Status**: {state.status.value.replace('_', ' ').title()}",
35+
f"**System Ready**: {'Yes' if migration_manager.is_ready else 'No'}",
36+
"",
37+
]
38+
39+
if migration_manager.is_ready:
40+
lines.extend(
41+
[
42+
"✅ **All migrations completed** - System is fully operational",
43+
"",
44+
"All Basic Memory MCP tools are available and functioning normally.",
45+
"You can proceed with any knowledge management tasks.",
46+
]
47+
)
48+
else:
49+
lines.append(f"**Status Message**: {state.message}")
50+
51+
if state.status.value == "in_progress":
52+
if state.projects_total > 0:
53+
progress = f" ({state.projects_migrated}/{state.projects_total})"
54+
lines.append(f"**Progress**: {progress}")
55+
56+
lines.extend(
57+
[
58+
"",
59+
"🔄 **Migration in progress** - Legacy data is being migrated to new format",
60+
"",
61+
"**Impact**: Some tools may show status messages instead of normal responses",
62+
"until migration completes (usually 1-3 minutes).",
63+
]
64+
)
65+
66+
elif state.status.value == "failed":
67+
lines.extend(
68+
[
69+
"",
70+
f"❌ **Migration failed**: {state.error or 'Unknown error'}",
71+
"",
72+
"**Impact**: System may have limited functionality until issue is resolved.",
73+
]
74+
)
75+
76+
# Convert string parameter to boolean
77+
include_recs = True
78+
79+
if include_recs and not migration_manager.is_ready:
80+
lines.extend(
81+
[
82+
"",
83+
"---",
84+
"",
85+
"## AI Assistant Recommendations",
86+
"",
87+
"**When migration is in progress:**",
88+
"- Inform the user about the background migration",
89+
"- Suggest using `migration_status()` tool to check progress",
90+
"- Explain that most tools will work normally once migration completes",
91+
"- Avoid creating complex workflows until migration is done",
92+
"",
93+
"**What to tell users:**",
94+
"- 'Basic Memory is upgrading your knowledge base in the background'",
95+
"- 'This usually takes 1-3 minutes depending on your data size'",
96+
"- 'You can check progress anytime with the migration_status tool'",
97+
"- 'Most functionality will be available once the upgrade completes'",
98+
]
99+
)
100+
101+
return "\n".join(lines)
102+
103+
except Exception as e:
104+
return f"""# Migration Status - Error
105+
106+
❌ **Unable to check migration status**: {str(e)}
107+
108+
## AI Assistant Recommendations
109+
110+
**When status is unavailable:**
111+
- Assume the system is likely working normally
112+
- Try proceeding with normal operations
113+
- If users report issues, suggest checking logs or restarting
114+
"""

src/basic_memory/mcp/server.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,23 @@
3131
@dataclass
3232
class AppContext:
3333
watch_task: Optional[asyncio.Task]
34+
migration_manager: Optional[Any] = None
3435

3536

3637
@asynccontextmanager
3738
async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: # pragma: no cover
3839
"""Manage application lifecycle with type-safe context"""
39-
# Initialize on startup
40-
watch_task = await initialize_app(app_config)
40+
# Initialize on startup (now returns migration_manager)
41+
migration_manager = await initialize_app(app_config)
4142

4243
# Initialize project session with default project
4344
session.initialize(app_config.default_project)
4445

4546
try:
46-
yield AppContext(watch_task=watch_task)
47+
yield AppContext(watch_task=None, migration_manager=migration_manager)
4748
finally:
48-
# Cleanup on shutdown
49-
if watch_task:
50-
watch_task.cancel()
49+
# Cleanup on shutdown - migration tasks will be cancelled automatically
50+
pass
5151

5252

5353
# OAuth configuration function

src/basic_memory/mcp/tools/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from basic_memory.mcp.tools.list_directory import list_directory
1818
from basic_memory.mcp.tools.edit_note import edit_note
1919
from basic_memory.mcp.tools.move_note import move_note
20+
from basic_memory.mcp.tools.migration_status import migration_status
2021
from basic_memory.mcp.tools.project_management import (
2122
list_projects,
2223
switch_project,
@@ -36,6 +37,7 @@
3637
"get_current_project",
3738
"list_directory",
3839
"list_projects",
40+
"migration_status",
3941
"move_note",
4042
"read_content",
4143
"read_note",

src/basic_memory/mcp/tools/build_context.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,27 @@ async def build_context(
8282
logger.info(f"Building context from {url}")
8383
# URL is already validated and normalized by MemoryUrl type annotation
8484

85+
# Check migration status and wait briefly if needed
86+
from basic_memory.mcp.tools.utils import wait_for_migration_or_return_status
87+
88+
migration_status = await wait_for_migration_or_return_status(timeout=5.0)
89+
if migration_status:
90+
# Return a proper GraphContext with status message
91+
from basic_memory.schemas.memory import MemoryMetadata
92+
from datetime import datetime
93+
94+
return GraphContext(
95+
results=[],
96+
metadata=MemoryMetadata(
97+
depth=depth or 1,
98+
timeframe=timeframe,
99+
generated_at=datetime.now(),
100+
primary_count=0,
101+
related_count=0,
102+
uri=migration_status, # Include status in metadata
103+
),
104+
)
105+
85106
active_project = get_active_project(project)
86107
project_url = active_project.project_url
87108

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
"""Migration status tool for Basic Memory MCP server."""
2+
3+
from typing import Optional
4+
5+
from loguru import logger
6+
7+
from basic_memory.mcp.server import mcp
8+
from basic_memory.mcp.project_session import get_active_project
9+
10+
11+
@mcp.tool(
12+
description="""Check the status of system migration and background operations.
13+
14+
Use this tool to:
15+
- Check if migration is in progress or completed
16+
- Get detailed migration progress information
17+
- Understand if the system is ready for normal operations
18+
- Get specific error details if migration failed
19+
""",
20+
)
21+
async def migration_status(project: Optional[str] = None) -> str:
22+
"""Get current migration status and system readiness information.
23+
24+
This tool provides detailed information about any ongoing or completed
25+
migration operations, helping users understand system availability.
26+
27+
Args:
28+
project: Optional project name (included for consistency with other tools)
29+
30+
Returns:
31+
Detailed migration status including:
32+
- Current migration state (ready, in progress, failed, etc.)
33+
- Progress information if migration is running
34+
- Error details if migration failed
35+
- Estimated completion information
36+
- Guidance on next steps
37+
38+
Examples:
39+
# Check current migration status
40+
migration_status()
41+
42+
# Get migration status for specific project context
43+
migration_status(project="work-project")
44+
"""
45+
logger.info("MCP tool call tool=migration_status")
46+
47+
try:
48+
from basic_memory.services.migration_service import migration_manager
49+
50+
# Get current migration state
51+
state = migration_manager.state
52+
53+
# Build detailed status response
54+
status_lines = [
55+
"# Migration Status",
56+
"",
57+
f"**Current Status**: {state.status.value.replace('_', ' ').title()}",
58+
"",
59+
]
60+
61+
if migration_manager.is_ready:
62+
status_lines.extend(
63+
[
64+
"✅ **System Ready**: All migrations completed successfully",
65+
"",
66+
"The system is fully operational and ready for normal use. All MCP tools",
67+
"are available and functioning normally.",
68+
]
69+
)
70+
else:
71+
# Migration in progress or failed
72+
status_lines.append(f"**Message**: {state.message}")
73+
74+
if state.status.value == "in_progress":
75+
status_lines.extend(
76+
[
77+
"",
78+
"🔄 **Migration in Progress**",
79+
"",
80+
]
81+
)
82+
83+
if state.projects_total > 0:
84+
progress_pct = (state.projects_migrated / state.projects_total) * 100
85+
status_lines.extend(
86+
[
87+
f"- **Progress**: {state.projects_migrated}/{state.projects_total} projects ({progress_pct:.0f}%)",
88+
f"- **Remaining**: {state.projects_total - state.projects_migrated} projects",
89+
]
90+
)
91+
92+
status_lines.extend(
93+
[
94+
"",
95+
"**What's happening**: Basic Memory is migrating legacy project data",
96+
"to the new unified database format. This process runs in the background",
97+
"and most tools will show status messages until completion.",
98+
"",
99+
"**Estimated time**: Usually 1-3 minutes depending on knowledge base size",
100+
"",
101+
"**What you can do**: Wait for migration to complete, or check status",
102+
"again in a few moments. The system will be fully operational once finished.",
103+
]
104+
)
105+
106+
elif state.status.value == "failed":
107+
status_lines.extend(
108+
[
109+
"",
110+
"❌ **Migration Failed**",
111+
"",
112+
f"**Error**: {state.error or 'Unknown error occurred'}",
113+
"",
114+
"**What this means**: The automatic migration encountered an issue.",
115+
"Basic Memory may still work, but some legacy data might not be available.",
116+
"",
117+
"**Recommended actions**:",
118+
"1. Try running `basic-memory sync` manually from the command line",
119+
"2. Check the logs for more detailed error information",
120+
"3. If issues persist, consider filing a support issue",
121+
]
122+
)
123+
124+
elif state.status.value == "pending":
125+
status_lines.extend(
126+
[
127+
"",
128+
"⏳ **Migration Pending**",
129+
"",
130+
"Migration has been detected as needed but hasn't started yet.",
131+
"This usually resolves automatically within a few seconds.",
132+
]
133+
)
134+
135+
# Add project context if provided
136+
if project:
137+
try:
138+
active_project = get_active_project(project)
139+
status_lines.extend(
140+
[
141+
"",
142+
"---",
143+
"",
144+
f"**Active Project**: {active_project.name}",
145+
f"**Project Path**: {active_project.path}",
146+
]
147+
)
148+
except Exception as e:
149+
logger.debug(f"Could not get project info: {e}")
150+
# Don't fail the tool for project info issues
151+
152+
return "\n".join(status_lines)
153+
154+
except Exception as e:
155+
logger.error(f"Error checking migration status: {e}")
156+
return f"""# Migration Status - Error
157+
158+
❌ **Unable to check migration status**
159+
160+
**Error**: {str(e)}
161+
162+
**What this means**: There was a technical issue checking the migration status.
163+
The system is likely functioning normally, but status information is unavailable.
164+
165+
**Recommended action**: Try again in a moment, or proceed with normal operations.
166+
"""

src/basic_memory/mcp/tools/read_note.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ async def read_note(
5252
read_note("Meeting Notes", project="work-project")
5353
"""
5454

55+
# Check migration status and wait briefly if needed
56+
from basic_memory.mcp.tools.utils import wait_for_migration_or_return_status
57+
58+
migration_status = await wait_for_migration_or_return_status(timeout=5.0)
59+
if migration_status:
60+
return f"# System Status\n\n{migration_status}\n\nPlease wait for migration to complete before reading notes."
61+
5562
active_project = get_active_project(project)
5663
project_url = active_project.project_url
5764

0 commit comments

Comments
 (0)