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.
Files changed (65) hide show
  1. memorygraph/__init__.py +50 -0
  2. memorygraph/__main__.py +12 -0
  3. memorygraph/advanced_tools.py +509 -0
  4. memorygraph/analytics/__init__.py +46 -0
  5. memorygraph/analytics/advanced_queries.py +727 -0
  6. memorygraph/backends/__init__.py +21 -0
  7. memorygraph/backends/base.py +179 -0
  8. memorygraph/backends/cloud.py +75 -0
  9. memorygraph/backends/cloud_backend.py +858 -0
  10. memorygraph/backends/factory.py +577 -0
  11. memorygraph/backends/falkordb_backend.py +749 -0
  12. memorygraph/backends/falkordblite_backend.py +746 -0
  13. memorygraph/backends/ladybugdb_backend.py +242 -0
  14. memorygraph/backends/memgraph_backend.py +327 -0
  15. memorygraph/backends/neo4j_backend.py +298 -0
  16. memorygraph/backends/sqlite_fallback.py +463 -0
  17. memorygraph/backends/turso.py +448 -0
  18. memorygraph/cli.py +743 -0
  19. memorygraph/cloud_database.py +297 -0
  20. memorygraph/config.py +295 -0
  21. memorygraph/database.py +933 -0
  22. memorygraph/graph_analytics.py +631 -0
  23. memorygraph/integration/__init__.py +69 -0
  24. memorygraph/integration/context_capture.py +426 -0
  25. memorygraph/integration/project_analysis.py +583 -0
  26. memorygraph/integration/workflow_tracking.py +492 -0
  27. memorygraph/intelligence/__init__.py +59 -0
  28. memorygraph/intelligence/context_retrieval.py +447 -0
  29. memorygraph/intelligence/entity_extraction.py +386 -0
  30. memorygraph/intelligence/pattern_recognition.py +420 -0
  31. memorygraph/intelligence/temporal.py +374 -0
  32. memorygraph/migration/__init__.py +27 -0
  33. memorygraph/migration/manager.py +579 -0
  34. memorygraph/migration/models.py +142 -0
  35. memorygraph/migration/scripts/__init__.py +17 -0
  36. memorygraph/migration/scripts/bitemporal_migration.py +595 -0
  37. memorygraph/migration/scripts/multitenancy_migration.py +452 -0
  38. memorygraph/migration_tools_module.py +146 -0
  39. memorygraph/models.py +684 -0
  40. memorygraph/proactive/__init__.py +46 -0
  41. memorygraph/proactive/outcome_learning.py +444 -0
  42. memorygraph/proactive/predictive.py +410 -0
  43. memorygraph/proactive/session_briefing.py +399 -0
  44. memorygraph/relationships.py +668 -0
  45. memorygraph/server.py +883 -0
  46. memorygraph/sqlite_database.py +1876 -0
  47. memorygraph/tools/__init__.py +59 -0
  48. memorygraph/tools/activity_tools.py +262 -0
  49. memorygraph/tools/memory_tools.py +315 -0
  50. memorygraph/tools/migration_tools.py +181 -0
  51. memorygraph/tools/relationship_tools.py +147 -0
  52. memorygraph/tools/search_tools.py +406 -0
  53. memorygraph/tools/temporal_tools.py +339 -0
  54. memorygraph/utils/__init__.py +10 -0
  55. memorygraph/utils/context_extractor.py +429 -0
  56. memorygraph/utils/error_handling.py +151 -0
  57. memorygraph/utils/export_import.py +425 -0
  58. memorygraph/utils/graph_algorithms.py +200 -0
  59. memorygraph/utils/pagination.py +149 -0
  60. memorygraph/utils/project_detection.py +133 -0
  61. memorygraphmcp-0.11.7.dist-info/METADATA +970 -0
  62. memorygraphmcp-0.11.7.dist-info/RECORD +65 -0
  63. memorygraphmcp-0.11.7.dist-info/WHEEL +4 -0
  64. memorygraphmcp-0.11.7.dist-info/entry_points.txt +2 -0
  65. memorygraphmcp-0.11.7.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,59 @@
