memorygraphMCP 0.11.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- memorygraph/__init__.py +50 -0
- memorygraph/__main__.py +12 -0
- memorygraph/advanced_tools.py +509 -0
- memorygraph/analytics/__init__.py +46 -0
- memorygraph/analytics/advanced_queries.py +727 -0
- memorygraph/backends/__init__.py +21 -0
- memorygraph/backends/base.py +179 -0
- memorygraph/backends/cloud.py +75 -0
- memorygraph/backends/cloud_backend.py +858 -0
- memorygraph/backends/factory.py +577 -0
- memorygraph/backends/falkordb_backend.py +749 -0
- memorygraph/backends/falkordblite_backend.py +746 -0
- memorygraph/backends/ladybugdb_backend.py +242 -0
- memorygraph/backends/memgraph_backend.py +327 -0
- memorygraph/backends/neo4j_backend.py +298 -0
- memorygraph/backends/sqlite_fallback.py +463 -0
- memorygraph/backends/turso.py +448 -0
- memorygraph/cli.py +743 -0
- memorygraph/cloud_database.py +297 -0
- memorygraph/config.py +295 -0
- memorygraph/database.py +933 -0
- memorygraph/graph_analytics.py +631 -0
- memorygraph/integration/__init__.py +69 -0
- memorygraph/integration/context_capture.py +426 -0
- memorygraph/integration/project_analysis.py +583 -0
- memorygraph/integration/workflow_tracking.py +492 -0
- memorygraph/intelligence/__init__.py +59 -0
- memorygraph/intelligence/context_retrieval.py +447 -0
- memorygraph/intelligence/entity_extraction.py +386 -0
- memorygraph/intelligence/pattern_recognition.py +420 -0
- memorygraph/intelligence/temporal.py +374 -0
- memorygraph/migration/__init__.py +27 -0
- memorygraph/migration/manager.py +579 -0
- memorygraph/migration/models.py +142 -0
- memorygraph/migration/scripts/__init__.py +17 -0
- memorygraph/migration/scripts/bitemporal_migration.py +595 -0
- memorygraph/migration/scripts/multitenancy_migration.py +452 -0
- memorygraph/migration_tools_module.py +146 -0
- memorygraph/models.py +684 -0
- memorygraph/proactive/__init__.py +46 -0
- memorygraph/proactive/outcome_learning.py +444 -0
- memorygraph/proactive/predictive.py +410 -0
- memorygraph/proactive/session_briefing.py +399 -0
- memorygraph/relationships.py +668 -0
- memorygraph/server.py +883 -0
- memorygraph/sqlite_database.py +1876 -0
- memorygraph/tools/__init__.py +59 -0
- memorygraph/tools/activity_tools.py +262 -0
- memorygraph/tools/memory_tools.py +315 -0
- memorygraph/tools/migration_tools.py +181 -0
- memorygraph/tools/relationship_tools.py +147 -0
- memorygraph/tools/search_tools.py +406 -0
- memorygraph/tools/temporal_tools.py +339 -0
- memorygraph/utils/__init__.py +10 -0
- memorygraph/utils/context_extractor.py +429 -0
- memorygraph/utils/error_handling.py +151 -0
- memorygraph/utils/export_import.py +425 -0
- memorygraph/utils/graph_algorithms.py +200 -0
- memorygraph/utils/pagination.py +149 -0
- memorygraph/utils/project_detection.py +133 -0
- memorygraphmcp-0.11.7.dist-info/METADATA +970 -0
- memorygraphmcp-0.11.7.dist-info/RECORD +65 -0
- memorygraphmcp-0.11.7.dist-info/WHEEL +4 -0
- memorygraphmcp-0.11.7.dist-info/entry_points.txt +2 -0
- memorygraphmcp-0.11.7.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP tools for database migration.
|
|
3
|
+
|
|
4
|
+
Provides migration tools for moving memories between different backend types.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Dict, Any, Optional
|
|
9
|
+
|
|
10
|
+
from ..migration.manager import MigrationManager, MigrationError
|
|
11
|
+
from ..migration.models import BackendConfig, MigrationOptions, BackendType
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def handle_migrate_database(
|
|
17
|
+
target_backend: str,
|
|
18
|
+
target_config: Optional[Dict[str, Any]] = None,
|
|
19
|
+
dry_run: bool = False,
|
|
20
|
+
skip_duplicates: bool = True,
|
|
21
|
+
verify: bool = True
|
|
22
|
+
) -> Dict[str, Any]:
|
|
23
|
+
"""
|
|
24
|
+
Migrate memories from current backend to target backend.
|
|
25
|
+
|
|
26
|
+
This tool enables AI assistants to help users migrate their memory database
|
|
27
|
+
to a different backend (e.g., SQLite → FalkorDB for production).
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
target_backend: Target backend type (sqlite, neo4j, memgraph, falkordb, falkordblite)
|
|
31
|
+
target_config: Target backend configuration (path, URI, credentials)
|
|
32
|
+
dry_run: Validate without making changes
|
|
33
|
+
skip_duplicates: Skip memories that already exist in target
|
|
34
|
+
verify: Verify data integrity after migration
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Migration result with statistics and status
|
|
38
|
+
|
|
39
|
+
Example:
|
|
40
|
+
# Migrate from SQLite to FalkorDB
|
|
41
|
+
result = await migrate_database(
|
|
42
|
+
target_backend="falkordb",
|
|
43
|
+
target_config={
|
|
44
|
+
"uri": "redis://prod.example.com:6379",
|
|
45
|
+
"username": "admin",
|
|
46
|
+
"password": "secret"
|
|
47
|
+
},
|
|
48
|
+
dry_run=True # Test first
|
|
49
|
+
)
|
|
50
|
+
"""
|
|
51
|
+
try:
|
|
52
|
+
# Source is current environment
|
|
53
|
+
source_config = BackendConfig.from_env()
|
|
54
|
+
|
|
55
|
+
# Parse target backend type
|
|
56
|
+
try:
|
|
57
|
+
target_backend_type = BackendType(target_backend.lower())
|
|
58
|
+
except ValueError:
|
|
59
|
+
return {
|
|
60
|
+
"success": False,
|
|
61
|
+
"error": f"Invalid target backend: {target_backend}. Must be one of: sqlite, neo4j, memgraph, falkordb, falkordblite",
|
|
62
|
+
"error_type": "ValueError"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Build target config
|
|
66
|
+
target_config_obj = BackendConfig(
|
|
67
|
+
backend_type=target_backend_type,
|
|
68
|
+
path=target_config.get("path") if target_config else None,
|
|
69
|
+
uri=target_config.get("uri") if target_config else None,
|
|
70
|
+
username=target_config.get("username") if target_config else None,
|
|
71
|
+
password=target_config.get("password") if target_config else None,
|
|
72
|
+
database=target_config.get("database") if target_config else None
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Validate target config
|
|
76
|
+
validation_errors = target_config_obj.validate()
|
|
77
|
+
if validation_errors:
|
|
78
|
+
return {
|
|
79
|
+
"success": False,
|
|
80
|
+
"error": f"Invalid target configuration: {', '.join(validation_errors)}",
|
|
81
|
+
"error_type": "ValidationError"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Build options
|
|
85
|
+
options = MigrationOptions(
|
|
86
|
+
dry_run=dry_run,
|
|
87
|
+
verbose=True,
|
|
88
|
+
skip_duplicates=skip_duplicates,
|
|
89
|
+
verify=verify,
|
|
90
|
+
rollback_on_failure=True
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Perform migration
|
|
94
|
+
logger.info(f"Starting migration: {source_config.backend_type.value} → {target_backend_type.value}")
|
|
95
|
+
manager = MigrationManager()
|
|
96
|
+
result = await manager.migrate(source_config, target_config_obj, options)
|
|
97
|
+
|
|
98
|
+
# Format response
|
|
99
|
+
response = {
|
|
100
|
+
"success": result.success,
|
|
101
|
+
"dry_run": result.dry_run,
|
|
102
|
+
"source_backend": source_config.backend_type.value,
|
|
103
|
+
"target_backend": target_backend,
|
|
104
|
+
"imported_memories": result.imported_memories,
|
|
105
|
+
"imported_relationships": result.imported_relationships,
|
|
106
|
+
"skipped_memories": result.skipped_memories,
|
|
107
|
+
"duration_seconds": round(result.duration_seconds, 2),
|
|
108
|
+
"errors": result.errors
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Add verification results if available
|
|
112
|
+
if result.verification_result:
|
|
113
|
+
response["verification"] = {
|
|
114
|
+
"valid": result.verification_result.valid,
|
|
115
|
+
"source_count": result.verification_result.source_count,
|
|
116
|
+
"target_count": result.verification_result.target_count,
|
|
117
|
+
"sample_checks": result.verification_result.sample_checks,
|
|
118
|
+
"sample_passed": result.verification_result.sample_passed,
|
|
119
|
+
"errors": result.verification_result.errors
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Add stats if available
|
|
123
|
+
if result.source_stats:
|
|
124
|
+
response["source_stats"] = result.source_stats
|
|
125
|
+
if result.target_stats:
|
|
126
|
+
response["target_stats"] = result.target_stats
|
|
127
|
+
|
|
128
|
+
return response
|
|
129
|
+
|
|
130
|
+
except MigrationError as e:
|
|
131
|
+
logger.error(f"Migration failed: {e}")
|
|
132
|
+
return {
|
|
133
|
+
"success": False,
|
|
134
|
+
"error": str(e),
|
|
135
|
+
"error_type": "MigrationError"
|
|
136
|
+
}
|
|
137
|
+
except Exception as e:
|
|
138
|
+
logger.error(f"Unexpected error during migration: {e}", exc_info=True)
|
|
139
|
+
return {
|
|
140
|
+
"success": False,
|
|
141
|
+
"error": str(e),
|
|
142
|
+
"error_type": type(e).__name__
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
async def handle_validate_migration(
|
|
147
|
+
target_backend: str,
|
|
148
|
+
target_config: Optional[Dict[str, Any]] = None
|
|
149
|
+
) -> Dict[str, Any]:
|
|
150
|
+
"""
|
|
151
|
+
Validate that migration to target backend would succeed.
|
|
152
|
+
|
|
153
|
+
This is a dry-run that checks:
|
|
154
|
+
- Source backend is accessible
|
|
155
|
+
- Target backend is accessible
|
|
156
|
+
- Backends are compatible
|
|
157
|
+
- Estimates migration size and duration
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
target_backend: Target backend type
|
|
161
|
+
target_config: Target backend configuration
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
Validation result with checks and estimates
|
|
165
|
+
|
|
166
|
+
Example:
|
|
167
|
+
# Validate migration before running
|
|
168
|
+
result = await validate_migration(
|
|
169
|
+
target_backend="falkordb",
|
|
170
|
+
target_config={
|
|
171
|
+
"uri": "redis://prod.example.com:6379"
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
"""
|
|
175
|
+
# Call migrate_database with dry_run=True
|
|
176
|
+
return await handle_migrate_database(
|
|
177
|
+
target_backend=target_backend,
|
|
178
|
+
target_config=target_config,
|
|
179
|
+
dry_run=True,
|
|
180
|
+
verify=False # No need to verify in dry-run
|
|
181
|
+
)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Relationship tool handlers for the MCP server.
|
|
3
|
+
|
|
4
|
+
This module contains handlers for relationship operations:
|
|
5
|
+
- create_relationship: Create relationships between memories
|
|
6
|
+
- get_related_memories: Find memories related to a specific memory
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any, Dict
|
|
12
|
+
|
|
13
|
+
from mcp.types import CallToolResult, TextContent
|
|
14
|
+
|
|
15
|
+
from ..database import MemoryDatabase
|
|
16
|
+
from ..models import RelationshipType, RelationshipProperties
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def handle_create_relationship(
|
|
22
|
+
memory_db: MemoryDatabase,
|
|
23
|
+
arguments: Dict[str, Any]
|
|
24
|
+
) -> CallToolResult:
|
|
25
|
+
"""Handle create_relationship tool call.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
memory_db: Database instance for memory operations
|
|
29
|
+
arguments: Tool arguments from MCP call containing:
|
|
30
|
+
- from_memory_id: ID of source memory
|
|
31
|
+
- to_memory_id: ID of target memory
|
|
32
|
+
- relationship_type: Type of relationship (SOLVES, CAUSES, etc.)
|
|
33
|
+
- strength: Optional relationship strength (0.0-1.0, default: 0.5)
|
|
34
|
+
- confidence: Optional confidence score (0.0-1.0, default: 0.8)
|
|
35
|
+
- context: Optional natural language description
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
CallToolResult with relationship ID on success or error message on failure
|
|
39
|
+
"""
|
|
40
|
+
try:
|
|
41
|
+
# Get user-provided context (natural language)
|
|
42
|
+
user_context = arguments.get("context")
|
|
43
|
+
|
|
44
|
+
# Auto-extract structure if context provided
|
|
45
|
+
structured_context = None
|
|
46
|
+
if user_context:
|
|
47
|
+
from ..utils.context_extractor import extract_context_structure
|
|
48
|
+
structure = extract_context_structure(user_context)
|
|
49
|
+
structured_context = json.dumps(structure) # Serialize to JSON string
|
|
50
|
+
|
|
51
|
+
properties = RelationshipProperties(
|
|
52
|
+
strength=arguments.get("strength", 0.5),
|
|
53
|
+
confidence=arguments.get("confidence", 0.8),
|
|
54
|
+
context=structured_context # Store JSON string
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
relationship_id = await memory_db.create_relationship(
|
|
58
|
+
from_memory_id=arguments["from_memory_id"],
|
|
59
|
+
to_memory_id=arguments["to_memory_id"],
|
|
60
|
+
relationship_type=RelationshipType(arguments["relationship_type"]),
|
|
61
|
+
properties=properties
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
return CallToolResult(
|
|
65
|
+
content=[TextContent(
|
|
66
|
+
type="text",
|
|
67
|
+
text=f"Relationship created successfully: {relationship_id}"
|
|
68
|
+
)]
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
except Exception as e:
|
|
72
|
+
logger.error(f"Failed to create relationship: {e}")
|
|
73
|
+
return CallToolResult(
|
|
74
|
+
content=[TextContent(
|
|
75
|
+
type="text",
|
|
76
|
+
text=f"Failed to create relationship: {e}"
|
|
77
|
+
)],
|
|
78
|
+
isError=True
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
async def handle_get_related_memories(
|
|
83
|
+
memory_db: MemoryDatabase,
|
|
84
|
+
arguments: Dict[str, Any]
|
|
85
|
+
) -> CallToolResult:
|
|
86
|
+
"""Handle get_related_memories tool call.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
memory_db: Database instance for memory operations
|
|
90
|
+
arguments: Tool arguments from MCP call containing:
|
|
91
|
+
- memory_id: ID of memory to find relations for
|
|
92
|
+
- relationship_types: Optional list of relationship types to filter
|
|
93
|
+
- max_depth: Optional maximum traversal depth (default: 2)
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
CallToolResult with list of related memories or error message
|
|
97
|
+
"""
|
|
98
|
+
try:
|
|
99
|
+
memory_id = arguments["memory_id"]
|
|
100
|
+
relationship_types = None
|
|
101
|
+
|
|
102
|
+
if "relationship_types" in arguments:
|
|
103
|
+
relationship_types = [RelationshipType(t) for t in arguments["relationship_types"]]
|
|
104
|
+
|
|
105
|
+
max_depth = arguments.get("max_depth", 2)
|
|
106
|
+
|
|
107
|
+
related_memories = await memory_db.get_related_memories(
|
|
108
|
+
memory_id=memory_id,
|
|
109
|
+
relationship_types=relationship_types,
|
|
110
|
+
max_depth=max_depth
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if not related_memories:
|
|
114
|
+
return CallToolResult(
|
|
115
|
+
content=[TextContent(
|
|
116
|
+
type="text",
|
|
117
|
+
text=f"No related memories found for: {memory_id}"
|
|
118
|
+
)]
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Format results
|
|
122
|
+
results_text = f"Found {len(related_memories)} related memories:\n\n"
|
|
123
|
+
for i, (memory, relationship) in enumerate(related_memories, 1):
|
|
124
|
+
results_text += f"**{i}. {memory.title}** (ID: {memory.id})\n"
|
|
125
|
+
results_text += f"Relationship: {relationship.type.value} (strength: {relationship.properties.strength})\n"
|
|
126
|
+
results_text += f"Type: {memory.type.value} | Importance: {memory.importance}\n\n"
|
|
127
|
+
|
|
128
|
+
return CallToolResult(
|
|
129
|
+
content=[TextContent(type="text", text=results_text)]
|
|
130
|
+
)
|
|
131
|
+
except KeyError as e:
|
|
132
|
+
return CallToolResult(
|
|
133
|
+
content=[TextContent(
|
|
134
|
+
type="text",
|
|
135
|
+
text=f"Missing required field: {e}"
|
|
136
|
+
)],
|
|
137
|
+
isError=True
|
|
138
|
+
)
|
|
139
|
+
except Exception as e:
|
|
140
|
+
logger.error(f"Failed to get related memories: {e}")
|
|
141
|
+
return CallToolResult(
|
|
142
|
+
content=[TextContent(
|
|
143
|
+
type="text",
|
|
144
|
+
text=f"Failed to get related memories: {e}"
|
|
145
|
+
)],
|
|
146
|
+
isError=True
|
|
147
|
+
)
|