claude-memory-agent 2.0.1 → 2.2.0
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.
- package/README.md +206 -206
- package/agent_card.py +186 -0
- package/bin/cli.js +327 -185
- package/bin/lib/banner.js +39 -0
- package/bin/lib/environment.js +166 -0
- package/bin/lib/installer.js +291 -0
- package/bin/lib/models.js +95 -0
- package/bin/lib/steps/advanced.js +101 -0
- package/bin/lib/steps/confirm.js +87 -0
- package/bin/lib/steps/model.js +57 -0
- package/bin/lib/steps/provider.js +65 -0
- package/bin/lib/steps/scope.js +59 -0
- package/bin/lib/steps/server.js +74 -0
- package/bin/lib/ui.js +75 -0
- package/bin/onboarding.js +164 -0
- package/bin/postinstall.js +35 -270
- package/config.py +103 -4
- package/dashboard.html +4902 -2689
- package/hooks/extract_memories.py +439 -0
- package/hooks/grounding-hook.py +422 -348
- package/hooks/pre_compact_hook.py +76 -0
- package/hooks/session_end.py +293 -192
- package/hooks/session_end_hook.py +149 -0
- package/hooks/session_start.py +227 -227
- package/hooks/stop_hook.py +372 -0
- package/install.py +972 -902
- package/main.py +5240 -2859
- package/mcp_server.py +451 -0
- package/package.json +58 -47
- package/requirements.txt +12 -8
- package/services/__init__.py +50 -50
- package/services/adaptive_ranker.py +272 -0
- package/services/agent_catalog.json +153 -0
- package/services/agent_registry.py +245 -730
- package/services/claude_md_sync.py +320 -4
- package/services/consolidation.py +417 -0
- package/services/curator.py +1606 -0
- package/services/database.py +4118 -2485
- package/services/embedding_pipeline.py +262 -0
- package/services/embeddings.py +493 -85
- package/services/memory_decay.py +408 -0
- package/services/native_memory_paths.py +86 -0
- package/services/native_memory_sync.py +496 -0
- package/services/response_manager.py +183 -0
- package/services/terminal_ui.py +199 -0
- package/services/tier_manager.py +235 -0
- package/services/websocket.py +26 -6
- package/skills/__init__.py +21 -1
- package/skills/confidence_tracker.py +441 -0
- package/skills/context.py +675 -0
- package/skills/curator.py +348 -0
- package/skills/search.py +444 -213
- package/skills/session_review.py +605 -0
- package/skills/store.py +484 -179
- package/terminal_dashboard.py +474 -0
- package/update_system.py +829 -817
- package/hooks/__pycache__/auto-detect-response.cpython-312.pyc +0 -0
- package/hooks/__pycache__/auto_capture.cpython-312.pyc +0 -0
- package/hooks/__pycache__/session_end.cpython-312.pyc +0 -0
- package/hooks/__pycache__/session_start.cpython-312.pyc +0 -0
- package/services/__pycache__/__init__.cpython-312.pyc +0 -0
- package/services/__pycache__/agent_registry.cpython-312.pyc +0 -0
- package/services/__pycache__/auth.cpython-312.pyc +0 -0
- package/services/__pycache__/auto_inject.cpython-312.pyc +0 -0
- package/services/__pycache__/claude_md_sync.cpython-312.pyc +0 -0
- package/services/__pycache__/cleanup.cpython-312.pyc +0 -0
- package/services/__pycache__/compaction_flush.cpython-312.pyc +0 -0
- package/services/__pycache__/confidence.cpython-312.pyc +0 -0
- package/services/__pycache__/daily_log.cpython-312.pyc +0 -0
- package/services/__pycache__/database.cpython-312.pyc +0 -0
- package/services/__pycache__/embeddings.cpython-312.pyc +0 -0
- package/services/__pycache__/insights.cpython-312.pyc +0 -0
- package/services/__pycache__/llm_analyzer.cpython-312.pyc +0 -0
- package/services/__pycache__/memory_md_sync.cpython-312.pyc +0 -0
- package/services/__pycache__/retry_queue.cpython-312.pyc +0 -0
- package/services/__pycache__/timeline.cpython-312.pyc +0 -0
- package/services/__pycache__/vector_index.cpython-312.pyc +0 -0
- package/services/__pycache__/websocket.cpython-312.pyc +0 -0
- package/skills/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/__pycache__/admin.cpython-312.pyc +0 -0
- package/skills/__pycache__/checkpoint.cpython-312.pyc +0 -0
- package/skills/__pycache__/claude_md.cpython-312.pyc +0 -0
- package/skills/__pycache__/cleanup.cpython-312.pyc +0 -0
- package/skills/__pycache__/grounding.cpython-312.pyc +0 -0
- package/skills/__pycache__/insights.cpython-312.pyc +0 -0
- package/skills/__pycache__/natural_language.cpython-312.pyc +0 -0
- package/skills/__pycache__/retrieve.cpython-312.pyc +0 -0
- package/skills/__pycache__/search.cpython-312.pyc +0 -0
- package/skills/__pycache__/state.cpython-312.pyc +0 -0
- package/skills/__pycache__/store.cpython-312.pyc +0 -0
- package/skills/__pycache__/summarize.cpython-312.pyc +0 -0
- package/skills/__pycache__/timeline.cpython-312.pyc +0 -0
- package/skills/__pycache__/verification.cpython-312.pyc +0 -0
- package/test_automation.py +0 -221
- package/test_complete.py +0 -338
- package/test_full.py +0 -322
- package/verify_db.py +0 -134
package/mcp_server.py
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
"""MCP stdio server for Claude Memory.
|
|
2
|
+
|
|
3
|
+
Thin adapter that exposes the memory system's core skills as MCP tools,
|
|
4
|
+
allowing any MCP-compatible client (OpenClaw, Claude Code, etc.) to
|
|
5
|
+
store, search, and manage memories over stdio JSON-RPC.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
python mcp_server.py # stdio mode (default)
|
|
9
|
+
mcp dev mcp_server.py # interactive inspector
|
|
10
|
+
|
|
11
|
+
Shares the same SQLite database as the HTTP server (main.py) via WAL mode.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
# ── CRITICAL: Suppress stdout noise before ANY library imports ──────────
|
|
15
|
+
# stdout is reserved exclusively for MCP JSON-RPC protocol messages.
|
|
16
|
+
# Any stray print/progress-bar on stdout will corrupt the protocol.
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
|
|
22
|
+
os.environ.setdefault("TRANSFORMERS_NO_ADVISORY_WARNINGS", "1")
|
|
23
|
+
os.environ.setdefault("TQDM_DISABLE", "1")
|
|
24
|
+
os.environ.setdefault("HF_HUB_DISABLE_PROGRESS_BARS", "1")
|
|
25
|
+
|
|
26
|
+
import logging
|
|
27
|
+
|
|
28
|
+
logging.basicConfig(
|
|
29
|
+
stream=sys.stderr,
|
|
30
|
+
level=logging.INFO,
|
|
31
|
+
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
|
|
32
|
+
)
|
|
33
|
+
logger = logging.getLogger("mcp-claude-memory")
|
|
34
|
+
|
|
35
|
+
# Add memory-agent/ to sys.path so local imports (services.*, skills.*, config) resolve
|
|
36
|
+
AGENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
37
|
+
if AGENT_DIR not in sys.path:
|
|
38
|
+
sys.path.insert(0, AGENT_DIR)
|
|
39
|
+
|
|
40
|
+
# ── Imports ─────────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
import json
|
|
43
|
+
from collections.abc import AsyncIterator
|
|
44
|
+
from contextlib import asynccontextmanager
|
|
45
|
+
from dataclasses import dataclass
|
|
46
|
+
from typing import Optional, List, Dict, Any
|
|
47
|
+
|
|
48
|
+
# MCP SDK - support both v1 (FastMCP) and v2 (MCPServer) import paths
|
|
49
|
+
try:
|
|
50
|
+
from mcp.server.fastmcp import FastMCP, Context
|
|
51
|
+
except ImportError:
|
|
52
|
+
try:
|
|
53
|
+
from mcp.server.mcpserver import MCPServer as FastMCP, Context
|
|
54
|
+
except ImportError:
|
|
55
|
+
raise ImportError(
|
|
56
|
+
"MCP SDK not found. Install with: pip install 'mcp>=1.0.0'"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
from services.database import DatabaseService
|
|
60
|
+
from services.embeddings import EmbeddingService
|
|
61
|
+
from config import config
|
|
62
|
+
|
|
63
|
+
# Direct skill imports - no HTTP, no FastAPI dependency
|
|
64
|
+
from skills.store import store_memory, store_project, store_pattern
|
|
65
|
+
from skills.search import semantic_search, search_patterns, get_project_context
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# ── Lifespan: DB + Embeddings initialization ───────────────────────────
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class AppContext:
|
|
72
|
+
db: DatabaseService
|
|
73
|
+
embeddings: EmbeddingService
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@asynccontextmanager
|
|
77
|
+
async def app_lifespan(server: Any) -> AsyncIterator[AppContext]:
|
|
78
|
+
"""Initialize database and embedding services on startup, clean up on shutdown."""
|
|
79
|
+
logger.info("Initializing Claude Memory MCP server...")
|
|
80
|
+
|
|
81
|
+
db = DatabaseService()
|
|
82
|
+
await db.connect()
|
|
83
|
+
await db.initialize_schema()
|
|
84
|
+
logger.info(f"Database connected: {db.db_path}")
|
|
85
|
+
|
|
86
|
+
logger.info(
|
|
87
|
+
f"Loading embedding model: {config.EMBEDDING_MODEL} "
|
|
88
|
+
f"(provider: {config.EMBEDDING_PROVIDER}) - this may take a moment..."
|
|
89
|
+
)
|
|
90
|
+
embeddings = EmbeddingService(
|
|
91
|
+
provider_type=config.EMBEDDING_PROVIDER,
|
|
92
|
+
model=config.EMBEDDING_MODEL,
|
|
93
|
+
)
|
|
94
|
+
logger.info(f"Embeddings ready (dim={embeddings.get_dimension()})")
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
yield AppContext(db=db, embeddings=embeddings)
|
|
98
|
+
finally:
|
|
99
|
+
if db.conn:
|
|
100
|
+
db.conn.close()
|
|
101
|
+
logger.info("Claude Memory MCP server shut down.")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# ── MCP Server ──────────────────────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
mcp_server = FastMCP("claude-memory", lifespan=app_lifespan)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _get_app(ctx: Context) -> AppContext:
|
|
110
|
+
"""Extract AppContext from the MCP request context."""
|
|
111
|
+
return ctx.request_context.lifespan_context
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# ── Tools ───────────────────────────────────────────────────────────────
|
|
115
|
+
|
|
116
|
+
@mcp_server.tool()
|
|
117
|
+
async def memory_store(
|
|
118
|
+
ctx: Context,
|
|
119
|
+
content: str,
|
|
120
|
+
memory_type: str = "chunk",
|
|
121
|
+
tags: Optional[List[str]] = None,
|
|
122
|
+
importance: int = 5,
|
|
123
|
+
outcome: Optional[str] = None,
|
|
124
|
+
success: Optional[bool] = None,
|
|
125
|
+
project_path: Optional[str] = None,
|
|
126
|
+
project_name: Optional[str] = None,
|
|
127
|
+
project_type: Optional[str] = None,
|
|
128
|
+
tech_stack: Optional[List[str]] = None,
|
|
129
|
+
agent_type: Optional[str] = None,
|
|
130
|
+
) -> str:
|
|
131
|
+
"""Store a memory with semantic embedding.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
content: Content to remember
|
|
135
|
+
memory_type: Type: session, decision, code, chunk, error, preference
|
|
136
|
+
tags: Classification tags
|
|
137
|
+
importance: 1-10 importance scale (default 5)
|
|
138
|
+
outcome: What happened
|
|
139
|
+
success: Did it work?
|
|
140
|
+
project_path: Project path
|
|
141
|
+
project_name: Project name
|
|
142
|
+
project_type: Project type (wordpress, react, etc.)
|
|
143
|
+
tech_stack: Technologies used
|
|
144
|
+
agent_type: Agent used (Explore, Plan, etc.)
|
|
145
|
+
"""
|
|
146
|
+
app = _get_app(ctx)
|
|
147
|
+
result = await store_memory(
|
|
148
|
+
db=app.db,
|
|
149
|
+
embeddings=app.embeddings,
|
|
150
|
+
content=content,
|
|
151
|
+
memory_type=memory_type,
|
|
152
|
+
tags=tags,
|
|
153
|
+
importance=importance,
|
|
154
|
+
outcome=outcome,
|
|
155
|
+
success=success,
|
|
156
|
+
project_path=project_path,
|
|
157
|
+
project_name=project_name,
|
|
158
|
+
project_type=project_type,
|
|
159
|
+
tech_stack=tech_stack,
|
|
160
|
+
agent_type=agent_type,
|
|
161
|
+
)
|
|
162
|
+
return json.dumps(result, default=str)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@mcp_server.tool()
|
|
166
|
+
async def memory_search(
|
|
167
|
+
ctx: Context,
|
|
168
|
+
query: str,
|
|
169
|
+
limit: int = 10,
|
|
170
|
+
memory_type: Optional[str] = None,
|
|
171
|
+
project_path: Optional[str] = None,
|
|
172
|
+
success_only: bool = False,
|
|
173
|
+
threshold: float = 0.5,
|
|
174
|
+
) -> str:
|
|
175
|
+
"""Search memories using natural language. Returns similar content ranked by relevance.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
query: Search query
|
|
179
|
+
limit: Max results (default 10)
|
|
180
|
+
memory_type: Filter: session, decision, code, chunk, error, preference
|
|
181
|
+
project_path: Filter by project
|
|
182
|
+
success_only: Only return successful memories
|
|
183
|
+
threshold: Minimum similarity 0-1 (default 0.5)
|
|
184
|
+
"""
|
|
185
|
+
app = _get_app(ctx)
|
|
186
|
+
result = await semantic_search(
|
|
187
|
+
db=app.db,
|
|
188
|
+
embeddings=app.embeddings,
|
|
189
|
+
query=query,
|
|
190
|
+
limit=limit,
|
|
191
|
+
memory_type=memory_type,
|
|
192
|
+
project_path=project_path,
|
|
193
|
+
success_only=success_only,
|
|
194
|
+
threshold=threshold,
|
|
195
|
+
)
|
|
196
|
+
return json.dumps(result, default=str)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@mcp_server.tool()
|
|
200
|
+
async def memory_search_patterns(
|
|
201
|
+
ctx: Context,
|
|
202
|
+
query: str,
|
|
203
|
+
limit: int = 5,
|
|
204
|
+
problem_type: Optional[str] = None,
|
|
205
|
+
threshold: float = 0.5,
|
|
206
|
+
) -> str:
|
|
207
|
+
"""Search for reusable solution patterns, ranked by similarity and success rate.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
query: Problem description
|
|
211
|
+
limit: Max results (default 5)
|
|
212
|
+
problem_type: Filter: bug_fix, feature, refactor, config, performance
|
|
213
|
+
threshold: Minimum similarity 0-1 (default 0.5)
|
|
214
|
+
"""
|
|
215
|
+
app = _get_app(ctx)
|
|
216
|
+
result = await search_patterns(
|
|
217
|
+
db=app.db,
|
|
218
|
+
embeddings=app.embeddings,
|
|
219
|
+
query=query,
|
|
220
|
+
limit=limit,
|
|
221
|
+
problem_type=problem_type,
|
|
222
|
+
threshold=threshold,
|
|
223
|
+
)
|
|
224
|
+
return json.dumps(result, default=str)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@mcp_server.tool()
|
|
228
|
+
async def memory_store_pattern(
|
|
229
|
+
ctx: Context,
|
|
230
|
+
name: str,
|
|
231
|
+
solution: str,
|
|
232
|
+
problem_type: Optional[str] = None,
|
|
233
|
+
tech_context: Optional[List[str]] = None,
|
|
234
|
+
) -> str:
|
|
235
|
+
"""Store a reusable solution pattern for future reference.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
name: Pattern name
|
|
239
|
+
solution: The solution
|
|
240
|
+
problem_type: Type: bug_fix, feature, refactor, config, performance
|
|
241
|
+
tech_context: Technologies this applies to
|
|
242
|
+
"""
|
|
243
|
+
app = _get_app(ctx)
|
|
244
|
+
result = await store_pattern(
|
|
245
|
+
db=app.db,
|
|
246
|
+
embeddings=app.embeddings,
|
|
247
|
+
name=name,
|
|
248
|
+
solution=solution,
|
|
249
|
+
problem_type=problem_type,
|
|
250
|
+
tech_context=tech_context,
|
|
251
|
+
)
|
|
252
|
+
return json.dumps(result, default=str)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
@mcp_server.tool()
|
|
256
|
+
async def memory_store_project(
|
|
257
|
+
ctx: Context,
|
|
258
|
+
path: str,
|
|
259
|
+
name: Optional[str] = None,
|
|
260
|
+
project_type: Optional[str] = None,
|
|
261
|
+
tech_stack: Optional[List[str]] = None,
|
|
262
|
+
conventions: Optional[Dict[str, Any]] = None,
|
|
263
|
+
preferences: Optional[Dict[str, Any]] = None,
|
|
264
|
+
) -> str:
|
|
265
|
+
"""Store project info (tech stack, conventions, preferences).
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
path: Project path
|
|
269
|
+
name: Project name
|
|
270
|
+
project_type: Project type
|
|
271
|
+
tech_stack: Technologies used
|
|
272
|
+
conventions: Coding conventions dict
|
|
273
|
+
preferences: User preferences dict
|
|
274
|
+
"""
|
|
275
|
+
app = _get_app(ctx)
|
|
276
|
+
result = await store_project(
|
|
277
|
+
db=app.db,
|
|
278
|
+
path=path,
|
|
279
|
+
name=name,
|
|
280
|
+
project_type=project_type,
|
|
281
|
+
tech_stack=tech_stack,
|
|
282
|
+
conventions=conventions,
|
|
283
|
+
preferences=preferences,
|
|
284
|
+
)
|
|
285
|
+
return json.dumps(result, default=str)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
@mcp_server.tool()
|
|
289
|
+
async def memory_get_project(
|
|
290
|
+
ctx: Context,
|
|
291
|
+
project_path: str,
|
|
292
|
+
) -> str:
|
|
293
|
+
"""Get stored info about a project.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
project_path: Project path to look up
|
|
297
|
+
"""
|
|
298
|
+
app = _get_app(ctx)
|
|
299
|
+
result = await app.db.get_project(project_path)
|
|
300
|
+
if result is None:
|
|
301
|
+
return json.dumps({"found": False, "project_path": project_path})
|
|
302
|
+
return json.dumps(result, default=str)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@mcp_server.tool()
|
|
306
|
+
async def memory_context(
|
|
307
|
+
ctx: Context,
|
|
308
|
+
project_path: Optional[str] = None,
|
|
309
|
+
query: Optional[str] = None,
|
|
310
|
+
include_decisions: bool = True,
|
|
311
|
+
include_errors: bool = True,
|
|
312
|
+
include_patterns: bool = True,
|
|
313
|
+
) -> str:
|
|
314
|
+
"""Load relevant memories for the current session. Call at session start to get
|
|
315
|
+
project info, recent decisions, patterns, and relevant past errors/solutions.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
project_path: Project path (optional, filters results)
|
|
319
|
+
query: Optional semantic query to find relevant memories
|
|
320
|
+
include_decisions: Include recent decisions (default true)
|
|
321
|
+
include_errors: Include recent errors (default true)
|
|
322
|
+
include_patterns: Include solution patterns (default true)
|
|
323
|
+
"""
|
|
324
|
+
app = _get_app(ctx)
|
|
325
|
+
result: Dict[str, Any] = {}
|
|
326
|
+
|
|
327
|
+
# Project context (includes decisions, code patterns, and query-relevant memories)
|
|
328
|
+
if project_path:
|
|
329
|
+
project_ctx = await get_project_context(
|
|
330
|
+
db=app.db,
|
|
331
|
+
embeddings=app.embeddings,
|
|
332
|
+
project_path=project_path,
|
|
333
|
+
query=query,
|
|
334
|
+
)
|
|
335
|
+
result["project"] = project_ctx
|
|
336
|
+
|
|
337
|
+
# Solution patterns (when a query is provided)
|
|
338
|
+
if include_patterns and query:
|
|
339
|
+
patterns = await search_patterns(
|
|
340
|
+
db=app.db,
|
|
341
|
+
embeddings=app.embeddings,
|
|
342
|
+
query=query,
|
|
343
|
+
limit=5,
|
|
344
|
+
)
|
|
345
|
+
result["patterns"] = patterns
|
|
346
|
+
|
|
347
|
+
# Recent errors (when requested and query provided)
|
|
348
|
+
if include_errors and query:
|
|
349
|
+
errors = await semantic_search(
|
|
350
|
+
db=app.db,
|
|
351
|
+
embeddings=app.embeddings,
|
|
352
|
+
query=query,
|
|
353
|
+
limit=5,
|
|
354
|
+
memory_type="error",
|
|
355
|
+
project_path=project_path,
|
|
356
|
+
)
|
|
357
|
+
result["recent_errors"] = errors
|
|
358
|
+
|
|
359
|
+
# Stats
|
|
360
|
+
try:
|
|
361
|
+
stats = await app.db.get_stats()
|
|
362
|
+
result["stats"] = stats
|
|
363
|
+
except Exception as e:
|
|
364
|
+
result["stats_error"] = str(e)
|
|
365
|
+
|
|
366
|
+
result["success"] = True
|
|
367
|
+
return json.dumps(result, default=str)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@mcp_server.tool()
|
|
371
|
+
async def memory_stats(ctx: Context) -> str:
|
|
372
|
+
"""Get memory statistics including total memories, database size, and breakdown by type."""
|
|
373
|
+
app = _get_app(ctx)
|
|
374
|
+
result = await app.db.get_stats()
|
|
375
|
+
return json.dumps(result, default=str)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
@mcp_server.tool()
|
|
379
|
+
async def memory_dashboard(ctx: Context) -> str:
|
|
380
|
+
"""Open the Claude Memory real-time dashboard in the browser."""
|
|
381
|
+
import webbrowser
|
|
382
|
+
|
|
383
|
+
url = config.get_dashboard_url()
|
|
384
|
+
try:
|
|
385
|
+
webbrowser.open(url)
|
|
386
|
+
return json.dumps({
|
|
387
|
+
"success": True,
|
|
388
|
+
"url": url,
|
|
389
|
+
"message": f"Dashboard opened at {url}",
|
|
390
|
+
})
|
|
391
|
+
except Exception as e:
|
|
392
|
+
return json.dumps({
|
|
393
|
+
"success": False,
|
|
394
|
+
"url": url,
|
|
395
|
+
"error": str(e),
|
|
396
|
+
"message": f"Could not auto-open browser. Visit {url} manually.",
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
@mcp_server.tool()
|
|
401
|
+
async def memory_sync_native(
|
|
402
|
+
ctx: Context,
|
|
403
|
+
project_path: Optional[str] = None,
|
|
404
|
+
direction: str = "both",
|
|
405
|
+
) -> str:
|
|
406
|
+
"""Sync between MCP DB and Claude's native MEMORY.md.
|
|
407
|
+
|
|
408
|
+
Bridges the MCP vector memory DB with Claude Code's built-in auto memory
|
|
409
|
+
(~/.claude/projects/<slug>/memory/MEMORY.md).
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
project_path: Project path to sync. If omitted, syncs current project.
|
|
413
|
+
direction: 'to_native' (MCP->MEMORY.md), 'from_native' (MEMORY.md->MCP), or 'both'
|
|
414
|
+
"""
|
|
415
|
+
from services.native_memory_sync import (
|
|
416
|
+
sync_mcp_to_native,
|
|
417
|
+
sync_native_to_mcp,
|
|
418
|
+
sync_bidirectional,
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
app = _get_app(ctx)
|
|
422
|
+
|
|
423
|
+
if not project_path:
|
|
424
|
+
return json.dumps({
|
|
425
|
+
"success": False,
|
|
426
|
+
"error": "project_path is required for native memory sync",
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
try:
|
|
430
|
+
if direction == "to_native":
|
|
431
|
+
result = await sync_mcp_to_native(app.db, project_path)
|
|
432
|
+
elif direction == "from_native":
|
|
433
|
+
result = await sync_native_to_mcp(app.db, app.embeddings, project_path)
|
|
434
|
+
elif direction == "both":
|
|
435
|
+
result = await sync_bidirectional(app.db, app.embeddings, project_path)
|
|
436
|
+
else:
|
|
437
|
+
return json.dumps({
|
|
438
|
+
"success": False,
|
|
439
|
+
"error": f"Invalid direction '{direction}'. Use 'to_native', 'from_native', or 'both'.",
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
return json.dumps(result, default=str)
|
|
443
|
+
except Exception as e:
|
|
444
|
+
logger.error(f"memory_sync_native failed: {e}")
|
|
445
|
+
return json.dumps({"success": False, "error": str(e)})
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
# ── Entry Point ─────────────────────────────────────────────────────────
|
|
449
|
+
|
|
450
|
+
if __name__ == "__main__":
|
|
451
|
+
mcp_server.run(transport="stdio")
|
package/package.json
CHANGED
|
@@ -1,47 +1,58 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "claude-memory-agent",
|
|
3
|
-
"version": "2.0
|
|
4
|
-
"description": "Persistent semantic memory system for Claude Code sessions with anti-hallucination grounding",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"claude",
|
|
7
|
-
"claude-code",
|
|
8
|
-
"memory",
|
|
9
|
-
"ai",
|
|
10
|
-
"mcp",
|
|
11
|
-
"semantic-search",
|
|
12
|
-
"embeddings",
|
|
13
|
-
"ollama"
|
|
14
|
-
],
|
|
15
|
-
"author": "Claude Memory Agent Contributors",
|
|
16
|
-
"license": "MIT",
|
|
17
|
-
"bin": {
|
|
18
|
-
"claude-memory-agent": "./bin/cli.js",
|
|
19
|
-
"claude-memory": "./bin/cli.js"
|
|
20
|
-
},
|
|
21
|
-
"files": [
|
|
22
|
-
"bin/",
|
|
23
|
-
"services/",
|
|
24
|
-
"skills/",
|
|
25
|
-
"hooks/",
|
|
26
|
-
"*.py",
|
|
27
|
-
"*.md",
|
|
28
|
-
"*.txt",
|
|
29
|
-
"*.html",
|
|
30
|
-
".env.example"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-memory-agent",
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "Persistent semantic memory system for Claude Code sessions with anti-hallucination grounding",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"claude",
|
|
7
|
+
"claude-code",
|
|
8
|
+
"memory",
|
|
9
|
+
"ai",
|
|
10
|
+
"mcp",
|
|
11
|
+
"semantic-search",
|
|
12
|
+
"embeddings",
|
|
13
|
+
"ollama"
|
|
14
|
+
],
|
|
15
|
+
"author": "Claude Memory Agent Contributors",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"bin": {
|
|
18
|
+
"claude-memory-agent": "./bin/cli.js",
|
|
19
|
+
"claude-memory": "./bin/cli.js"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"bin/",
|
|
23
|
+
"services/",
|
|
24
|
+
"skills/",
|
|
25
|
+
"hooks/",
|
|
26
|
+
"*.py",
|
|
27
|
+
"*.md",
|
|
28
|
+
"*.txt",
|
|
29
|
+
"*.html",
|
|
30
|
+
".env.example",
|
|
31
|
+
"!**/__pycache__/",
|
|
32
|
+
"!**/*.pyc",
|
|
33
|
+
"!test_*.py",
|
|
34
|
+
"!verify_db.py"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"postinstall": "node bin/postinstall.js",
|
|
38
|
+
"start": "python main.py",
|
|
39
|
+
"install-agent": "python install.py --auto",
|
|
40
|
+
"test": "python -m pytest"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=16.0.0"
|
|
44
|
+
},
|
|
45
|
+
"os": [
|
|
46
|
+
"win32",
|
|
47
|
+
"darwin",
|
|
48
|
+
"linux"
|
|
49
|
+
],
|
|
50
|
+
"preferGlobal": true,
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@inquirer/prompts": "^7.10.1",
|
|
53
|
+
"boxen": "^5.1.2",
|
|
54
|
+
"chalk": "^4.1.2",
|
|
55
|
+
"gradient-string": "^2.0.2",
|
|
56
|
+
"ora": "^5.4.1"
|
|
57
|
+
}
|
|
58
|
+
}
|
package/requirements.txt
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
fastapi>=0.109.0
|
|
2
|
-
uvicorn>=0.27.0
|
|
3
|
-
ollama>=0.4.0
|
|
4
|
-
python-dotenv>=1.0.0
|
|
5
|
-
pydantic>=2.0.0
|
|
6
|
-
httpx>=0.27.0
|
|
7
|
-
numpy>=1.26.0
|
|
8
|
-
|
|
1
|
+
fastapi>=0.109.0,<1.0.0
|
|
2
|
+
uvicorn>=0.27.0,<1.0.0
|
|
3
|
+
ollama>=0.4.0,<1.0.0 # Optional: only needed for Ollama provider
|
|
4
|
+
python-dotenv>=1.0.0,<2.0.0
|
|
5
|
+
pydantic>=2.0.0,<3.0.0
|
|
6
|
+
httpx>=0.27.0,<1.0.0
|
|
7
|
+
numpy>=1.26.0,<3.0.0
|
|
8
|
+
torch>=2.0.0
|
|
9
|
+
sentence-transformers>=3.0.0,<4.0.0
|
|
10
|
+
faiss-cpu>=1.7.4,<2.0.0
|
|
11
|
+
rich>=13.0.0,<14.0.0
|
|
12
|
+
mcp>=1.0.0
|
package/services/__init__.py
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
from .database import DatabaseService
|
|
2
|
-
from .embeddings import EmbeddingService
|
|
3
|
-
|
|
4
|
-
# Moltbot-inspired transparency services
|
|
5
|
-
from .daily_log import (
|
|
6
|
-
append_entry as daily_log_append,
|
|
7
|
-
append_session_summary as daily_log_append_session,
|
|
8
|
-
load_recent_logs as daily_log_read,
|
|
9
|
-
get_today_highlights as daily_log_highlights,
|
|
10
|
-
list_logs as daily_log_list,
|
|
11
|
-
get_log_path
|
|
12
|
-
)
|
|
13
|
-
from .memory_md_sync import (
|
|
14
|
-
sync_to_memory_md,
|
|
15
|
-
read_memory_md,
|
|
16
|
-
add_fact as add_memory_md_fact,
|
|
17
|
-
get_memory_md_summary,
|
|
18
|
-
get_memory_md_path
|
|
19
|
-
)
|
|
20
|
-
from .compaction_flush import (
|
|
21
|
-
check_flush_needed,
|
|
22
|
-
execute_flush as pre_compaction_flush,
|
|
23
|
-
list_flushes,
|
|
24
|
-
read_flush,
|
|
25
|
-
get_flush_path
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
__all__ = [
|
|
29
|
-
"DatabaseService",
|
|
30
|
-
"EmbeddingService",
|
|
31
|
-
# Daily log
|
|
32
|
-
"daily_log_append",
|
|
33
|
-
"daily_log_append_session",
|
|
34
|
-
"daily_log_read",
|
|
35
|
-
"daily_log_highlights",
|
|
36
|
-
"daily_log_list",
|
|
37
|
-
"get_log_path",
|
|
38
|
-
# MEMORY.md
|
|
39
|
-
"sync_to_memory_md",
|
|
40
|
-
"read_memory_md",
|
|
41
|
-
"add_memory_md_fact",
|
|
42
|
-
"get_memory_md_summary",
|
|
43
|
-
"get_memory_md_path",
|
|
44
|
-
# Compaction flush
|
|
45
|
-
"check_flush_needed",
|
|
46
|
-
"pre_compaction_flush",
|
|
47
|
-
"list_flushes",
|
|
48
|
-
"read_flush",
|
|
49
|
-
"get_flush_path",
|
|
50
|
-
]
|
|
1
|
+
from .database import DatabaseService
|
|
2
|
+
from .embeddings import EmbeddingService
|
|
3
|
+
|
|
4
|
+
# Moltbot-inspired transparency services
|
|
5
|
+
from .daily_log import (
|
|
6
|
+
append_entry as daily_log_append,
|
|
7
|
+
append_session_summary as daily_log_append_session,
|
|
8
|
+
load_recent_logs as daily_log_read,
|
|
9
|
+
get_today_highlights as daily_log_highlights,
|
|
10
|
+
list_logs as daily_log_list,
|
|
11
|
+
get_log_path
|
|
12
|
+
)
|
|
13
|
+
from .memory_md_sync import (
|
|
14
|
+
sync_to_memory_md,
|
|
15
|
+
read_memory_md,
|
|
16
|
+
add_fact as add_memory_md_fact,
|
|
17
|
+
get_memory_md_summary,
|
|
18
|
+
get_memory_md_path
|
|
19
|
+
)
|
|
20
|
+
from .compaction_flush import (
|
|
21
|
+
check_flush_needed,
|
|
22
|
+
execute_flush as pre_compaction_flush,
|
|
23
|
+
list_flushes,
|
|
24
|
+
read_flush,
|
|
25
|
+
get_flush_path
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"DatabaseService",
|
|
30
|
+
"EmbeddingService",
|
|
31
|
+
# Daily log
|
|
32
|
+
"daily_log_append",
|
|
33
|
+
"daily_log_append_session",
|
|
34
|
+
"daily_log_read",
|
|
35
|
+
"daily_log_highlights",
|
|
36
|
+
"daily_log_list",
|
|
37
|
+
"get_log_path",
|
|
38
|
+
# MEMORY.md
|
|
39
|
+
"sync_to_memory_md",
|
|
40
|
+
"read_memory_md",
|
|
41
|
+
"add_memory_md_fact",
|
|
42
|
+
"get_memory_md_summary",
|
|
43
|
+
"get_memory_md_path",
|
|
44
|
+
# Compaction flush
|
|
45
|
+
"check_flush_needed",
|
|
46
|
+
"pre_compaction_flush",
|
|
47
|
+
"list_flushes",
|
|
48
|
+
"read_flush",
|
|
49
|
+
"get_flush_path",
|
|
50
|
+
]
|