1
+ """
2
+ Tool handlers for the MCP server.
3
+
4
+ This package contains modular tool handlers organized by functionality:
5
+ - memory_tools: CRUD operations for memories
6
+ - relationship_tools: Create and query relationships
7
+ - search_tools: Search, recall, and contextual search for memories
8
+ - activity_tools: Activity summaries and statistics
9
+ - temporal_tools: Bi-temporal queries and time-travel operations
10
+ """
11
+
12
+ from .memory_tools import (
13
+ handle_store_memory,
14
+ handle_get_memory,
15
+ handle_update_memory,
16
+ handle_delete_memory,
17
+ )
18
+ from .relationship_tools import (
19
+ handle_create_relationship,
20
+ handle_get_related_memories,
21
+ )
22
+ from .search_tools import (
23
+ handle_search_memories,
24
+ handle_recall_memories,
25
+ handle_contextual_search,
26
+ )
27
+ from .activity_tools import (
28
+ handle_get_memory_statistics,
29
+ handle_get_recent_activity,
30
+ handle_search_relationships_by_context,
31
+ )
32
+ from .temporal_tools import (
33
+ handle_query_as_of,
34
+ handle_get_relationship_history,
35
+ handle_what_changed,
36
+ )
37
+
38
+ __all__ = [
39
+ # Memory CRUD operations
40
+ "handle_store_memory",
41
+ "handle_get_memory",
42
+ "handle_update_memory",
43
+ "handle_delete_memory",
44
+ # Relationship operations
45
+ "handle_create_relationship",
46
+ "handle_get_related_memories",
47
+ # Search operations
48
+ "handle_search_memories",
49
+ "handle_recall_memories",
50
+ "handle_contextual_search",
51
+ # Activity and statistics
52
+ "handle_get_memory_statistics",
53
+ "handle_get_recent_activity",
54
+ "handle_search_relationships_by_context",
55
+ # Temporal operations
56
+ "handle_query_as_of",
57
+ "handle_get_relationship_history",
58
+ "handle_what_changed",
59
+ ]
@@ -0,0 +1,262 @@
1
+ """
2
+ Activity and statistics tool handlers for the MCP server.
3
+
4
+ This module contains handlers for activity and statistics operations:
5
+ - get_recent_activity: Get summary of recent memory activity
6
+ - get_memory_statistics: Get statistics about the memory database
7
+ - search_relationships_by_context: Search relationships by structured context fields
8
+ """
9
+
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 ..sqlite_database import SQLiteMemoryDatabase
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ async def handle_get_memory_statistics(
22
+ memory_db: MemoryDatabase,
23
+ arguments: Dict[str, Any]
24
+ ) -> CallToolResult:
25
+ """Handle get_memory_statistics tool call.
26
+
27
+ Args:
28
+ memory_db: Database instance for memory operations
29
+ arguments: Tool arguments from MCP call (no parameters required)
30
+
31
+ Returns:
32
+ CallToolResult with formatted statistics or error message
33
+ """
34
+ try:
35
+ stats = await memory_db.get_memory_statistics()
36
+
37
+ # Format statistics
38
+ stats_text = "**Memory Database Statistics**\n\n"
39
+
40
+ if stats.get("total_memories"):
41
+ stats_text += f"Total Memories: {stats['total_memories']['count']}\n"
42
+
43
+ if stats.get("memories_by_type"):
44
+ stats_text += "\n**Memories by Type:**\n"
45
+ for mem_type, count in stats["memories_by_type"].items():
46
+ stats_text += f"- {mem_type}: {count}\n"
47
+
48
+ if stats.get("total_relationships"):
49
+ stats_text += f"\nTotal Relationships: {stats['total_relationships']['count']}\n"
50
+
51
+ if stats.get("avg_importance"):
52
+ stats_text += f"Average Importance: {stats['avg_importance']['avg_importance']:.2f}\n"
53
+
54
+ if stats.get("avg_confidence"):
55
+ stats_text += f"Average Confidence: {stats['avg_confidence']['avg_confidence']:.2f}\n"
56
+
57
+ return CallToolResult(
58
+ content=[TextContent(type="text", text=stats_text)]
59
+ )
60
+ except Exception as e:
61
+ logger.error(f"Failed to get memory statistics: {e}")
62
+ return CallToolResult(
63
+ content=[TextContent(
64
+ type="text",
65
+ text=f"Failed to get memory statistics: {e}"
66
+ )],
67
+ isError=True
68
+ )
69
+
70
+
71
+ async def handle_get_recent_activity(
72
+ memory_db: MemoryDatabase,
73
+ arguments: Dict[str, Any]
74
+ ) -> CallToolResult:
75
+ """Handle get_recent_activity tool call.
76
+
77
+ Args:
78
+ memory_db: Database instance for memory operations
79
+ arguments: Tool arguments from MCP call containing:
80
+ - days: Number of days to look back (default: 7)
81
+ - project: Optional project path to filter by
82
+
83
+ Returns:
84
+ CallToolResult with formatted activity summary or error message
85
+ """
86
+ try:
87
+ # Check if database supports get_recent_activity
88
+ if not isinstance(memory_db, SQLiteMemoryDatabase):
89
+ return CallToolResult(
90
+ content=[TextContent(
91
+ type="text",
92
+ text="Recent activity summary is only available with SQLite backend"
93
+ )],
94
+ isError=True
95
+ )
96
+
97
+ days = arguments.get("days", 7)
98
+ project = arguments.get("project")
99
+
100
+ # Auto-detect project if not specified
101
+ if not project:
102
+ from ..utils.project_detection import detect_project_context
103
+ project_info = detect_project_context()
104
+ if project_info:
105
+ project = project_info.get("project_path")
106
+
107
+ activity = await memory_db.get_recent_activity(days=days, project=project)
108
+
109
+ # Format results
110
+ result_text = f"**Recent Activity Summary (Last {days} days)**\n\n"
111
+
112
+ if project:
113
+ result_text += f"**Project**: {project}\n\n"
114
+
115
+ # Total count
116
+ result_text += f"**Total Memories**: {activity['total_count']}\n\n"
117
+
118
+ # Memories by type
119
+ if activity['memories_by_type']:
120
+ result_text += "**Breakdown by Type**:\n"
121
+ for mem_type, count in sorted(activity['memories_by_type'].items(), key=lambda x: x[1], reverse=True):
122
+ result_text += f"- {mem_type.replace('_', ' ').title()}: {count}\n"
123
+ result_text += "\n"
124
+
125
+ # Unresolved problems
126
+ if activity['unresolved_problems']:
127
+ result_text += f"**⚠️ Unresolved Problems ({len(activity['unresolved_problems'])})**:\n"
128
+ for problem in activity['unresolved_problems']:
129
+ result_text += f"- **{problem.title}** (importance: {problem.importance:.1f})\n"
130
+ if problem.summary:
131
+ result_text += f" {problem.summary}\n"
132
+ result_text += "\n"
133
+
134
+ # Recent memories
135
+ if activity['recent_memories']:
136
+ result_text += f"**Recent Memories** (showing {min(10, len(activity['recent_memories']))}):\n"
137
+ for i, memory in enumerate(activity['recent_memories'][:10], 1):
138
+ result_text += f"{i}. **{memory.title}** ({memory.type.value})\n"
139
+ if memory.summary:
140
+ result_text += f" {memory.summary}\n"
141
+ result_text += "\n"
142
+
143
+ # Next steps suggestion
144
+ result_text += "**💡 Next Steps**:\n"
145
+ if activity['unresolved_problems']:
146
+ result_text += "- Review unresolved problems and consider solutions\n"
147
+ result_text += f"- Use `get_memory(memory_id=\"...\")` for details\n"
148
+ else:
149
+ result_text += "- All problems have been addressed!\n"
150
+
151
+ return CallToolResult(
152
+ content=[TextContent(type="text", text=result_text)]
153
+ )
154
+
155
+ except Exception as e:
156
+ logger.error(f"Error in get_recent_activity: {e}")
157
+ return CallToolResult(
158
+ content=[TextContent(
159
+ type="text",
160
+ text=f"Failed to get recent activity: {e}"
161
+ )],
162
+ isError=True
163
+ )
164
+
165
+
166
+ async def handle_search_relationships_by_context(
167
+ memory_db: MemoryDatabase,
168
+ arguments: Dict[str, Any]
169
+ ) -> CallToolResult:
170
+ """Handle search_relationships_by_context tool call.
171
+
172
+ Args:
173
+ memory_db: Database instance for memory operations
174
+ arguments: Tool arguments from MCP call containing:
175
+ - scope: Filter by scope (partial/full/conditional, optional)
176
+ - conditions: Filter by conditions (optional)
177
+ - has_evidence: Filter by presence/absence of evidence (optional)
178
+ - evidence: Filter by specific evidence types (optional)
179
+ - components: Filter by components mentioned (optional)
180
+ - temporal: Filter by temporal information (optional)
181
+ - limit: Maximum results (default: 20)
182
+
183
+ Returns:
184
+ CallToolResult with formatted relationship results or error message
185
+ """
186
+ try:
187
+ # Use SQLiteMemoryDatabase's search_relationships_by_context method
188
+ if not isinstance(memory_db, SQLiteMemoryDatabase):
189
+ return CallToolResult(
190
+ content=[TextContent(
191
+ type="text",
192
+ text="Context-based relationship search is only available with SQLite backend"
193
+ )],
194
+ isError=True
195
+ )
196
+
197
+ relationships = await memory_db.search_relationships_by_context(
198
+ scope=arguments.get("scope"),
199
+ conditions=arguments.get("conditions"),
200
+ has_evidence=arguments.get("has_evidence"),
201
+ evidence=arguments.get("evidence"),
202
+ components=arguments.get("components"),
203
+ temporal=arguments.get("temporal"),
204
+ limit=arguments.get("limit", 20)
205
+ )
206
+
207
+ if not relationships:
208
+ return CallToolResult(
209
+ content=[TextContent(
210
+ type="text",
211
+ text="No relationships found matching the specified context criteria"
212
+ )]
213
+ )
214
+
215
+ # Format results
216
+ result_text = f"**Found {len(relationships)} relationships matching context criteria**\n\n"
217
+
218
+ # Show applied filters
219
+ filters_applied = []
220
+ if arguments.get("scope"):
221
+ filters_applied.append(f"Scope: {arguments['scope']}")
222
+ if arguments.get("conditions"):
223
+ filters_applied.append(f"Conditions: {', '.join(arguments['conditions'])}")
224
+ if arguments.get("has_evidence") is not None:
225
+ filters_applied.append(f"Has Evidence: {arguments['has_evidence']}")
226
+ if arguments.get("evidence"):
227
+ filters_applied.append(f"Evidence: {', '.join(arguments['evidence'])}")
228
+ if arguments.get("components"):
229
+ filters_applied.append(f"Components: {', '.join(arguments['components'])}")
230
+ if arguments.get("temporal"):
231
+ filters_applied.append(f"Temporal: {arguments['temporal']}")
232
+
233
+ if filters_applied:
234
+ result_text += "**Filters Applied:**\n"
235
+ for f in filters_applied:
236
+ result_text += f"- {f}\n"
237
+ result_text += "\n"
238
+
239
+ # List relationships
240
+ for i, rel in enumerate(relationships, 1):
241
+ result_text += f"{i}. **{rel.type.value}**\n"
242
+ result_text += f" - ID: {rel.id}\n"
243
+ result_text += f" - From: {rel.from_memory_id}\n"
244
+ result_text += f" - To: {rel.to_memory_id}\n"
245
+ result_text += f" - Strength: {rel.properties.strength:.2f}\n"
246
+ if rel.properties.context:
247
+ result_text += f" - Context: {rel.properties.context}\n"
248
+ result_text += "\n"
249
+
250
+ return CallToolResult(
251
+ content=[TextContent(type="text", text=result_text)]
252
+ )
253
+
254
+ except Exception as e:
255
+ logger.error(f"Error in search_relationships_by_context: {e}")
256
+ return CallToolResult(
257
+ content=[TextContent(
258
+ type="text",
259
+ text=f"Failed to search relationships by context: {e}"
260
+ )],
261
+ isError=True
262
+ )
@@ -0,0 +1,315 @@
1
+ """
2
+ Memory CRUD tool handlers for the MCP server.
3
+
4
+ This module contains handlers for basic memory operations:
5
+ - store_memory: Create new memories
6
+ - get_memory: Retrieve a memory by ID
7
+ - update_memory: Modify an existing memory
8
+ - delete_memory: Remove a memory and its relationships
9
+ """
10
+
11
+ import logging
12
+ from typing import Any, Dict
13
+
14
+ from mcp.types import CallToolResult, TextContent
15
+ from pydantic import ValidationError
16
+
17
+ from ..database import MemoryDatabase
18
+ from ..models import Memory, MemoryType, MemoryContext
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ async def handle_store_memory(
24
+ memory_db: MemoryDatabase,
25
+ arguments: Dict[str, Any]
26
+ ) -> CallToolResult:
27
+ """Handle store_memory tool call.
28
+
29
+ Args:
30
+ memory_db: Database instance for memory operations
31
+ arguments: Tool arguments from MCP call containing:
32
+ - type: Memory type (solution, problem, error, etc.)
33
+ - title: Short descriptive title
34
+ - content: Detailed content
35
+ - summary: Optional brief summary
36
+ - tags: Optional list of tags
37
+ - importance: Optional importance score (0.0-1.0)
38
+ - context: Optional context information
39
+
40
+ Returns:
41
+ CallToolResult with memory ID on success or error message on failure
42
+ """
43
+ try:
44
+ # Extract context if provided
45
+ context = None
46
+ if "context" in arguments:
47
+ context = MemoryContext(**arguments["context"])
48
+
49
+ # Create memory object
50
+ memory = Memory(
51
+ type=MemoryType(arguments["type"]),
52
+ title=arguments["title"],
53
+ content=arguments["content"],
54
+ summary=arguments.get("summary"),
55
+ tags=arguments.get("tags", []),
56
+ importance=arguments.get("importance", 0.5),
57
+ context=context
58
+ )
59
+
60
+ # Store in database
61
+ memory_id = await memory_db.store_memory(memory)
62
+
63
+ return CallToolResult(
64
+ content=[TextContent(
65
+ type="text",
66
+ text=f"Memory stored successfully with ID: {memory_id}"
67
+ )]
68
+ )
69
+
70
+ except (ValidationError, KeyError, ValueError) as e:
71
+ return CallToolResult(
72
+ content=[TextContent(
73
+ type="text",
74
+ text=f"Validation error: {e}"
75
+ )],
76
+ isError=True
77
+ )
78
+ except Exception as e:
79
+ logger.error(f"Failed to store memory: {e}")
80
+ return CallToolResult(
81
+ content=[TextContent(
82
+ type="text",
83
+ text=f"Failed to store memory: {e}"
84
+ )],
85
+ isError=True
86
+ )
87
+
88
+
89
+ async def handle_get_memory(
90
+ memory_db: MemoryDatabase,
91
+ arguments: Dict[str, Any]
92
+ ) -> CallToolResult:
93
+ """Handle get_memory tool call.
94
+
95
+ Args:
96
+ memory_db: Database instance for memory operations
97
+ arguments: Tool arguments from MCP call containing:
98
+ - memory_id: ID of memory to retrieve
99
+ - include_relationships: Whether to include related memories (default: True)
100
+
101
+ Returns:
102
+ CallToolResult with formatted memory details or error message
103
+ """
104
+ try:
105
+ memory_id = arguments["memory_id"]
106
+ include_relationships = arguments.get("include_relationships", True)
107
+
108
+ memory = await memory_db.get_memory(memory_id, include_relationships)
109
+
110
+ if not memory:
111
+ return CallToolResult(
112
+ content=[TextContent(
113
+ type="text",
114
+ text=f"Memory not found: {memory_id}"
115
+ )],
116
+ isError=True
117
+ )
118
+
119
+ # Format memory for display
120
+ memory_text = f"""**Memory: {memory.title}**
121
+ Type: {memory.type.value}
122
+ Created: {memory.created_at}
123
+ Importance: {memory.importance}
124
+ Tags: {', '.join(memory.tags) if memory.tags else 'None'}
125
+
126
+ **Content:**
127
+ {memory.content}"""
128
+
129
+ if memory.summary:
130
+ memory_text = f"**Summary:** {memory.summary}\n\n" + memory_text
131
+
132
+ # Add context information if available
133
+ if memory.context:
134
+ context_parts = []
135
+
136
+ if memory.context.project_path:
137
+ context_parts.append(f"Project: {memory.context.project_path}")
138
+
139
+ if memory.context.files_involved:
140
+ files_str = ', '.join(memory.context.files_involved[:3])
141
+ if len(memory.context.files_involved) > 3:
142
+ files_str += f" (+{len(memory.context.files_involved) - 3} more)"
143
+ context_parts.append(f"Files: {files_str}")
144
+
145
+ if memory.context.languages:
146
+ context_parts.append(f"Languages: {', '.join(memory.context.languages)}")
147
+
148
+ if memory.context.frameworks:
149
+ context_parts.append(f"Frameworks: {', '.join(memory.context.frameworks)}")
150
+
151
+ if memory.context.technologies:
152
+ context_parts.append(f"Technologies: {', '.join(memory.context.technologies)}")
153
+
154
+ if memory.context.git_branch:
155
+ context_parts.append(f"Branch: {memory.context.git_branch}")
156
+
157
+ if context_parts:
158
+ context_text = "\n**Context:**\n" + "\n".join(f" {part}" for part in context_parts)
159
+ memory_text += "\n" + context_text
160
+
161
+ return CallToolResult(
162
+ content=[TextContent(type="text", text=memory_text)]
163
+ )
164
+ except KeyError as e:
165
+ return CallToolResult(
166
+ content=[TextContent(
167
+ type="text",
168
+ text=f"Missing required field: {e}"
169
+ )],
170
+ isError=True
171
+ )
172
+ except Exception as e:
173
+ logger.error(f"Failed to get memory: {e}")
174
+ return CallToolResult(
175
+ content=[TextContent(
176
+ type="text",
177
+ text=f"Failed to get memory: {e}"
178
+ )],
179
+ isError=True
180
+ )
181
+
182
+
183
+ async def handle_update_memory(
184
+ memory_db: MemoryDatabase,
185
+ arguments: Dict[str, Any]
186
+ ) -> CallToolResult:
187
+ """Handle update_memory tool call.
188
+
189
+ Args:
190
+ memory_db: Database instance for memory operations
191
+ arguments: Tool arguments from MCP call containing:
192
+ - memory_id: ID of memory to update (required)
193
+ - title: New title (optional)
194
+ - content: New content (optional)
195
+ - summary: New summary (optional)
196
+ - tags: New tags list (optional)
197
+ - importance: New importance score (optional)
198
+
199
+ Returns:
200
+ CallToolResult with success message or error
201
+ """
202
+ try:
203
+ memory_id = arguments["memory_id"]
204
+
205
+ # Get existing memory
206
+ memory = await memory_db.get_memory(memory_id, include_relationships=False)
207
+ if not memory:
208
+ return CallToolResult(
209
+ content=[TextContent(
210
+ type="text",
211
+ text=f"Memory not found: {memory_id}"
212
+ )],
213
+ isError=True
214
+ )
215
+
216
+ # Update fields
217
+ if "title" in arguments:
218
+ memory.title = arguments["title"]
219
+ if "content" in arguments:
220
+ memory.content = arguments["content"]
221
+ if "summary" in arguments:
222
+ memory.summary = arguments["summary"]
223
+ if "tags" in arguments:
224
+ memory.tags = arguments["tags"]
225
+ if "importance" in arguments:
226
+ memory.importance = arguments["importance"]
227
+
228
+ # Update in database
229
+ success = await memory_db.update_memory(memory)
230
+
231
+ if success:
232
+ return CallToolResult(
233
+ content=[TextContent(
234
+ type="text",
235
+ text=f"Memory updated successfully: {memory_id}"
236
+ )]
237
+ )
238
+ else:
239
+ return CallToolResult(
240
+ content=[TextContent(
241
+ type="text",
242
+ text=f"Failed to update memory: {memory_id}"
243
+ )],
244
+ isError=True
245
+ )
246
+ except KeyError as e:
247
+ return CallToolResult(
248
+ content=[TextContent(
249
+ type="text",
250
+ text=f"Missing required field: {e}"
251
+ )],
252
+ isError=True
253
+ )
254
+ except Exception as e:
255
+ logger.error(f"Failed to update memory: {e}")
256
+ return CallToolResult(
257
+ content=[TextContent(
258
+ type="text",
259
+ text=f"Failed to update memory: {e}"
260
+ )],
261
+ isError=True
262
+ )
263
+
264
+
265
+ async def handle_delete_memory(
266
+ memory_db: MemoryDatabase,
267
+ arguments: Dict[str, Any]
268
+ ) -> CallToolResult:
269
+ """Handle delete_memory tool call.
270
+
271
+ Args:
272
+ memory_db: Database instance for memory operations
273
+ arguments: Tool arguments from MCP call containing:
274
+ - memory_id: ID of memory to delete
275
+
276
+ Returns:
277
+ CallToolResult with success message or error
278
+ """
279
+ try:
280
+ memory_id = arguments["memory_id"]
281
+
282
+ success = await memory_db.delete_memory(memory_id)
283
+
284
+ if success:
285
+ return CallToolResult(
286
+ content=[TextContent(
287
+ type="text",
288
+ text=f"Memory deleted successfully: {memory_id}"
289
+ )]
290
+ )
291
+ else:
292
+ return CallToolResult(
293
+ content=[TextContent(
294
+ type="text",
295
+ text=f"Failed to delete memory (may not exist): {memory_id}"
296
+ )],
297
+ isError=True
298
+ )
299
+ except KeyError as e:
300
+ return CallToolResult(
301
+ content=[TextContent(
302
+ type="text",
303
+ text=f"Missing required field: {e}"
304
+ )],
305
+ isError=True
306
+ )
307
+ except Exception as e:
308
+ logger.error(f"Failed to delete memory: {e}")
309
+ return CallToolResult(
310
+ content=[TextContent(
311
+ type="text",
312
+ text=f"Failed to delete memory: {e}"
313
+ )],
314
+ isError=True
315
+ )