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
memorygraph/server.py
ADDED
|
@@ -0,0 +1,883 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Claude Code Memory Server - MCP implementation.
|
|
3
|
+
|
|
4
|
+
This module implements the Model Context Protocol server that provides intelligent
|
|
5
|
+
memory capabilities for Claude Code using Neo4j as the backend storage.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import logging
|
|
10
|
+
import os
|
|
11
|
+
import uuid
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from typing import Any, Dict, List, Optional, Sequence
|
|
14
|
+
|
|
15
|
+
from mcp.server import Server, NotificationOptions
|
|
16
|
+
from mcp.server.models import InitializationOptions
|
|
17
|
+
from mcp.server.stdio import stdio_server
|
|
18
|
+
from mcp.types import (
|
|
19
|
+
Tool,
|
|
20
|
+
TextContent,
|
|
21
|
+
CallToolResult,
|
|
22
|
+
ListToolsRequest,
|
|
23
|
+
ListToolsResult,
|
|
24
|
+
)
|
|
25
|
+
from pydantic import ValidationError
|
|
26
|
+
|
|
27
|
+
from . import __version__
|
|
28
|
+
from .database import MemoryDatabase
|
|
29
|
+
from .sqlite_database import SQLiteMemoryDatabase
|
|
30
|
+
from .cloud_database import CloudMemoryDatabase
|
|
31
|
+
from .backends.sqlite_fallback import SQLiteFallbackBackend
|
|
32
|
+
from .backends.cloud_backend import CloudBackend
|
|
33
|
+
from .models import (
|
|
34
|
+
Memory,
|
|
35
|
+
MemoryType,
|
|
36
|
+
RelationshipType,
|
|
37
|
+
RelationshipProperties,
|
|
38
|
+
SearchQuery,
|
|
39
|
+
MemoryContext,
|
|
40
|
+
MemoryError,
|
|
41
|
+
MemoryNotFoundError,
|
|
42
|
+
RelationshipError,
|
|
43
|
+
ValidationError as MemoryValidationError,
|
|
44
|
+
DatabaseConnectionError,
|
|
45
|
+
)
|
|
46
|
+
from .advanced_tools import ADVANCED_RELATIONSHIP_TOOLS, AdvancedRelationshipHandlers
|
|
47
|
+
from .migration_tools_module import MIGRATION_TOOLS, MIGRATION_TOOL_HANDLERS
|
|
48
|
+
# Removed: intelligence_tools, integration_tools, proactive_tools (moved to experimental/)
|
|
49
|
+
from .config import Config
|
|
50
|
+
from .tools import (
|
|
51
|
+
handle_store_memory,
|
|
52
|
+
handle_get_memory,
|
|
53
|
+
handle_update_memory,
|
|
54
|
+
handle_delete_memory,
|
|
55
|
+
handle_create_relationship,
|
|
56
|
+
handle_get_related_memories,
|
|
57
|
+
handle_search_memories,
|
|
58
|
+
handle_recall_memories,
|
|
59
|
+
handle_contextual_search,
|
|
60
|
+
handle_get_memory_statistics,
|
|
61
|
+
handle_get_recent_activity,
|
|
62
|
+
handle_search_relationships_by_context,
|
|
63
|
+
# Temporal handlers deferred (backend methods available via Python API):
|
|
64
|
+
# handle_query_as_of, handle_get_relationship_history, handle_what_changed
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# Configure logging
|
|
69
|
+
logging.basicConfig(
|
|
70
|
+
level=logging.INFO,
|
|
71
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
72
|
+
)
|
|
73
|
+
logger = logging.getLogger(__name__)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ClaudeMemoryServer:
|
|
77
|
+
"""Claude Code Memory MCP Server implementation."""
|
|
78
|
+
|
|
79
|
+
def __init__(self):
|
|
80
|
+
"""Initialize the memory server."""
|
|
81
|
+
self.server = Server("claude-memory")
|
|
82
|
+
self.db_connection = None # GraphBackend instance
|
|
83
|
+
self.memory_db: Optional[MemoryDatabase] = None
|
|
84
|
+
self.advanced_handlers: Optional[AdvancedRelationshipHandlers] = None
|
|
85
|
+
|
|
86
|
+
# Register MCP handlers
|
|
87
|
+
self._register_handlers()
|
|
88
|
+
|
|
89
|
+
# Collect all tools from all modules
|
|
90
|
+
all_tools = self._collect_all_tools()
|
|
91
|
+
|
|
92
|
+
# Filter tools based on profile
|
|
93
|
+
enabled_tool_names = Config.get_enabled_tools()
|
|
94
|
+
if enabled_tool_names is None:
|
|
95
|
+
# Full profile: all tools enabled
|
|
96
|
+
self.tools = all_tools
|
|
97
|
+
logger.info(f"Tool profile: FULL - All {len(all_tools)} tools enabled")
|
|
98
|
+
else:
|
|
99
|
+
# Filter tools by name
|
|
100
|
+
self.tools = [tool for tool in all_tools if tool.name in enabled_tool_names]
|
|
101
|
+
logger.info(f"Tool profile: {Config.TOOL_PROFILE.upper()} - {len(self.tools)}/{len(all_tools)} tools enabled")
|
|
102
|
+
|
|
103
|
+
def _collect_all_tools(self) -> List[Tool]:
|
|
104
|
+
"""Collect all tool definitions from all modules."""
|
|
105
|
+
# Basic tools (defined inline below)
|
|
106
|
+
basic_tools = [
|
|
107
|
+
Tool(
|
|
108
|
+
name="recall_memories",
|
|
109
|
+
description="""🎯 RECOMMENDED STARTING POINT for recalling past memories and learnings.
|
|
110
|
+
|
|
111
|
+
This is a convenience tool that wraps search_memories with optimal defaults for natural language queries.
|
|
112
|
+
|
|
113
|
+
WHEN TO USE:
|
|
114
|
+
- This should be your FIRST tool for any recall query
|
|
115
|
+
- User asks "What did we learn about X?"
|
|
116
|
+
- Looking for past solutions, problems, or patterns
|
|
117
|
+
- Understanding project context or history
|
|
118
|
+
- Finding related memories by topic
|
|
119
|
+
|
|
120
|
+
WHY USE THIS vs search_memories:
|
|
121
|
+
- Optimized for natural language queries
|
|
122
|
+
- Automatically uses fuzzy matching (handles plurals, tenses, case)
|
|
123
|
+
- Always includes relationship context
|
|
124
|
+
- Simpler interface for common use cases
|
|
125
|
+
- Best default settings applied
|
|
126
|
+
|
|
127
|
+
HOW TO USE:
|
|
128
|
+
- Pass a natural language query (e.g., "Redis timeout solutions")
|
|
129
|
+
- Optionally filter by memory_types for precision
|
|
130
|
+
- Optionally specify project_path to scope results
|
|
131
|
+
- Results automatically ranked by relevance
|
|
132
|
+
|
|
133
|
+
EXAMPLES:
|
|
134
|
+
- User: "What timeouts have we fixed?" → recall_memories(query="timeout fix")
|
|
135
|
+
- User: "Show me Redis solutions" → recall_memories(query="Redis", memory_types=["solution"])
|
|
136
|
+
- User: "What authentication errors occurred?" → recall_memories(query="authentication error", memory_types=["error"])
|
|
137
|
+
- User: "Catch me up on this project" → recall_memories(project_path="/current/project")
|
|
138
|
+
|
|
139
|
+
RETURNS:
|
|
140
|
+
- Memories with match quality hints
|
|
141
|
+
- Immediate relationships (what solves what, what causes what)
|
|
142
|
+
- Context summaries for quick understanding
|
|
143
|
+
|
|
144
|
+
NOTE: For advanced queries (boolean operators, exact matches, multi-term), use search_memories directly.""",
|
|
145
|
+
inputSchema={
|
|
146
|
+
"type": "object",
|
|
147
|
+
"properties": {
|
|
148
|
+
"query": {
|
|
149
|
+
"type": "string",
|
|
150
|
+
"description": "Natural language query for what you're looking for"
|
|
151
|
+
},
|
|
152
|
+
"memory_types": {
|
|
153
|
+
"type": "array",
|
|
154
|
+
"items": {
|
|
155
|
+
"type": "string",
|
|
156
|
+
"enum": [t.value for t in MemoryType]
|
|
157
|
+
},
|
|
158
|
+
"description": "Optional: Filter by memory types for more precision"
|
|
159
|
+
},
|
|
160
|
+
"project_path": {
|
|
161
|
+
"type": "string",
|
|
162
|
+
"description": "Optional: Filter by project path to scope results"
|
|
163
|
+
},
|
|
164
|
+
"limit": {
|
|
165
|
+
"type": "integer",
|
|
166
|
+
"minimum": 1,
|
|
167
|
+
"maximum": 1000,
|
|
168
|
+
"description": "Maximum number of results per page (default: 20)"
|
|
169
|
+
},
|
|
170
|
+
"offset": {
|
|
171
|
+
"type": "integer",
|
|
172
|
+
"minimum": 0,
|
|
173
|
+
"description": "Number of results to skip for pagination (default: 0)"
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
),
|
|
178
|
+
Tool(
|
|
179
|
+
name="store_memory",
|
|
180
|
+
description="""Store a new memory with context and metadata.
|
|
181
|
+
|
|
182
|
+
WHEN TO USE:
|
|
183
|
+
- Capturing solutions to problems
|
|
184
|
+
- Recording important decisions and rationale
|
|
185
|
+
- Documenting errors and their causes
|
|
186
|
+
- Noting patterns or learnings from work
|
|
187
|
+
- Saving technology choices and trade-offs
|
|
188
|
+
- Recording project context and state
|
|
189
|
+
|
|
190
|
+
HOW TO USE:
|
|
191
|
+
- Choose appropriate type: solution, problem, error, fix, decision, pattern, etc.
|
|
192
|
+
- Write clear, searchable title (this is searched during recall)
|
|
193
|
+
- Include detailed content with specifics
|
|
194
|
+
- Add tags for categorical organization (e.g., "redis", "authentication", "performance")
|
|
195
|
+
- Set importance: 0.8-1.0 for critical info, 0.5-0.7 for normal, 0.0-0.4 for reference
|
|
196
|
+
- Optional: Add project_path in context to scope to current project
|
|
197
|
+
|
|
198
|
+
EXAMPLES:
|
|
199
|
+
- Solved a bug: store_memory(type="solution", title="Fixed Redis timeout in payment flow", content="...", tags=["redis", "payment"], importance=0.8)
|
|
200
|
+
- Learned a pattern: store_memory(type="pattern", title="Use exponential backoff for API retries", content="...", tags=["api", "reliability"])
|
|
201
|
+
- Made a decision: store_memory(type="decision", title="Chose PostgreSQL over MongoDB", content="Rationale: ...", importance=0.9)
|
|
202
|
+
- Hit an error: store_memory(type="error", title="Authentication fails with OAuth2", content="Error details...", tags=["auth", "oauth"])
|
|
203
|
+
|
|
204
|
+
AFTER STORING:
|
|
205
|
+
- Use create_relationship to link related memories (e.g., solution SOLVES problem)
|
|
206
|
+
- Returns memory_id for future reference""",
|
|
207
|
+
inputSchema={
|
|
208
|
+
"type": "object",
|
|
209
|
+
"properties": {
|
|
210
|
+
"type": {
|
|
211
|
+
"type": "string",
|
|
212
|
+
"enum": [t.value for t in MemoryType],
|
|
213
|
+
"description": "Type of memory to store"
|
|
214
|
+
},
|
|
215
|
+
"title": {
|
|
216
|
+
"type": "string",
|
|
217
|
+
"description": "Short descriptive title for the memory"
|
|
218
|
+
},
|
|
219
|
+
"content": {
|
|
220
|
+
"type": "string",
|
|
221
|
+
"description": "Detailed content of the memory"
|
|
222
|
+
},
|
|
223
|
+
"summary": {
|
|
224
|
+
"type": "string",
|
|
225
|
+
"description": "Optional brief summary of the memory"
|
|
226
|
+
},
|
|
227
|
+
"tags": {
|
|
228
|
+
"type": "array",
|
|
229
|
+
"items": {"type": "string"},
|
|
230
|
+
"description": "Tags to categorize the memory"
|
|
231
|
+
},
|
|
232
|
+
"importance": {
|
|
233
|
+
"type": "number",
|
|
234
|
+
"minimum": 0.0,
|
|
235
|
+
"maximum": 1.0,
|
|
236
|
+
"description": "Importance score (0.0-1.0)"
|
|
237
|
+
},
|
|
238
|
+
"context": {
|
|
239
|
+
"type": "object",
|
|
240
|
+
"description": "Context information for the memory"
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
"required": ["type", "title", "content"]
|
|
244
|
+
}
|
|
245
|
+
),
|
|
246
|
+
Tool(
|
|
247
|
+
name="get_memory",
|
|
248
|
+
description="""Retrieve a specific memory by ID with full details.
|
|
249
|
+
|
|
250
|
+
WHEN TO USE:
|
|
251
|
+
- You have a memory_id from search results
|
|
252
|
+
- User asks for details about a specific memory
|
|
253
|
+
- Need to verify memory contents before updating or deleting
|
|
254
|
+
- Drilling down after finding a memory in search
|
|
255
|
+
|
|
256
|
+
HOW TO USE:
|
|
257
|
+
- Pass memory_id from search_memories or store_memory results
|
|
258
|
+
- Set include_relationships=true (default) to see what connects to this memory
|
|
259
|
+
- Returns full memory with all fields
|
|
260
|
+
|
|
261
|
+
EXAMPLE:
|
|
262
|
+
- After search: get_memory(memory_id="abc-123", include_relationships=true)
|
|
263
|
+
|
|
264
|
+
NOTE: Prefer search_memories for discovery. Use get_memory only when you have a specific ID.""",
|
|
265
|
+
inputSchema={
|
|
266
|
+
"type": "object",
|
|
267
|
+
"properties": {
|
|
268
|
+
"memory_id": {
|
|
269
|
+
"type": "string",
|
|
270
|
+
"description": "ID of the memory to retrieve"
|
|
271
|
+
},
|
|
272
|
+
"include_relationships": {
|
|
273
|
+
"type": "boolean",
|
|
274
|
+
"description": "Whether to include related memories"
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
"required": ["memory_id"]
|
|
278
|
+
}
|
|
279
|
+
),
|
|
280
|
+
Tool(
|
|
281
|
+
name="search_memories",
|
|
282
|
+
description="""Advanced search tool with fine-grained control over search parameters.
|
|
283
|
+
|
|
284
|
+
⚠️ CONSIDER USING recall_memories FIRST - it has better defaults for most queries.
|
|
285
|
+
Use search_memories only when you need:
|
|
286
|
+
- Exact matching (search_tolerance="strict")
|
|
287
|
+
- Multi-term boolean queries
|
|
288
|
+
- Specific tag filtering
|
|
289
|
+
- Advanced parameter control
|
|
290
|
+
|
|
291
|
+
WHEN TO USE:
|
|
292
|
+
- Need strict exact matching instead of fuzzy
|
|
293
|
+
- Complex queries with multiple terms and match_mode
|
|
294
|
+
- Filtering by specific tags or importance thresholds
|
|
295
|
+
- When recall_memories didn't find what you need
|
|
296
|
+
|
|
297
|
+
HOW TO USE:
|
|
298
|
+
- Query searches across title, content, and summary fields
|
|
299
|
+
- Use search_tolerance to control matching:
|
|
300
|
+
• 'normal' (default): Handles plurals, tenses, case variations (e.g., "timeout" matches "timeouts", "timed out")
|
|
301
|
+
• 'strict': Exact substring matches only
|
|
302
|
+
• 'fuzzy': Reserved for future typo tolerance
|
|
303
|
+
- Filter by memory_types to narrow results (e.g., only "solution" or "problem")
|
|
304
|
+
- Filter by tags for categorical search
|
|
305
|
+
- Results include relationship context automatically (what connects to what)
|
|
306
|
+
|
|
307
|
+
EXAMPLES:
|
|
308
|
+
- User: "What timeouts have we fixed?" → search_memories(query="timeout", memory_types=["solution"])
|
|
309
|
+
- User: "Show me Redis issues" → search_memories(query="Redis", memory_types=["problem", "error"])
|
|
310
|
+
- User: "Authentication solutions" → search_memories(query="authentication", memory_types=["solution"])
|
|
311
|
+
- User: "High priority items" → search_memories(min_importance=0.7)
|
|
312
|
+
|
|
313
|
+
RESULTS INCLUDE:
|
|
314
|
+
- Match quality hints (which fields matched)
|
|
315
|
+
- Relationship context (what solves/causes/relates to what)
|
|
316
|
+
- Context summaries for quick scanning""",
|
|
317
|
+
inputSchema={
|
|
318
|
+
"type": "object",
|
|
319
|
+
"properties": {
|
|
320
|
+
"query": {
|
|
321
|
+
"type": "string",
|
|
322
|
+
"description": "Text to search for in memory content"
|
|
323
|
+
},
|
|
324
|
+
"terms": {
|
|
325
|
+
"type": "array",
|
|
326
|
+
"items": {"type": "string"},
|
|
327
|
+
"description": "Multiple search terms for complex queries (alternative to query)"
|
|
328
|
+
},
|
|
329
|
+
"memory_types": {
|
|
330
|
+
"type": "array",
|
|
331
|
+
"items": {
|
|
332
|
+
"type": "string",
|
|
333
|
+
"enum": [t.value for t in MemoryType]
|
|
334
|
+
},
|
|
335
|
+
"description": "Filter by memory types"
|
|
336
|
+
},
|
|
337
|
+
"tags": {
|
|
338
|
+
"type": "array",
|
|
339
|
+
"items": {"type": "string"},
|
|
340
|
+
"description": "Filter by tags"
|
|
341
|
+
},
|
|
342
|
+
"project_path": {
|
|
343
|
+
"type": "string",
|
|
344
|
+
"description": "Filter by project path"
|
|
345
|
+
},
|
|
346
|
+
"min_importance": {
|
|
347
|
+
"type": "number",
|
|
348
|
+
"minimum": 0.0,
|
|
349
|
+
"maximum": 1.0,
|
|
350
|
+
"description": "Minimum importance score"
|
|
351
|
+
},
|
|
352
|
+
"limit": {
|
|
353
|
+
"type": "integer",
|
|
354
|
+
"minimum": 1,
|
|
355
|
+
"maximum": 1000,
|
|
356
|
+
"description": "Maximum number of results per page (default: 50)"
|
|
357
|
+
},
|
|
358
|
+
"offset": {
|
|
359
|
+
"type": "integer",
|
|
360
|
+
"minimum": 0,
|
|
361
|
+
"description": "Number of results to skip for pagination (default: 0)"
|
|
362
|
+
},
|
|
363
|
+
"search_tolerance": {
|
|
364
|
+
"type": "string",
|
|
365
|
+
"enum": ["strict", "normal", "fuzzy"],
|
|
366
|
+
"description": "Search tolerance mode: 'strict' for exact matches, 'normal' for stemming (default), 'fuzzy' for typo tolerance"
|
|
367
|
+
},
|
|
368
|
+
"match_mode": {
|
|
369
|
+
"type": "string",
|
|
370
|
+
"enum": ["any", "all"],
|
|
371
|
+
"description": "Match mode for terms: 'any' returns results matching ANY term (OR), 'all' requires ALL terms (AND)"
|
|
372
|
+
},
|
|
373
|
+
"relationship_filter": {
|
|
374
|
+
"type": "array",
|
|
375
|
+
"items": {"type": "string"},
|
|
376
|
+
"description": "Filter results to only include memories with these relationship types"
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
),
|
|
381
|
+
Tool(
|
|
382
|
+
name="update_memory",
|
|
383
|
+
description="Update an existing memory",
|
|
384
|
+
inputSchema={
|
|
385
|
+
"type": "object",
|
|
386
|
+
"properties": {
|
|
387
|
+
"memory_id": {
|
|
388
|
+
"type": "string",
|
|
389
|
+
"description": "ID of the memory to update"
|
|
390
|
+
},
|
|
391
|
+
"title": {"type": "string"},
|
|
392
|
+
"content": {"type": "string"},
|
|
393
|
+
"summary": {"type": "string"},
|
|
394
|
+
"tags": {
|
|
395
|
+
"type": "array",
|
|
396
|
+
"items": {"type": "string"}
|
|
397
|
+
},
|
|
398
|
+
"importance": {
|
|
399
|
+
"type": "number",
|
|
400
|
+
"minimum": 0.0,
|
|
401
|
+
"maximum": 1.0
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
"required": ["memory_id"]
|
|
405
|
+
}
|
|
406
|
+
),
|
|
407
|
+
Tool(
|
|
408
|
+
name="delete_memory",
|
|
409
|
+
description="Delete a memory and all its relationships",
|
|
410
|
+
inputSchema={
|
|
411
|
+
"type": "object",
|
|
412
|
+
"properties": {
|
|
413
|
+
"memory_id": {
|
|
414
|
+
"type": "string",
|
|
415
|
+
"description": "ID of the memory to delete"
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
"required": ["memory_id"]
|
|
419
|
+
}
|
|
420
|
+
),
|
|
421
|
+
Tool(
|
|
422
|
+
name="create_relationship",
|
|
423
|
+
description="""Create a relationship between two memories to capture how they connect.
|
|
424
|
+
|
|
425
|
+
WHEN TO USE:
|
|
426
|
+
- After storing a solution, link it to the problem it solves
|
|
427
|
+
- Connect an error to its fix
|
|
428
|
+
- Link a decision to what it improves or replaces
|
|
429
|
+
- Associate patterns with where they apply
|
|
430
|
+
- Track what causes what (e.g., error TRIGGERS problem)
|
|
431
|
+
- Document what requires what (dependencies)
|
|
432
|
+
|
|
433
|
+
HOW TO USE:
|
|
434
|
+
- Get memory IDs from store_memory or search_memories
|
|
435
|
+
- Choose appropriate relationship type:
|
|
436
|
+
• SOLVES: solution → problem/error
|
|
437
|
+
• CAUSES/TRIGGERS: cause → effect
|
|
438
|
+
• FIXES/ADDRESSES: fix → error/problem
|
|
439
|
+
• IMPROVES/REPLACES: new approach → old approach
|
|
440
|
+
• REQUIRES/DEPENDS_ON: dependent → dependency
|
|
441
|
+
• USED_IN/APPLIES_TO: pattern → project/context
|
|
442
|
+
• RELATED_TO: general association
|
|
443
|
+
- Optional: Add natural language context (auto-extracted into structured format)
|
|
444
|
+
- Optional: Set strength (defaults to 0.5) and confidence (defaults to 0.8)
|
|
445
|
+
|
|
446
|
+
EXAMPLES:
|
|
447
|
+
- Link solution to problem: create_relationship(from_memory_id="sol-123", to_memory_id="prob-456", relationship_type="SOLVES")
|
|
448
|
+
- Document cause: create_relationship(from_memory_id="config-error", to_memory_id="timeout-problem", relationship_type="CAUSES", context="Missing Redis timeout config causes connection timeouts in production")
|
|
449
|
+
- Track dependency: create_relationship(from_memory_id="auth-module", to_memory_id="jwt-library", relationship_type="REQUIRES")
|
|
450
|
+
- Pattern usage: create_relationship(from_memory_id="retry-pattern", to_memory_id="api-integration", relationship_type="APPLIES_TO")
|
|
451
|
+
|
|
452
|
+
WHY IT MATTERS:
|
|
453
|
+
- Relationships enable "What solved X?" queries
|
|
454
|
+
- Builds knowledge graph for pattern recognition
|
|
455
|
+
- Context is automatically structured for advanced queries""",
|
|
456
|
+
inputSchema={
|
|
457
|
+
"type": "object",
|
|
458
|
+
"properties": {
|
|
459
|
+
"from_memory_id": {
|
|
460
|
+
"type": "string",
|
|
461
|
+
"description": "ID of the source memory"
|
|
462
|
+
},
|
|
463
|
+
"to_memory_id": {
|
|
464
|
+
"type": "string",
|
|
465
|
+
"description": "ID of the target memory"
|
|
466
|
+
},
|
|
467
|
+
"relationship_type": {
|
|
468
|
+
"type": "string",
|
|
469
|
+
"enum": [t.value for t in RelationshipType],
|
|
470
|
+
"description": "Type of relationship to create"
|
|
471
|
+
},
|
|
472
|
+
"strength": {
|
|
473
|
+
"type": "number",
|
|
474
|
+
"minimum": 0.0,
|
|
475
|
+
"maximum": 1.0,
|
|
476
|
+
"description": "Strength of the relationship (0.0-1.0)"
|
|
477
|
+
},
|
|
478
|
+
"confidence": {
|
|
479
|
+
"type": "number",
|
|
480
|
+
"minimum": 0.0,
|
|
481
|
+
"maximum": 1.0,
|
|
482
|
+
"description": "Confidence in the relationship (0.0-1.0)"
|
|
483
|
+
},
|
|
484
|
+
"context": {
|
|
485
|
+
"type": "string",
|
|
486
|
+
"description": "Context or description of the relationship"
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
"required": ["from_memory_id", "to_memory_id", "relationship_type"]
|
|
490
|
+
}
|
|
491
|
+
),
|
|
492
|
+
Tool(
|
|
493
|
+
name="get_related_memories",
|
|
494
|
+
description="""Find memories related to a specific memory by traversing relationships.
|
|
495
|
+
|
|
496
|
+
WHEN TO USE:
|
|
497
|
+
- After finding a memory, explore what connects to it
|
|
498
|
+
- User asks "What caused this?" or "What solves this?"
|
|
499
|
+
- Understanding the context around a specific memory
|
|
500
|
+
- Following chains of reasoning (what led to what)
|
|
501
|
+
- Finding all solutions for a problem
|
|
502
|
+
|
|
503
|
+
HOW TO USE:
|
|
504
|
+
- Pass memory_id from search_memories or get_memory
|
|
505
|
+
- Filter by relationship_types to focus query:
|
|
506
|
+
• ["SOLVES"] → Find all solutions for a problem
|
|
507
|
+
• ["CAUSES", "TRIGGERS"] → Find what causes this
|
|
508
|
+
• ["USED_IN", "APPLIES_TO"] → Find where a pattern applies
|
|
509
|
+
- Set max_depth to control traversal:
|
|
510
|
+
• 1 = immediate connections only (default)
|
|
511
|
+
• 2 = connections of connections
|
|
512
|
+
• 3+ = deeper traversal (rarely needed)
|
|
513
|
+
|
|
514
|
+
EXAMPLES:
|
|
515
|
+
- Find solutions: get_related_memories(memory_id="problem-123", relationship_types=["SOLVES"], max_depth=1)
|
|
516
|
+
- Explore context: get_related_memories(memory_id="decision-456", max_depth=2)
|
|
517
|
+
- Find causes: get_related_memories(memory_id="error-789", relationship_types=["CAUSES", "TRIGGERS"])
|
|
518
|
+
|
|
519
|
+
RETURNS:
|
|
520
|
+
- List of related memories with relationship types and strengths""",
|
|
521
|
+
inputSchema={
|
|
522
|
+
"type": "object",
|
|
523
|
+
"properties": {
|
|
524
|
+
"memory_id": {
|
|
525
|
+
"type": "string",
|
|
526
|
+
"description": "ID of the memory to find relations for"
|
|
527
|
+
},
|
|
528
|
+
"relationship_types": {
|
|
529
|
+
"type": "array",
|
|
530
|
+
"items": {
|
|
531
|
+
"type": "string",
|
|
532
|
+
"enum": [t.value for t in RelationshipType]
|
|
533
|
+
},
|
|
534
|
+
"description": "Filter by relationship types"
|
|
535
|
+
},
|
|
536
|
+
"max_depth": {
|
|
537
|
+
"type": "integer",
|
|
538
|
+
"minimum": 1,
|
|
539
|
+
"maximum": 5,
|
|
540
|
+
"description": "Maximum relationship depth to traverse"
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
"required": ["memory_id"]
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
Tool(
|
|
547
|
+
name="get_memory_statistics",
|
|
548
|
+
description="Get statistics about the memory database",
|
|
549
|
+
inputSchema={
|
|
550
|
+
"type": "object",
|
|
551
|
+
"properties": {}
|
|
552
|
+
}
|
|
553
|
+
),
|
|
554
|
+
Tool(
|
|
555
|
+
name="get_recent_activity",
|
|
556
|
+
description="""Get a summary of recent memory activity for session briefing.
|
|
557
|
+
|
|
558
|
+
WHEN TO USE:
|
|
559
|
+
- User asks "What have we been working on?"
|
|
560
|
+
- User asks "Catch me up" or "What's the status?"
|
|
561
|
+
- Starting a new session and want context
|
|
562
|
+
- Need to understand recent progress
|
|
563
|
+
|
|
564
|
+
HOW TO USE:
|
|
565
|
+
- Specify days (default: 7) to control timeframe
|
|
566
|
+
- Optionally filter by project to scope to current work
|
|
567
|
+
- Returns summary by type, recent memories, and unresolved problems
|
|
568
|
+
|
|
569
|
+
WHAT YOU GET:
|
|
570
|
+
- Count of memories by type (solutions, problems, etc.)
|
|
571
|
+
- List of recent memories (up to 20)
|
|
572
|
+
- Unresolved problems (problems with no solution yet)
|
|
573
|
+
- Time range and filters applied
|
|
574
|
+
|
|
575
|
+
EXAMPLES:
|
|
576
|
+
- User: "What have we been working on?" → get_recent_activity(days=7)
|
|
577
|
+
- User: "Catch me up on this project" → get_recent_activity(days=7, project="/current/project")
|
|
578
|
+
- User: "What happened last month?" → get_recent_activity(days=30)
|
|
579
|
+
- User: "Any unsolved problems?" → get_recent_activity(days=30) // check unresolved_problems
|
|
580
|
+
|
|
581
|
+
WHY IT MATTERS:
|
|
582
|
+
- Provides quick context at session start
|
|
583
|
+
- Identifies work that needs attention (unresolved problems)
|
|
584
|
+
- Shows progress and activity patterns""",
|
|
585
|
+
inputSchema={
|
|
586
|
+
"type": "object",
|
|
587
|
+
"properties": {
|
|
588
|
+
"days": {
|
|
589
|
+
"type": "integer",
|
|
590
|
+
"minimum": 1,
|
|
591
|
+
"maximum": 365,
|
|
592
|
+
"description": "Number of days to look back (default: 7)"
|
|
593
|
+
},
|
|
594
|
+
"project": {
|
|
595
|
+
"type": "string",
|
|
596
|
+
"description": "Optional: Filter by project path"
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
),
|
|
601
|
+
Tool(
|
|
602
|
+
name="search_relationships_by_context",
|
|
603
|
+
description="Search relationships by their structured context fields (scope, conditions, evidence, components)",
|
|
604
|
+
inputSchema={
|
|
605
|
+
"type": "object",
|
|
606
|
+
"properties": {
|
|
607
|
+
"scope": {
|
|
608
|
+
"type": "string",
|
|
609
|
+
"enum": ["partial", "full", "conditional"],
|
|
610
|
+
"description": "Filter by scope (partial, full, or conditional implementation)"
|
|
611
|
+
},
|
|
612
|
+
"conditions": {
|
|
613
|
+
"type": "array",
|
|
614
|
+
"items": {"type": "string"},
|
|
615
|
+
"description": "Filter by conditions (e.g., ['production', 'Redis enabled']). Matches any."
|
|
616
|
+
},
|
|
617
|
+
"has_evidence": {
|
|
618
|
+
"type": "boolean",
|
|
619
|
+
"description": "Filter by presence/absence of evidence (verified by tests, etc.)"
|
|
620
|
+
},
|
|
621
|
+
"evidence": {
|
|
622
|
+
"type": "array",
|
|
623
|
+
"items": {"type": "string"},
|
|
624
|
+
"description": "Filter by specific evidence types (e.g., ['integration tests', 'unit tests']). Matches any."
|
|
625
|
+
},
|
|
626
|
+
"components": {
|
|
627
|
+
"type": "array",
|
|
628
|
+
"items": {"type": "string"},
|
|
629
|
+
"description": "Filter by components mentioned (e.g., ['auth', 'Redis']). Matches any."
|
|
630
|
+
},
|
|
631
|
+
"temporal": {
|
|
632
|
+
"type": "string",
|
|
633
|
+
"description": "Filter by temporal information (e.g., 'v2.1.0', 'since 2024')"
|
|
634
|
+
},
|
|
635
|
+
"limit": {
|
|
636
|
+
"type": "integer",
|
|
637
|
+
"minimum": 1,
|
|
638
|
+
"maximum": 100,
|
|
639
|
+
"description": "Maximum number of results (default: 20)"
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
),
|
|
644
|
+
# Contextual search tool for semantic graph traversal
|
|
645
|
+
Tool(
|
|
646
|
+
name="contextual_search",
|
|
647
|
+
description="""Search only within the context of a given memory (scoped search).
|
|
648
|
+
|
|
649
|
+
Two-phase process: (1) Find related memories, (2) Search only within that set.
|
|
650
|
+
Provides semantic scoping without embeddings.
|
|
651
|
+
|
|
652
|
+
WHEN TO USE:
|
|
653
|
+
- Searching within a specific problem context
|
|
654
|
+
- Finding solutions in related knowledge
|
|
655
|
+
- Scoped discovery
|
|
656
|
+
|
|
657
|
+
HOW TO USE:
|
|
658
|
+
- Specify memory_id (context root)
|
|
659
|
+
- Provide query (search term)
|
|
660
|
+
- Optional: max_depth (default: 2)
|
|
661
|
+
|
|
662
|
+
RETURNS:
|
|
663
|
+
- Matches found only within related memories
|
|
664
|
+
- Context information
|
|
665
|
+
- No leakage outside context""",
|
|
666
|
+
inputSchema={
|
|
667
|
+
"type": "object",
|
|
668
|
+
"properties": {
|
|
669
|
+
"memory_id": {
|
|
670
|
+
"type": "string",
|
|
671
|
+
"description": "Memory ID to use as context root (required)"
|
|
672
|
+
},
|
|
673
|
+
"query": {
|
|
674
|
+
"type": "string",
|
|
675
|
+
"description": "Search query within context (required)"
|
|
676
|
+
},
|
|
677
|
+
"max_depth": {
|
|
678
|
+
"type": "integer",
|
|
679
|
+
"minimum": 1,
|
|
680
|
+
"maximum": 5,
|
|
681
|
+
"description": "Maximum relationship traversal depth (default: 2)"
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
"required": ["memory_id", "query"]
|
|
685
|
+
}
|
|
686
|
+
),
|
|
687
|
+
# Temporal tools deferred per ADR-017 (Context Budget Constraint)
|
|
688
|
+
# Backend methods available via Python API:
|
|
689
|
+
# - query_as_of, get_relationship_history, what_changed
|
|
690
|
+
# MCP tool registration deferred until usage data justifies context cost
|
|
691
|
+
]
|
|
692
|
+
|
|
693
|
+
# Combine all tools from all modules
|
|
694
|
+
all_tools = (
|
|
695
|
+
basic_tools +
|
|
696
|
+
ADVANCED_RELATIONSHIP_TOOLS +
|
|
697
|
+
MIGRATION_TOOLS
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
return all_tools
|
|
701
|
+
|
|
702
|
+
def _register_handlers(self):
|
|
703
|
+
"""Register MCP protocol handlers."""
|
|
704
|
+
|
|
705
|
+
@self.server.list_tools()
|
|
706
|
+
async def handle_list_tools() -> ListToolsResult:
|
|
707
|
+
"""List available tools."""
|
|
708
|
+
return ListToolsResult(tools=self.tools)
|
|
709
|
+
|
|
710
|
+
@self.server.call_tool()
|
|
711
|
+
async def handle_call_tool(name: str, arguments: dict) -> CallToolResult:
|
|
712
|
+
"""Handle tool calls."""
|
|
713
|
+
try:
|
|
714
|
+
if not self.memory_db:
|
|
715
|
+
return CallToolResult(
|
|
716
|
+
content=[TextContent(
|
|
717
|
+
type="text",
|
|
718
|
+
text="Error: Memory database not initialized"
|
|
719
|
+
)],
|
|
720
|
+
isError=True
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
if name == "recall_memories":
|
|
724
|
+
return await handle_recall_memories(self.memory_db, arguments)
|
|
725
|
+
elif name == "store_memory":
|
|
726
|
+
return await handle_store_memory(self.memory_db, arguments)
|
|
727
|
+
elif name == "get_memory":
|
|
728
|
+
return await handle_get_memory(self.memory_db, arguments)
|
|
729
|
+
elif name == "search_memories":
|
|
730
|
+
return await handle_search_memories(self.memory_db, arguments)
|
|
731
|
+
elif name == "update_memory":
|
|
732
|
+
return await handle_update_memory(self.memory_db, arguments)
|
|
733
|
+
elif name == "delete_memory":
|
|
734
|
+
return await handle_delete_memory(self.memory_db, arguments)
|
|
735
|
+
elif name == "create_relationship":
|
|
736
|
+
return await handle_create_relationship(self.memory_db, arguments)
|
|
737
|
+
elif name == "get_related_memories":
|
|
738
|
+
return await handle_get_related_memories(self.memory_db, arguments)
|
|
739
|
+
elif name == "get_memory_statistics":
|
|
740
|
+
return await handle_get_memory_statistics(self.memory_db, arguments)
|
|
741
|
+
elif name == "get_recent_activity":
|
|
742
|
+
return await handle_get_recent_activity(self.memory_db, arguments)
|
|
743
|
+
elif name == "search_relationships_by_context":
|
|
744
|
+
return await handle_search_relationships_by_context(self.memory_db, arguments)
|
|
745
|
+
# Contextual search tool
|
|
746
|
+
elif name == "contextual_search":
|
|
747
|
+
return await handle_contextual_search(self.memory_db, arguments)
|
|
748
|
+
# Temporal tools deferred (backend methods available via Python API)
|
|
749
|
+
# Advanced relationship tools
|
|
750
|
+
elif name in ["find_memory_path", "analyze_memory_clusters", "find_bridge_memories",
|
|
751
|
+
"suggest_relationship_type", "reinforce_relationship",
|
|
752
|
+
"get_relationship_types_by_category", "analyze_graph_metrics"]:
|
|
753
|
+
# Dispatch to advanced handlers
|
|
754
|
+
method_name = f"handle_{name}"
|
|
755
|
+
handler = getattr(self.advanced_handlers, method_name, None)
|
|
756
|
+
if handler:
|
|
757
|
+
return await handler(arguments)
|
|
758
|
+
else:
|
|
759
|
+
return CallToolResult(
|
|
760
|
+
content=[TextContent(type="text", text=f"Handler not found: {name}")],
|
|
761
|
+
isError=True
|
|
762
|
+
)
|
|
763
|
+
|
|
764
|
+
# Migration tools
|
|
765
|
+
elif name in ["migrate_database", "validate_migration"]:
|
|
766
|
+
handler = MIGRATION_TOOL_HANDLERS.get(name)
|
|
767
|
+
if handler:
|
|
768
|
+
# Migration tools don't need memory_db parameter - they create their own connections
|
|
769
|
+
result = await handler(**arguments)
|
|
770
|
+
# Format result as MCP response
|
|
771
|
+
import json
|
|
772
|
+
return CallToolResult(
|
|
773
|
+
content=[TextContent(
|
|
774
|
+
type="text",
|
|
775
|
+
text=json.dumps(result, indent=2)
|
|
776
|
+
)],
|
|
777
|
+
isError=not result.get("success", False)
|
|
778
|
+
)
|
|
779
|
+
else:
|
|
780
|
+
return CallToolResult(
|
|
781
|
+
content=[TextContent(type="text", text=f"Migration handler not found: {name}")],
|
|
782
|
+
isError=True
|
|
783
|
+
)
|
|
784
|
+
|
|
785
|
+
else:
|
|
786
|
+
return CallToolResult(
|
|
787
|
+
content=[TextContent(
|
|
788
|
+
type="text",
|
|
789
|
+
text=f"Unknown tool: {name}"
|
|
790
|
+
)],
|
|
791
|
+
isError=True
|
|
792
|
+
)
|
|
793
|
+
|
|
794
|
+
except Exception as e:
|
|
795
|
+
logger.error(f"Error handling tool call {name}: {e}")
|
|
796
|
+
return CallToolResult(
|
|
797
|
+
content=[TextContent(
|
|
798
|
+
type="text",
|
|
799
|
+
text=f"Error: {str(e)}"
|
|
800
|
+
)],
|
|
801
|
+
isError=True
|
|
802
|
+
)
|
|
803
|
+
|
|
804
|
+
async def initialize(self):
|
|
805
|
+
"""Initialize the server and establish database connection."""
|
|
806
|
+
try:
|
|
807
|
+
# Initialize backend connection using factory
|
|
808
|
+
from .backends.factory import BackendFactory
|
|
809
|
+
self.db_connection = await BackendFactory.create_backend()
|
|
810
|
+
|
|
811
|
+
# Initialize memory database - choose wrapper based on backend type
|
|
812
|
+
if isinstance(self.db_connection, SQLiteFallbackBackend):
|
|
813
|
+
logger.info("Using SQLiteMemoryDatabase for SQLite backend")
|
|
814
|
+
self.memory_db = SQLiteMemoryDatabase(self.db_connection)
|
|
815
|
+
elif isinstance(self.db_connection, CloudBackend):
|
|
816
|
+
logger.info("Using CloudMemoryDatabase for Cloud backend")
|
|
817
|
+
self.memory_db = CloudMemoryDatabase(self.db_connection)
|
|
818
|
+
else:
|
|
819
|
+
logger.info("Using MemoryDatabase for Cypher-compatible backend")
|
|
820
|
+
self.memory_db = MemoryDatabase(self.db_connection)
|
|
821
|
+
|
|
822
|
+
await self.memory_db.initialize_schema()
|
|
823
|
+
|
|
824
|
+
# Initialize advanced relationship handlers
|
|
825
|
+
self.advanced_handlers = AdvancedRelationshipHandlers(self.memory_db)
|
|
826
|
+
|
|
827
|
+
backend_name = getattr(self.db_connection, 'backend_name', lambda: 'Unknown')
|
|
828
|
+
if callable(backend_name):
|
|
829
|
+
backend_name = backend_name()
|
|
830
|
+
logger.info(f"Claude Memory Server initialized successfully")
|
|
831
|
+
logger.info(f"Backend: {backend_name}")
|
|
832
|
+
logger.info(f"Tool profile: {Config.TOOL_PROFILE.upper()} ({len(self.tools)} tools enabled)")
|
|
833
|
+
|
|
834
|
+
except Exception as e:
|
|
835
|
+
logger.error(f"Failed to initialize server: {e}")
|
|
836
|
+
raise
|
|
837
|
+
|
|
838
|
+
async def cleanup(self):
|
|
839
|
+
"""Clean up resources."""
|
|
840
|
+
if self.db_connection:
|
|
841
|
+
await self.db_connection.close()
|
|
842
|
+
logger.info("Claude Memory Server cleanup completed")
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
async def main():
|
|
846
|
+
"""Main entry point for the MCP server."""
|
|
847
|
+
server = ClaudeMemoryServer()
|
|
848
|
+
|
|
849
|
+
try:
|
|
850
|
+
# Initialize the server
|
|
851
|
+
await server.initialize()
|
|
852
|
+
|
|
853
|
+
# Create notification options and capabilities BEFORE passing to InitializationOptions
|
|
854
|
+
# This ensures proper object instantiation and avoids potential GC or scoping issues
|
|
855
|
+
notification_options = NotificationOptions()
|
|
856
|
+
capabilities = server.server.get_capabilities(
|
|
857
|
+
notification_options=notification_options,
|
|
858
|
+
experimental_capabilities={},
|
|
859
|
+
)
|
|
860
|
+
|
|
861
|
+
# Run the stdio server
|
|
862
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
863
|
+
await server.server.run(
|
|
864
|
+
read_stream,
|
|
865
|
+
write_stream,
|
|
866
|
+
InitializationOptions(
|
|
867
|
+
server_name="claude-memory",
|
|
868
|
+
server_version=__version__,
|
|
869
|
+
capabilities=capabilities,
|
|
870
|
+
),
|
|
871
|
+
)
|
|
872
|
+
|
|
873
|
+
except KeyboardInterrupt:
|
|
874
|
+
logger.info("Received interrupt signal")
|
|
875
|
+
except Exception as e:
|
|
876
|
+
logger.error(f"Server error: {e}")
|
|
877
|
+
raise
|
|
878
|
+
finally:
|
|
879
|
+
await server.cleanup()
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
if __name__ == "__main__":
|
|
883
|
+
asyncio.run(main())
|