@mnemoai/core 1.1.0 → 1.1.2

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 (220) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +7 -0
  4. package/dist/cli.js.map +7 -0
  5. package/dist/index.d.ts +136 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/{index.ts → dist/index.js} +537 -1333
  8. package/dist/index.js.map +7 -0
  9. package/dist/src/access-tracker.d.ts +97 -0
  10. package/dist/src/access-tracker.d.ts.map +1 -0
  11. package/dist/src/access-tracker.js +184 -0
  12. package/dist/src/access-tracker.js.map +7 -0
  13. package/dist/src/adapters/chroma.d.ts +31 -0
  14. package/dist/src/adapters/chroma.d.ts.map +1 -0
  15. package/{src/adapters/chroma.ts → dist/src/adapters/chroma.js} +45 -107
  16. package/dist/src/adapters/chroma.js.map +7 -0
  17. package/dist/src/adapters/lancedb.d.ts +29 -0
  18. package/dist/src/adapters/lancedb.d.ts.map +1 -0
  19. package/{src/adapters/lancedb.ts → dist/src/adapters/lancedb.js} +41 -109
  20. package/dist/src/adapters/lancedb.js.map +7 -0
  21. package/dist/src/adapters/pgvector.d.ts +33 -0
  22. package/dist/src/adapters/pgvector.d.ts.map +1 -0
  23. package/{src/adapters/pgvector.ts → dist/src/adapters/pgvector.js} +42 -104
  24. package/dist/src/adapters/pgvector.js.map +7 -0
  25. package/dist/src/adapters/qdrant.d.ts +34 -0
  26. package/dist/src/adapters/qdrant.d.ts.map +1 -0
  27. package/dist/src/adapters/qdrant.js +132 -0
  28. package/dist/src/adapters/qdrant.js.map +7 -0
  29. package/dist/src/adaptive-retrieval.d.ts +14 -0
  30. package/dist/src/adaptive-retrieval.d.ts.map +1 -0
  31. package/dist/src/adaptive-retrieval.js +52 -0
  32. package/dist/src/adaptive-retrieval.js.map +7 -0
  33. package/dist/src/audit-log.d.ts +56 -0
  34. package/dist/src/audit-log.d.ts.map +1 -0
  35. package/dist/src/audit-log.js +139 -0
  36. package/dist/src/audit-log.js.map +7 -0
  37. package/dist/src/chunker.d.ts +45 -0
  38. package/dist/src/chunker.d.ts.map +1 -0
  39. package/dist/src/chunker.js +157 -0
  40. package/dist/src/chunker.js.map +7 -0
  41. package/dist/src/config.d.ts +70 -0
  42. package/dist/src/config.d.ts.map +1 -0
  43. package/dist/src/config.js +142 -0
  44. package/dist/src/config.js.map +7 -0
  45. package/dist/src/decay-engine.d.ts +73 -0
  46. package/dist/src/decay-engine.d.ts.map +1 -0
  47. package/dist/src/decay-engine.js +119 -0
  48. package/dist/src/decay-engine.js.map +7 -0
  49. package/dist/src/embedder.d.ts +94 -0
  50. package/dist/src/embedder.d.ts.map +1 -0
  51. package/{src/embedder.ts → dist/src/embedder.js} +119 -317
  52. package/dist/src/embedder.js.map +7 -0
  53. package/dist/src/extraction-prompts.d.ts +12 -0
  54. package/dist/src/extraction-prompts.d.ts.map +1 -0
  55. package/dist/src/extraction-prompts.js +311 -0
  56. package/dist/src/extraction-prompts.js.map +7 -0
  57. package/dist/src/license.d.ts +29 -0
  58. package/dist/src/license.d.ts.map +1 -0
  59. package/{src/license.ts → dist/src/license.js} +42 -113
  60. package/dist/src/license.js.map +7 -0
  61. package/dist/src/llm-client.d.ts +23 -0
  62. package/dist/src/llm-client.d.ts.map +1 -0
  63. package/{src/llm-client.ts → dist/src/llm-client.js} +22 -55
  64. package/dist/src/llm-client.js.map +7 -0
  65. package/dist/src/logger.d.ts +33 -0
  66. package/dist/src/logger.d.ts.map +1 -0
  67. package/dist/src/logger.js +35 -0
  68. package/dist/src/logger.js.map +7 -0
  69. package/dist/src/mcp-server.d.ts +16 -0
  70. package/dist/src/mcp-server.d.ts.map +1 -0
  71. package/{src/mcp-server.ts → dist/src/mcp-server.js} +81 -181
  72. package/dist/src/mcp-server.js.map +7 -0
  73. package/dist/src/memory-categories.d.ts +40 -0
  74. package/dist/src/memory-categories.d.ts.map +1 -0
  75. package/dist/src/memory-categories.js +33 -0
  76. package/dist/src/memory-categories.js.map +7 -0
  77. package/dist/src/memory-upgrader.d.ts +71 -0
  78. package/dist/src/memory-upgrader.d.ts.map +1 -0
  79. package/dist/src/memory-upgrader.js +238 -0
  80. package/dist/src/memory-upgrader.js.map +7 -0
  81. package/dist/src/migrate.d.ts +47 -0
  82. package/dist/src/migrate.d.ts.map +1 -0
  83. package/{src/migrate.ts → dist/src/migrate.js} +57 -165
  84. package/dist/src/migrate.js.map +7 -0
  85. package/dist/src/mnemo.d.ts +67 -0
  86. package/dist/src/mnemo.d.ts.map +1 -0
  87. package/dist/src/mnemo.js +66 -0
  88. package/dist/src/mnemo.js.map +7 -0
  89. package/dist/src/noise-filter.d.ts +23 -0
  90. package/dist/src/noise-filter.d.ts.map +1 -0
  91. package/dist/src/noise-filter.js +62 -0
  92. package/dist/src/noise-filter.js.map +7 -0
  93. package/dist/src/noise-prototypes.d.ts +40 -0
  94. package/dist/src/noise-prototypes.d.ts.map +1 -0
  95. package/dist/src/noise-prototypes.js +116 -0
  96. package/dist/src/noise-prototypes.js.map +7 -0
  97. package/dist/src/observability.d.ts +16 -0
  98. package/dist/src/observability.d.ts.map +1 -0
  99. package/dist/src/observability.js +53 -0
  100. package/dist/src/observability.js.map +7 -0
  101. package/dist/src/query-tracker.d.ts +27 -0
  102. package/dist/src/query-tracker.d.ts.map +1 -0
  103. package/dist/src/query-tracker.js +32 -0
  104. package/dist/src/query-tracker.js.map +7 -0
  105. package/dist/src/reflection-event-store.d.ts +44 -0
  106. package/dist/src/reflection-event-store.d.ts.map +1 -0
  107. package/dist/src/reflection-event-store.js +50 -0
  108. package/dist/src/reflection-event-store.js.map +7 -0
  109. package/dist/src/reflection-item-store.d.ts +58 -0
  110. package/dist/src/reflection-item-store.d.ts.map +1 -0
  111. package/dist/src/reflection-item-store.js +69 -0
  112. package/dist/src/reflection-item-store.js.map +7 -0
  113. package/dist/src/reflection-mapped-metadata.d.ts +47 -0
  114. package/dist/src/reflection-mapped-metadata.d.ts.map +1 -0
  115. package/dist/src/reflection-mapped-metadata.js +40 -0
  116. package/dist/src/reflection-mapped-metadata.js.map +7 -0
  117. package/dist/src/reflection-metadata.d.ts +11 -0
  118. package/dist/src/reflection-metadata.d.ts.map +1 -0
  119. package/dist/src/reflection-metadata.js +24 -0
  120. package/dist/src/reflection-metadata.js.map +7 -0
  121. package/dist/src/reflection-ranking.d.ts +13 -0
  122. package/dist/src/reflection-ranking.d.ts.map +1 -0
  123. package/{src/reflection-ranking.ts → dist/src/reflection-ranking.js} +12 -21
  124. package/dist/src/reflection-ranking.js.map +7 -0
  125. package/dist/src/reflection-retry.d.ts +30 -0
  126. package/dist/src/reflection-retry.d.ts.map +1 -0
  127. package/{src/reflection-retry.ts → dist/src/reflection-retry.js} +24 -64
  128. package/dist/src/reflection-retry.js.map +7 -0
  129. package/dist/src/reflection-slices.d.ts +42 -0
  130. package/dist/src/reflection-slices.d.ts.map +1 -0
  131. package/{src/reflection-slices.ts → dist/src/reflection-slices.js} +60 -136
  132. package/dist/src/reflection-slices.js.map +7 -0
  133. package/dist/src/reflection-store.d.ts +85 -0
  134. package/dist/src/reflection-store.d.ts.map +1 -0
  135. package/dist/src/reflection-store.js +407 -0
  136. package/dist/src/reflection-store.js.map +7 -0
  137. package/dist/src/resonance-state.d.ts +19 -0
  138. package/dist/src/resonance-state.d.ts.map +1 -0
  139. package/{src/resonance-state.ts → dist/src/resonance-state.js} +13 -42
  140. package/dist/src/resonance-state.js.map +7 -0
  141. package/dist/src/retriever.d.ts +228 -0
  142. package/dist/src/retriever.d.ts.map +1 -0
  143. package/dist/src/retriever.js +1006 -0
  144. package/dist/src/retriever.js.map +7 -0
  145. package/dist/src/scopes.d.ts +58 -0
  146. package/dist/src/scopes.d.ts.map +1 -0
  147. package/dist/src/scopes.js +252 -0
  148. package/dist/src/scopes.js.map +7 -0
  149. package/dist/src/self-improvement-files.d.ts +20 -0
  150. package/dist/src/self-improvement-files.d.ts.map +1 -0
  151. package/{src/self-improvement-files.ts → dist/src/self-improvement-files.js} +24 -49
  152. package/dist/src/self-improvement-files.js.map +7 -0
  153. package/dist/src/semantic-gate.d.ts +24 -0
  154. package/dist/src/semantic-gate.d.ts.map +1 -0
  155. package/dist/src/semantic-gate.js +86 -0
  156. package/dist/src/semantic-gate.js.map +7 -0
  157. package/dist/src/session-recovery.d.ts +9 -0
  158. package/dist/src/session-recovery.d.ts.map +1 -0
  159. package/{src/session-recovery.ts → dist/src/session-recovery.js} +40 -57
  160. package/dist/src/session-recovery.js.map +7 -0
  161. package/dist/src/smart-extractor.d.ts +107 -0
  162. package/dist/src/smart-extractor.d.ts.map +1 -0
  163. package/{src/smart-extractor.ts → dist/src/smart-extractor.js} +130 -383
  164. package/dist/src/smart-extractor.js.map +7 -0
  165. package/dist/src/smart-metadata.d.ts +103 -0
  166. package/dist/src/smart-metadata.d.ts.map +1 -0
  167. package/dist/src/smart-metadata.js +361 -0
  168. package/dist/src/smart-metadata.js.map +7 -0
  169. package/dist/src/storage-adapter.d.ts +102 -0
  170. package/dist/src/storage-adapter.d.ts.map +1 -0
  171. package/dist/src/storage-adapter.js +22 -0
  172. package/dist/src/storage-adapter.js.map +7 -0
  173. package/dist/src/store.d.ts +108 -0
  174. package/dist/src/store.d.ts.map +1 -0
  175. package/dist/src/store.js +939 -0
  176. package/dist/src/store.js.map +7 -0
  177. package/dist/src/tier-manager.d.ts +57 -0
  178. package/dist/src/tier-manager.d.ts.map +1 -0
  179. package/dist/src/tier-manager.js +80 -0
  180. package/dist/src/tier-manager.js.map +7 -0
  181. package/dist/src/tools.d.ts +43 -0
  182. package/dist/src/tools.d.ts.map +1 -0
  183. package/dist/src/tools.js +1075 -0
  184. package/dist/src/tools.js.map +7 -0
  185. package/dist/src/wal-recovery.d.ts +30 -0
  186. package/dist/src/wal-recovery.d.ts.map +1 -0
  187. package/{src/wal-recovery.ts → dist/src/wal-recovery.js} +26 -79
  188. package/dist/src/wal-recovery.js.map +7 -0
  189. package/package.json +21 -2
  190. package/openclaw.plugin.json +0 -815
  191. package/src/access-tracker.ts +0 -341
  192. package/src/adapters/README.md +0 -78
  193. package/src/adapters/qdrant.ts +0 -191
  194. package/src/adaptive-retrieval.ts +0 -90
  195. package/src/audit-log.ts +0 -238
  196. package/src/chunker.ts +0 -254
  197. package/src/config.ts +0 -271
  198. package/src/decay-engine.ts +0 -238
  199. package/src/extraction-prompts.ts +0 -339
  200. package/src/memory-categories.ts +0 -71
  201. package/src/memory-upgrader.ts +0 -388
  202. package/src/mnemo.ts +0 -142
  203. package/src/noise-filter.ts +0 -97
  204. package/src/noise-prototypes.ts +0 -164
  205. package/src/observability.ts +0 -81
  206. package/src/query-tracker.ts +0 -57
  207. package/src/reflection-event-store.ts +0 -98
  208. package/src/reflection-item-store.ts +0 -112
  209. package/src/reflection-mapped-metadata.ts +0 -84
  210. package/src/reflection-metadata.ts +0 -23
  211. package/src/reflection-store.ts +0 -602
  212. package/src/retriever.ts +0 -1510
  213. package/src/scopes.ts +0 -375
  214. package/src/semantic-gate.ts +0 -121
  215. package/src/smart-metadata.ts +0 -561
  216. package/src/storage-adapter.ts +0 -153
  217. package/src/store.ts +0 -1330
  218. package/src/tier-manager.ts +0 -189
  219. package/src/tools.ts +0 -1292
  220. package/test/core.test.mjs +0 -301
@@ -1,29 +1,11 @@
1
- // SPDX-License-Identifier: LicenseRef-Mnemo-Pro
2
- /**
3
- * MCP Server for Mnemo
4
- *
5
- * Exposes memory tools (search, store, delete, update, list, stats) over
6
- * stdio JSON-RPC so Claude Code can call them directly without going through
7
- * the OpenClaw gateway.
8
- *
9
- * Usage:
10
- * node --import jiti/register src/mcp-server.ts
11
- *
12
- * Register with Claude Code:
13
- * claude mcp add memory -s user -- node --import jiti/register \
14
- * /path/to/mnemo/src/mcp-server.ts
15
- */
16
-
17
- // Redirect console.log to stderr — stdout is reserved for JSON-RPC
18
1
  const _origLog = console.log;
19
- console.log = (...args: any[]) => console.error(...args);
20
-
2
+ console.log = (...args) => console.error(...args);
21
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
22
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
23
5
  import { z } from "zod";
24
6
  import { join } from "node:path";
25
7
  import { mkdir, appendFile } from "node:fs/promises";
26
-
8
+ import { log } from "./logger.js";
27
9
  import { loadConfigFromOpenClaw, getDefaultDbPath } from "./config.js";
28
10
  import { MemoryStore, validateStoragePath } from "./store.js";
29
11
  import { createEmbedder, getVectorDimensions } from "./embedder.js";
@@ -32,25 +14,17 @@ import { createScopeManager } from "./scopes.js";
32
14
  import { isNoise } from "./noise-filter.js";
33
15
  import { SemanticGate } from "./semantic-gate.js";
34
16
  import { recoverPendingWrites } from "./wal-recovery.js";
35
-
36
- // ============================================================================
37
- // Initialization
38
- // ============================================================================
39
-
40
17
  const config = loadConfigFromOpenClaw();
41
-
42
18
  const dbPath = config.dbPath || getDefaultDbPath();
43
19
  try {
44
20
  validateStoragePath(dbPath);
45
21
  } catch (err) {
46
- console.error(`mnemo mcp: storage path issue ${String(err)}`);
22
+ log.error(`mnemo mcp: storage path issue \u2014 ${String(err)}`);
47
23
  }
48
-
49
24
  const vectorDim = getVectorDimensions(
50
25
  config.embedding.model || "text-embedding-3-small",
51
- config.embedding.dimensions,
26
+ config.embedding.dimensions
52
27
  );
53
-
54
28
  const store = new MemoryStore({ dbPath, vectorDim });
55
29
  const embedder = createEmbedder({
56
30
  provider: "openai-compatible",
@@ -60,77 +34,47 @@ const embedder = createEmbedder({
60
34
  dimensions: config.embedding.dimensions,
61
35
  taskQuery: config.embedding.taskQuery,
62
36
  taskPassage: config.embedding.taskPassage,
63
- normalized: config.embedding.normalized,
37
+ normalized: config.embedding.normalized
64
38
  });
65
- console.warn(`[config-debug] config.retrieval keys: ${JSON.stringify(Object.keys(config.retrieval || {}))}`);
66
- console.warn(`[config-debug] config.retrieval.rerankApiKey: ${config.retrieval?.rerankApiKey ? 'SET(' + String(config.retrieval.rerankApiKey).substring(0, 8) + ')' : 'EMPTY'}`);
39
+ log.warn(`[config-debug] config.retrieval keys: ${JSON.stringify(Object.keys(config.retrieval || {}))}`);
40
+ log.warn(`[config-debug] config.retrieval.rerankApiKey: ${config.retrieval?.rerankApiKey ? "SET(" + String(config.retrieval.rerankApiKey).substring(0, 8) + ")" : "EMPTY"}`);
67
41
  const retriever = createRetriever(store, embedder, {
68
42
  ...DEFAULT_RETRIEVAL_CONFIG,
69
- ...config.retrieval,
43
+ ...config.retrieval
70
44
  });
71
45
  const scopeManager = createScopeManager(config.scopes);
72
-
73
- // Inject semantic gate into store
74
46
  const semanticGate = new SemanticGate(embedder);
75
47
  store.setSemanticGate(semanticGate);
76
-
77
- // WAL recovery: fire-and-forget on startup
78
48
  recoverPendingWrites().catch((err) => {
79
- console.error(`mnemo mcp: WAL recovery failed ${String(err)}`);
49
+ log.error(`mnemo mcp: WAL recovery failed \u2014 ${String(err)}`);
80
50
  });
81
-
82
- // ============================================================================
83
- // Markdown Mirror (simplified — no OpenClaw API dependency)
84
- // ============================================================================
85
-
86
- const mirrorDir = config.mdMirror?.enabled
87
- ? (config.mdMirror.dir || join(getDefaultDbPath(), "..", "lancedb-pro-mirror"))
88
- : null;
89
-
90
- async function mirrorWrite(
91
- text: string,
92
- category: string,
93
- scope: string,
94
- timestamp?: number,
95
- ): Promise<void> {
51
+ const mirrorDir = config.mdMirror?.enabled ? config.mdMirror.dir || join(getDefaultDbPath(), "..", "lancedb-pro-mirror") : null;
52
+ async function mirrorWrite(text, category, scope, timestamp) {
96
53
  if (!mirrorDir) return;
97
54
  try {
98
55
  const ts = new Date(timestamp || Date.now());
99
56
  const dateStr = ts.toISOString().split("T")[0];
100
57
  const filePath = join(mirrorDir, `${dateStr}.md`);
101
58
  const safeText = text.replace(/\n/g, " ").slice(0, 500);
102
- const line = `- ${ts.toISOString()} [${category}:${scope}] source=mcp ${safeText}\n`;
59
+ const line = `- ${ts.toISOString()} [${category}:${scope}] source=mcp ${safeText}
60
+ `;
103
61
  await mkdir(mirrorDir, { recursive: true });
104
62
  await appendFile(filePath, line, "utf8");
105
63
  } catch {
106
- // Fail-open: mirror errors never block tool responses
107
64
  }
108
65
  }
109
-
110
- // ============================================================================
111
- // Helpers
112
- // ============================================================================
113
-
114
- function clampInt(value: number, min: number, max: number): number {
66
+ function clampInt(value, min, max) {
115
67
  if (!Number.isFinite(value)) return min;
116
68
  return Math.min(max, Math.max(min, Math.floor(value)));
117
69
  }
118
-
119
- function clamp01(value: number, fallback = 0.7): number {
70
+ function clamp01(value, fallback = 0.7) {
120
71
  if (!Number.isFinite(value)) return fallback;
121
72
  return Math.min(1, Math.max(0, value));
122
73
  }
123
-
124
- // ============================================================================
125
- // MCP Server
126
- // ============================================================================
127
-
128
74
  const server = new McpServer({
129
75
  name: "mnemo",
130
- version: "1.0.0",
76
+ version: "1.0.0"
131
77
  });
132
-
133
- // --- memory_search ---
134
78
  server.tool(
135
79
  "memory_search",
136
80
  "Search through long-term memories using hybrid retrieval (vector + keyword search). Use when you need context about user preferences, past decisions, or previously discussed topics.",
@@ -138,51 +82,44 @@ server.tool(
138
82
  query: z.string().describe("Search query for finding relevant memories"),
139
83
  limit: z.number().optional().describe("Max results to return (default: 5, max: 20)"),
140
84
  scope: z.string().optional().describe("Specific memory scope to search in"),
141
- category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional(),
85
+ category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional()
142
86
  },
143
87
  async ({ query, limit = 5, scope, category }) => {
144
88
  try {
145
89
  const safeLimit = clampInt(limit, 1, 20);
146
-
147
90
  let scopeFilter = scopeManager.getAccessibleScopes();
148
91
  if (scope) {
149
92
  if (scopeManager.isAccessible(scope)) {
150
93
  scopeFilter = [scope];
151
94
  } else {
152
- return { content: [{ type: "text" as const, text: `Access denied to scope: ${scope}` }] };
95
+ return { content: [{ type: "text", text: `Access denied to scope: ${scope}` }] };
153
96
  }
154
97
  }
155
-
156
98
  const results = await retriever.retrieve({
157
99
  query,
158
100
  limit: safeLimit,
159
101
  scopeFilter,
160
102
  category,
161
- source: "manual",
103
+ source: "manual"
162
104
  });
163
-
164
105
  if (results.length === 0) {
165
- return { content: [{ type: "text" as const, text: "No relevant memories found." }] };
106
+ return { content: [{ type: "text", text: "No relevant memories found." }] };
166
107
  }
167
-
168
- const text = results
169
- .map((r, i) => {
170
- const sources: string[] = [];
171
- if (r.sources.vector) sources.push("vector");
172
- if (r.sources.bm25) sources.push("BM25");
173
- if (r.sources.reranked) sources.push("reranked");
174
- return `${i + 1}. [${r.entry.id}] [${r.entry.category}:${r.entry.scope}] ${r.entry.text} (${(r.score * 100).toFixed(0)}%${sources.length > 0 ? `, ${sources.join("+")}` : ""})`;
175
- })
176
- .join("\n");
177
-
178
- return { content: [{ type: "text" as const, text: `Found ${results.length} memories:\n\n${text}` }] };
108
+ const text = results.map((r, i) => {
109
+ const sources = [];
110
+ if (r.sources.vector) sources.push("vector");
111
+ if (r.sources.bm25) sources.push("BM25");
112
+ if (r.sources.reranked) sources.push("reranked");
113
+ return `${i + 1}. [${r.entry.id}] [${r.entry.category}:${r.entry.scope}] ${r.entry.text} (${(r.score * 100).toFixed(0)}%${sources.length > 0 ? `, ${sources.join("+")}` : ""})`;
114
+ }).join("\n");
115
+ return { content: [{ type: "text", text: `Found ${results.length} memories:
116
+
117
+ ${text}` }] };
179
118
  } catch (error) {
180
- return { content: [{ type: "text" as const, text: `Memory search failed: ${error instanceof Error ? error.message : String(error)}` }] };
119
+ return { content: [{ type: "text", text: `Memory search failed: ${error instanceof Error ? error.message : String(error)}` }] };
181
120
  }
182
- },
121
+ }
183
122
  );
184
-
185
- // --- memory_store ---
186
123
  server.tool(
187
124
  "memory_store",
188
125
  "Save important information in long-term memory. Use for preferences, facts, decisions, and other notable information.",
@@ -190,78 +127,64 @@ server.tool(
190
127
  text: z.string().describe("Information to remember"),
191
128
  importance: z.number().optional().describe("Importance score 0-1 (default: 0.7)"),
192
129
  category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional(),
193
- scope: z.string().optional().describe("Memory scope (optional, defaults to global)"),
130
+ scope: z.string().optional().describe("Memory scope (optional, defaults to global)")
194
131
  },
195
132
  async ({ text, importance = 0.7, category = "other", scope }) => {
196
133
  try {
197
134
  let targetScope = scope || scopeManager.getDefaultScope();
198
-
199
135
  if (!scopeManager.isAccessible(targetScope)) {
200
- return { content: [{ type: "text" as const, text: `Access denied to scope: ${targetScope}` }] };
136
+ return { content: [{ type: "text", text: `Access denied to scope: ${targetScope}` }] };
201
137
  }
202
-
203
138
  if (isNoise(text)) {
204
- return { content: [{ type: "text" as const, text: "Skipped: text detected as noise (greeting, boilerplate, or meta-question)" }] };
139
+ return { content: [{ type: "text", text: "Skipped: text detected as noise (greeting, boilerplate, or meta-question)" }] };
205
140
  }
206
-
207
141
  const safeImportance = clamp01(importance, 0.7);
208
142
  const vector = await embedder.embedPassage(text);
209
-
210
- // Dedup check (fail-open)
211
- let existing: Awaited<ReturnType<typeof store.vectorSearch>> = [];
143
+ let existing = [];
212
144
  try {
213
145
  existing = await store.vectorSearch(vector, 1, 0.1, [targetScope]);
214
146
  } catch {
215
- // Dedup check failed — continue store
216
147
  }
217
-
218
148
  if (existing.length > 0 && existing[0].score > 0.98) {
219
149
  return {
220
- content: [{ type: "text" as const, text: `Similar memory already exists: "${existing[0].entry.text}"` }],
150
+ content: [{ type: "text", text: `Similar memory already exists: "${existing[0].entry.text}"` }]
221
151
  };
222
152
  }
223
-
224
153
  const entry = await store.store({
225
154
  text,
226
155
  vector,
227
156
  importance: safeImportance,
228
- category: category as any,
229
- scope: targetScope,
157
+ category,
158
+ scope: targetScope
230
159
  });
231
-
232
160
  await mirrorWrite(text, category, targetScope, entry.timestamp);
233
-
234
161
  return {
235
- content: [{ type: "text" as const, text: `Stored: "${text.slice(0, 100)}${text.length > 100 ? "..." : ""}" [id=${entry.id}] in scope '${targetScope}'` }],
162
+ content: [{ type: "text", text: `Stored: "${text.slice(0, 100)}${text.length > 100 ? "..." : ""}" [id=${entry.id}] in scope '${targetScope}'` }]
236
163
  };
237
164
  } catch (error) {
238
- return { content: [{ type: "text" as const, text: `Memory storage failed: ${error instanceof Error ? error.message : String(error)}` }] };
165
+ return { content: [{ type: "text", text: `Memory storage failed: ${error instanceof Error ? error.message : String(error)}` }] };
239
166
  }
240
- },
167
+ }
241
168
  );
242
-
243
- // --- memory_delete ---
244
169
  server.tool(
245
170
  "memory_delete",
246
171
  "Delete a specific memory by ID.",
247
172
  {
248
- memoryId: z.string().describe("Memory ID to delete (full UUID or 8+ char prefix)"),
173
+ memoryId: z.string().describe("Memory ID to delete (full UUID or 8+ char prefix)")
249
174
  },
250
175
  async ({ memoryId }) => {
251
176
  try {
252
177
  const scopeFilter = scopeManager.getAccessibleScopes();
253
178
  const deleted = await store.delete(memoryId, scopeFilter);
254
179
  if (deleted) {
255
- return { content: [{ type: "text" as const, text: `Memory ${memoryId} deleted.` }] };
180
+ return { content: [{ type: "text", text: `Memory ${memoryId} deleted.` }] };
256
181
  }
257
- return { content: [{ type: "text" as const, text: `Memory ${memoryId} not found or access denied.` }] };
182
+ return { content: [{ type: "text", text: `Memory ${memoryId} not found or access denied.` }] };
258
183
  } catch (error) {
259
- return { content: [{ type: "text" as const, text: `Memory deletion failed: ${error instanceof Error ? error.message : String(error)}` }] };
184
+ return { content: [{ type: "text", text: `Memory deletion failed: ${error instanceof Error ? error.message : String(error)}` }] };
260
185
  }
261
- },
186
+ }
262
187
  );
263
-
264
- // --- memory_update ---
265
188
  server.tool(
266
189
  "memory_update",
267
190
  "Update an existing memory in-place. Preserves original timestamp.",
@@ -269,46 +192,38 @@ server.tool(
269
192
  memoryId: z.string().describe("ID of the memory to update (full UUID or 8+ char prefix)"),
270
193
  text: z.string().optional().describe("New text content (triggers re-embedding)"),
271
194
  importance: z.number().optional().describe("New importance score 0-1"),
272
- category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional(),
195
+ category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional()
273
196
  },
274
197
  async ({ memoryId, text, importance, category }) => {
275
198
  try {
276
- if (!text && importance === undefined && !category) {
277
- return { content: [{ type: "text" as const, text: "Nothing to update. Provide at least one of: text, importance, category." }] };
199
+ if (!text && importance === void 0 && !category) {
200
+ return { content: [{ type: "text", text: "Nothing to update. Provide at least one of: text, importance, category." }] };
278
201
  }
279
-
280
202
  const scopeFilter = scopeManager.getAccessibleScopes();
281
-
282
- let newVector: number[] | undefined;
203
+ let newVector;
283
204
  if (text) {
284
205
  if (isNoise(text)) {
285
- return { content: [{ type: "text" as const, text: "Skipped: updated text detected as noise" }] };
206
+ return { content: [{ type: "text", text: "Skipped: updated text detected as noise" }] };
286
207
  }
287
208
  newVector = await embedder.embedPassage(text);
288
209
  }
289
-
290
- const updates: Record<string, any> = {};
210
+ const updates = {};
291
211
  if (text) updates.text = text;
292
212
  if (newVector) updates.vector = newVector;
293
- if (importance !== undefined) updates.importance = clamp01(importance, 0.7);
213
+ if (importance !== void 0) updates.importance = clamp01(importance, 0.7);
294
214
  if (category) updates.category = category;
295
-
296
215
  const updated = await store.update(memoryId, updates, scopeFilter);
297
-
298
216
  if (!updated) {
299
- return { content: [{ type: "text" as const, text: `Memory ${memoryId} not found or access denied.` }] };
217
+ return { content: [{ type: "text", text: `Memory ${memoryId} not found or access denied.` }] };
300
218
  }
301
-
302
219
  return {
303
- content: [{ type: "text" as const, text: `Updated memory ${updated.id.slice(0, 8)}...: "${updated.text.slice(0, 80)}${updated.text.length > 80 ? "..." : ""}"` }],
220
+ content: [{ type: "text", text: `Updated memory ${updated.id.slice(0, 8)}...: "${updated.text.slice(0, 80)}${updated.text.length > 80 ? "..." : ""}"` }]
304
221
  };
305
222
  } catch (error) {
306
- return { content: [{ type: "text" as const, text: `Memory update failed: ${error instanceof Error ? error.message : String(error)}` }] };
223
+ return { content: [{ type: "text", text: `Memory update failed: ${error instanceof Error ? error.message : String(error)}` }] };
307
224
  }
308
- },
225
+ }
309
226
  );
310
-
311
- // --- memory_list ---
312
227
  server.tool(
313
228
  "memory_list",
314
229
  "List recent memories with optional filtering by scope and category.",
@@ -316,48 +231,41 @@ server.tool(
316
231
  limit: z.number().optional().describe("Max memories to list (default: 10, max: 50)"),
317
232
  offset: z.number().optional().describe("Number of memories to skip (default: 0)"),
318
233
  scope: z.string().optional().describe("Filter by specific scope"),
319
- category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional(),
234
+ category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional()
320
235
  },
321
236
  async ({ limit = 10, offset = 0, scope, category }) => {
322
237
  try {
323
238
  const safeLimit = clampInt(limit, 1, 50);
324
- const safeOffset = clampInt(offset, 0, 1000);
325
-
239
+ const safeOffset = clampInt(offset, 0, 1e3);
326
240
  let scopeFilter = scopeManager.getAccessibleScopes();
327
241
  if (scope) {
328
242
  if (scopeManager.isAccessible(scope)) {
329
243
  scopeFilter = [scope];
330
244
  } else {
331
- return { content: [{ type: "text" as const, text: `Access denied to scope: ${scope}` }] };
245
+ return { content: [{ type: "text", text: `Access denied to scope: ${scope}` }] };
332
246
  }
333
247
  }
334
-
335
248
  const entries = await store.list(scopeFilter, category, safeLimit, safeOffset);
336
-
337
249
  if (entries.length === 0) {
338
- return { content: [{ type: "text" as const, text: "No memories found." }] };
250
+ return { content: [{ type: "text", text: "No memories found." }] };
339
251
  }
252
+ const text = entries.map((entry, i) => {
253
+ const date = new Date(entry.timestamp).toISOString().split("T")[0];
254
+ return `${safeOffset + i + 1}. [${entry.id}] [${entry.category}:${entry.scope}] ${entry.text.slice(0, 100)}${entry.text.length > 100 ? "..." : ""} (${date})`;
255
+ }).join("\n");
256
+ return { content: [{ type: "text", text: `Recent memories (showing ${entries.length}):
340
257
 
341
- const text = entries
342
- .map((entry, i) => {
343
- const date = new Date(entry.timestamp).toISOString().split("T")[0];
344
- return `${safeOffset + i + 1}. [${entry.id}] [${entry.category}:${entry.scope}] ${entry.text.slice(0, 100)}${entry.text.length > 100 ? "..." : ""} (${date})`;
345
- })
346
- .join("\n");
347
-
348
- return { content: [{ type: "text" as const, text: `Recent memories (showing ${entries.length}):\n\n${text}` }] };
258
+ ${text}` }] };
349
259
  } catch (error) {
350
- return { content: [{ type: "text" as const, text: `Failed to list memories: ${error instanceof Error ? error.message : String(error)}` }] };
260
+ return { content: [{ type: "text", text: `Failed to list memories: ${error instanceof Error ? error.message : String(error)}` }] };
351
261
  }
352
- },
262
+ }
353
263
  );
354
-
355
- // --- memory_stats ---
356
264
  server.tool(
357
265
  "memory_stats",
358
266
  "Get statistics about memory usage, scopes, and categories.",
359
267
  {
360
- scope: z.string().optional().describe("Specific scope to get stats for"),
268
+ scope: z.string().optional().describe("Specific scope to get stats for")
361
269
  },
362
270
  async ({ scope }) => {
363
271
  try {
@@ -366,14 +274,12 @@ server.tool(
366
274
  if (scopeManager.isAccessible(scope)) {
367
275
  scopeFilter = [scope];
368
276
  } else {
369
- return { content: [{ type: "text" as const, text: `Access denied to scope: ${scope}` }] };
277
+ return { content: [{ type: "text", text: `Access denied to scope: ${scope}` }] };
370
278
  }
371
279
  }
372
-
373
280
  const stats = await store.stats(scopeFilter);
374
281
  const scopeManagerStats = scopeManager.getStats();
375
282
  const retrievalConfig = retriever.getConfig();
376
-
377
283
  const text = [
378
284
  `Memory Statistics:`,
379
285
  ` Total memories: ${stats.totalCount}`,
@@ -383,33 +289,27 @@ server.tool(
383
289
  ``,
384
290
  `Memories by scope:`,
385
291
  ...Object.entries(stats.scopeCounts).map(
386
- ([s, count]) => ` ${s}: ${count}`,
292
+ ([s, count]) => ` ${s}: ${count}`
387
293
  ),
388
294
  ``,
389
295
  `Memories by category:`,
390
296
  ...Object.entries(stats.categoryCounts).map(
391
- ([c, count]) => ` ${c}: ${count}`,
392
- ),
297
+ ([c, count]) => ` ${c}: ${count}`
298
+ )
393
299
  ].join("\n");
394
-
395
- return { content: [{ type: "text" as const, text }] };
300
+ return { content: [{ type: "text", text }] };
396
301
  } catch (error) {
397
- return { content: [{ type: "text" as const, text: `Failed to get memory stats: ${error instanceof Error ? error.message : String(error)}` }] };
302
+ return { content: [{ type: "text", text: `Failed to get memory stats: ${error instanceof Error ? error.message : String(error)}` }] };
398
303
  }
399
- },
304
+ }
400
305
  );
401
-
402
- // ============================================================================
403
- // Start
404
- // ============================================================================
405
-
406
306
  async function main() {
407
307
  const transport = new StdioServerTransport();
408
308
  await server.connect(transport);
409
- console.error("mnemo MCP server started (stdio)");
309
+ log.error("mnemo MCP server started (stdio)");
410
310
  }
411
-
412
311
  main().catch((err) => {
413
- console.error("Fatal:", err);
312
+ log.error("Fatal:", err);
414
313
  process.exit(1);
415
314
  });
315
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/mcp-server.ts"],
4
+ "sourcesContent": ["// SPDX-License-Identifier: LicenseRef-Mnemo-Pro\n/**\n * MCP Server for Mnemo\n *\n * Exposes memory tools (search, store, delete, update, list, stats) over\n * stdio JSON-RPC so Claude Code can call them directly without going through\n * the OpenClaw gateway.\n *\n * Usage:\n * node --import jiti/register src/mcp-server.ts\n *\n * Register with Claude Code:\n * claude mcp add memory -s user -- node --import jiti/register \\\n * /path/to/mnemo/src/mcp-server.ts\n */\n\n// Redirect console.log to stderr \u2014 stdout is reserved for JSON-RPC\nconst _origLog = console.log;\nconsole.log = (...args: any[]) => console.error(...args);\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { join } from \"node:path\";\nimport { mkdir, appendFile } from \"node:fs/promises\";\n\nimport { log } from \"./logger.js\";\nimport { loadConfigFromOpenClaw, getDefaultDbPath } from \"./config.js\";\nimport { MemoryStore, validateStoragePath } from \"./store.js\";\nimport { createEmbedder, getVectorDimensions } from \"./embedder.js\";\nimport { createRetriever, DEFAULT_RETRIEVAL_CONFIG } from \"./retriever.js\";\nimport { createScopeManager } from \"./scopes.js\";\nimport { isNoise } from \"./noise-filter.js\";\nimport { SemanticGate } from \"./semantic-gate.js\";\nimport { recoverPendingWrites } from \"./wal-recovery.js\";\n\n// ============================================================================\n// Initialization\n// ============================================================================\n\nconst config = loadConfigFromOpenClaw();\n\nconst dbPath = config.dbPath || getDefaultDbPath();\ntry {\n validateStoragePath(dbPath);\n} catch (err) {\n log.error(`mnemo mcp: storage path issue \u2014 ${String(err)}`);\n}\n\nconst vectorDim = getVectorDimensions(\n config.embedding.model || \"text-embedding-3-small\",\n config.embedding.dimensions,\n);\n\nconst store = new MemoryStore({ dbPath, vectorDim });\nconst embedder = createEmbedder({\n provider: \"openai-compatible\",\n apiKey: config.embedding.apiKey,\n model: config.embedding.model || \"text-embedding-3-small\",\n baseURL: config.embedding.baseURL,\n dimensions: config.embedding.dimensions,\n taskQuery: config.embedding.taskQuery,\n taskPassage: config.embedding.taskPassage,\n normalized: config.embedding.normalized,\n});\nlog.warn(`[config-debug] config.retrieval keys: ${JSON.stringify(Object.keys(config.retrieval || {}))}`);\nlog.warn(`[config-debug] config.retrieval.rerankApiKey: ${config.retrieval?.rerankApiKey ? 'SET(' + String(config.retrieval.rerankApiKey).substring(0, 8) + ')' : 'EMPTY'}`);\nconst retriever = createRetriever(store, embedder, {\n ...DEFAULT_RETRIEVAL_CONFIG,\n ...config.retrieval,\n});\nconst scopeManager = createScopeManager(config.scopes);\n\n// Inject semantic gate into store\nconst semanticGate = new SemanticGate(embedder);\nstore.setSemanticGate(semanticGate);\n\n// WAL recovery: fire-and-forget on startup\nrecoverPendingWrites().catch((err) => {\n log.error(`mnemo mcp: WAL recovery failed \u2014 ${String(err)}`);\n});\n\n// ============================================================================\n// Markdown Mirror (simplified \u2014 no OpenClaw API dependency)\n// ============================================================================\n\nconst mirrorDir = config.mdMirror?.enabled\n ? (config.mdMirror.dir || join(getDefaultDbPath(), \"..\", \"lancedb-pro-mirror\"))\n : null;\n\nasync function mirrorWrite(\n text: string,\n category: string,\n scope: string,\n timestamp?: number,\n): Promise<void> {\n if (!mirrorDir) return;\n try {\n const ts = new Date(timestamp || Date.now());\n const dateStr = ts.toISOString().split(\"T\")[0];\n const filePath = join(mirrorDir, `${dateStr}.md`);\n const safeText = text.replace(/\\n/g, \" \").slice(0, 500);\n const line = `- ${ts.toISOString()} [${category}:${scope}] source=mcp ${safeText}\\n`;\n await mkdir(mirrorDir, { recursive: true });\n await appendFile(filePath, line, \"utf8\");\n } catch {\n // Fail-open: mirror errors never block tool responses\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction clampInt(value: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return min;\n return Math.min(max, Math.max(min, Math.floor(value)));\n}\n\nfunction clamp01(value: number, fallback = 0.7): number {\n if (!Number.isFinite(value)) return fallback;\n return Math.min(1, Math.max(0, value));\n}\n\n// ============================================================================\n// MCP Server\n// ============================================================================\n\nconst server = new McpServer({\n name: \"mnemo\",\n version: \"1.0.0\",\n});\n\n// --- memory_search ---\nserver.tool(\n \"memory_search\",\n \"Search through long-term memories using hybrid retrieval (vector + keyword search). Use when you need context about user preferences, past decisions, or previously discussed topics.\",\n {\n query: z.string().describe(\"Search query for finding relevant memories\"),\n limit: z.number().optional().describe(\"Max results to return (default: 5, max: 20)\"),\n scope: z.string().optional().describe(\"Specific memory scope to search in\"),\n category: z.enum([\"preference\", \"fact\", \"decision\", \"entity\", \"other\"]).optional(),\n },\n async ({ query, limit = 5, scope, category }) => {\n try {\n const safeLimit = clampInt(limit, 1, 20);\n\n let scopeFilter = scopeManager.getAccessibleScopes();\n if (scope) {\n if (scopeManager.isAccessible(scope)) {\n scopeFilter = [scope];\n } else {\n return { content: [{ type: \"text\" as const, text: `Access denied to scope: ${scope}` }] };\n }\n }\n\n const results = await retriever.retrieve({\n query,\n limit: safeLimit,\n scopeFilter,\n category,\n source: \"manual\",\n });\n\n if (results.length === 0) {\n return { content: [{ type: \"text\" as const, text: \"No relevant memories found.\" }] };\n }\n\n const text = results\n .map((r, i) => {\n const sources: string[] = [];\n if (r.sources.vector) sources.push(\"vector\");\n if (r.sources.bm25) sources.push(\"BM25\");\n if (r.sources.reranked) sources.push(\"reranked\");\n return `${i + 1}. [${r.entry.id}] [${r.entry.category}:${r.entry.scope}] ${r.entry.text} (${(r.score * 100).toFixed(0)}%${sources.length > 0 ? `, ${sources.join(\"+\")}` : \"\"})`;\n })\n .join(\"\\n\");\n\n return { content: [{ type: \"text\" as const, text: `Found ${results.length} memories:\\n\\n${text}` }] };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Memory search failed: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// --- memory_store ---\nserver.tool(\n \"memory_store\",\n \"Save important information in long-term memory. Use for preferences, facts, decisions, and other notable information.\",\n {\n text: z.string().describe(\"Information to remember\"),\n importance: z.number().optional().describe(\"Importance score 0-1 (default: 0.7)\"),\n category: z.enum([\"preference\", \"fact\", \"decision\", \"entity\", \"other\"]).optional(),\n scope: z.string().optional().describe(\"Memory scope (optional, defaults to global)\"),\n },\n async ({ text, importance = 0.7, category = \"other\", scope }) => {\n try {\n let targetScope = scope || scopeManager.getDefaultScope();\n\n if (!scopeManager.isAccessible(targetScope)) {\n return { content: [{ type: \"text\" as const, text: `Access denied to scope: ${targetScope}` }] };\n }\n\n if (isNoise(text)) {\n return { content: [{ type: \"text\" as const, text: \"Skipped: text detected as noise (greeting, boilerplate, or meta-question)\" }] };\n }\n\n const safeImportance = clamp01(importance, 0.7);\n const vector = await embedder.embedPassage(text);\n\n // Dedup check (fail-open)\n let existing: Awaited<ReturnType<typeof store.vectorSearch>> = [];\n try {\n existing = await store.vectorSearch(vector, 1, 0.1, [targetScope]);\n } catch {\n // Dedup check failed \u2014 continue store\n }\n\n if (existing.length > 0 && existing[0].score > 0.98) {\n return {\n content: [{ type: \"text\" as const, text: `Similar memory already exists: \"${existing[0].entry.text}\"` }],\n };\n }\n\n const entry = await store.store({\n text,\n vector,\n importance: safeImportance,\n category: category as any,\n scope: targetScope,\n });\n\n await mirrorWrite(text, category, targetScope, entry.timestamp);\n\n return {\n content: [{ type: \"text\" as const, text: `Stored: \"${text.slice(0, 100)}${text.length > 100 ? \"...\" : \"\"}\" [id=${entry.id}] in scope '${targetScope}'` }],\n };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Memory storage failed: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// --- memory_delete ---\nserver.tool(\n \"memory_delete\",\n \"Delete a specific memory by ID.\",\n {\n memoryId: z.string().describe(\"Memory ID to delete (full UUID or 8+ char prefix)\"),\n },\n async ({ memoryId }) => {\n try {\n const scopeFilter = scopeManager.getAccessibleScopes();\n const deleted = await store.delete(memoryId, scopeFilter);\n if (deleted) {\n return { content: [{ type: \"text\" as const, text: `Memory ${memoryId} deleted.` }] };\n }\n return { content: [{ type: \"text\" as const, text: `Memory ${memoryId} not found or access denied.` }] };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Memory deletion failed: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// --- memory_update ---\nserver.tool(\n \"memory_update\",\n \"Update an existing memory in-place. Preserves original timestamp.\",\n {\n memoryId: z.string().describe(\"ID of the memory to update (full UUID or 8+ char prefix)\"),\n text: z.string().optional().describe(\"New text content (triggers re-embedding)\"),\n importance: z.number().optional().describe(\"New importance score 0-1\"),\n category: z.enum([\"preference\", \"fact\", \"decision\", \"entity\", \"other\"]).optional(),\n },\n async ({ memoryId, text, importance, category }) => {\n try {\n if (!text && importance === undefined && !category) {\n return { content: [{ type: \"text\" as const, text: \"Nothing to update. Provide at least one of: text, importance, category.\" }] };\n }\n\n const scopeFilter = scopeManager.getAccessibleScopes();\n\n let newVector: number[] | undefined;\n if (text) {\n if (isNoise(text)) {\n return { content: [{ type: \"text\" as const, text: \"Skipped: updated text detected as noise\" }] };\n }\n newVector = await embedder.embedPassage(text);\n }\n\n const updates: Record<string, any> = {};\n if (text) updates.text = text;\n if (newVector) updates.vector = newVector;\n if (importance !== undefined) updates.importance = clamp01(importance, 0.7);\n if (category) updates.category = category;\n\n const updated = await store.update(memoryId, updates, scopeFilter);\n\n if (!updated) {\n return { content: [{ type: \"text\" as const, text: `Memory ${memoryId} not found or access denied.` }] };\n }\n\n return {\n content: [{ type: \"text\" as const, text: `Updated memory ${updated.id.slice(0, 8)}...: \"${updated.text.slice(0, 80)}${updated.text.length > 80 ? \"...\" : \"\"}\"` }],\n };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Memory update failed: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// --- memory_list ---\nserver.tool(\n \"memory_list\",\n \"List recent memories with optional filtering by scope and category.\",\n {\n limit: z.number().optional().describe(\"Max memories to list (default: 10, max: 50)\"),\n offset: z.number().optional().describe(\"Number of memories to skip (default: 0)\"),\n scope: z.string().optional().describe(\"Filter by specific scope\"),\n category: z.enum([\"preference\", \"fact\", \"decision\", \"entity\", \"other\"]).optional(),\n },\n async ({ limit = 10, offset = 0, scope, category }) => {\n try {\n const safeLimit = clampInt(limit, 1, 50);\n const safeOffset = clampInt(offset, 0, 1000);\n\n let scopeFilter = scopeManager.getAccessibleScopes();\n if (scope) {\n if (scopeManager.isAccessible(scope)) {\n scopeFilter = [scope];\n } else {\n return { content: [{ type: \"text\" as const, text: `Access denied to scope: ${scope}` }] };\n }\n }\n\n const entries = await store.list(scopeFilter, category, safeLimit, safeOffset);\n\n if (entries.length === 0) {\n return { content: [{ type: \"text\" as const, text: \"No memories found.\" }] };\n }\n\n const text = entries\n .map((entry, i) => {\n const date = new Date(entry.timestamp).toISOString().split(\"T\")[0];\n return `${safeOffset + i + 1}. [${entry.id}] [${entry.category}:${entry.scope}] ${entry.text.slice(0, 100)}${entry.text.length > 100 ? \"...\" : \"\"} (${date})`;\n })\n .join(\"\\n\");\n\n return { content: [{ type: \"text\" as const, text: `Recent memories (showing ${entries.length}):\\n\\n${text}` }] };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Failed to list memories: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// --- memory_stats ---\nserver.tool(\n \"memory_stats\",\n \"Get statistics about memory usage, scopes, and categories.\",\n {\n scope: z.string().optional().describe(\"Specific scope to get stats for\"),\n },\n async ({ scope }) => {\n try {\n let scopeFilter = scopeManager.getAccessibleScopes();\n if (scope) {\n if (scopeManager.isAccessible(scope)) {\n scopeFilter = [scope];\n } else {\n return { content: [{ type: \"text\" as const, text: `Access denied to scope: ${scope}` }] };\n }\n }\n\n const stats = await store.stats(scopeFilter);\n const scopeManagerStats = scopeManager.getStats();\n const retrievalConfig = retriever.getConfig();\n\n const text = [\n `Memory Statistics:`,\n ` Total memories: ${stats.totalCount}`,\n ` Available scopes: ${scopeManagerStats.totalScopes}`,\n ` Retrieval mode: ${retrievalConfig.mode}`,\n ` FTS support: ${store.hasFtsSupport ? \"Yes\" : \"No\"}`,\n ``,\n `Memories by scope:`,\n ...Object.entries(stats.scopeCounts).map(\n ([s, count]) => ` ${s}: ${count}`,\n ),\n ``,\n `Memories by category:`,\n ...Object.entries(stats.categoryCounts).map(\n ([c, count]) => ` ${c}: ${count}`,\n ),\n ].join(\"\\n\");\n\n return { content: [{ type: \"text\" as const, text }] };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Failed to get memory stats: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// ============================================================================\n// Start\n// ============================================================================\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n log.error(\"mnemo MCP server started (stdio)\");\n}\n\nmain().catch((err) => {\n log.error(\"Fatal:\", err);\n process.exit(1);\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Memory Categories — 6-category classification system
3
+ *
4
+ * UserMemory: profile, preferences, entities, events
5
+ * AgentMemory: cases, patterns
6
+ */
7
+ export declare const MEMORY_CATEGORIES: readonly ["profile", "preferences", "entities", "events", "cases", "patterns"];
8
+ export type MemoryCategory = (typeof MEMORY_CATEGORIES)[number];
9
+ /** Categories that always merge (skip dedup entirely). */
10
+ export declare const ALWAYS_MERGE_CATEGORIES: Set<"profile" | "preferences" | "entities" | "events" | "cases" | "patterns">;
11
+ /** Categories that support MERGE decision from LLM dedup. */
12
+ export declare const MERGE_SUPPORTED_CATEGORIES: Set<"profile" | "preferences" | "entities" | "events" | "cases" | "patterns">;
13
+ /** Categories that are append-only (CREATE or SKIP only, no MERGE). */
14
+ export declare const APPEND_ONLY_CATEGORIES: Set<"profile" | "preferences" | "entities" | "events" | "cases" | "patterns">;
15
+ /** Memory tier levels for lifecycle management. */
16
+ export type MemoryTier = "core" | "working" | "peripheral";
17
+ /** A candidate memory extracted from conversation by LLM. */
18
+ export type CandidateMemory = {
19
+ category: MemoryCategory;
20
+ abstract: string;
21
+ overview: string;
22
+ content: string;
23
+ };
24
+ /** Dedup decision from LLM. */
25
+ export type DedupDecision = "create" | "merge" | "skip" | "support" | "contextualize" | "contradict";
26
+ export type DedupResult = {
27
+ decision: DedupDecision;
28
+ reason: string;
29
+ matchId?: string;
30
+ contextLabel?: string;
31
+ };
32
+ export type ExtractionStats = {
33
+ created: number;
34
+ merged: number;
35
+ skipped: number;
36
+ supported?: number;
37
+ };
38
+ /** Validate and normalize a category string. */
39
+ export declare function normalizeCategory(raw: string): MemoryCategory | null;
40
+ //# sourceMappingURL=memory-categories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-categories.d.ts","sourceRoot":"","sources":["../../src/memory-categories.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,eAAO,MAAM,iBAAiB,gFAOpB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,0DAA0D;AAC1D,eAAO,MAAM,uBAAuB,+EAAuC,CAAC;AAE5E,6DAA6D;AAC7D,eAAO,MAAM,0BAA0B,+EAIrC,CAAC;AAEH,uEAAuE;AACvE,eAAO,MAAM,sBAAsB,+EAGjC,CAAC;AAEH,mDAAmD;AACnD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;AAE3D,6DAA6D;AAC7D,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,+BAA+B;AAC/B,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,eAAe,GAAG,YAAY,CAAC;AAErG,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,gDAAgD;AAChD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAMpE"}
@@ -0,0 +1,33 @@
1
+ const MEMORY_CATEGORIES = [
2
+ "profile",
3
+ "preferences",
4
+ "entities",
5
+ "events",
6
+ "cases",
7
+ "patterns"
8
+ ];
9
+ const ALWAYS_MERGE_CATEGORIES = /* @__PURE__ */ new Set(["profile"]);
10
+ const MERGE_SUPPORTED_CATEGORIES = /* @__PURE__ */ new Set([
11
+ "preferences",
12
+ "entities",
13
+ "patterns"
14
+ ]);
15
+ const APPEND_ONLY_CATEGORIES = /* @__PURE__ */ new Set([
16
+ "events",
17
+ "cases"
18
+ ]);
19
+ function normalizeCategory(raw) {
20
+ const lower = raw.toLowerCase().trim();
21
+ if (MEMORY_CATEGORIES.includes(lower)) {
22
+ return lower;
23
+ }
24
+ return null;
25
+ }
26
+ export {
27
+ ALWAYS_MERGE_CATEGORIES,
28
+ APPEND_ONLY_CATEGORIES,
29
+ MEMORY_CATEGORIES,
30
+ MERGE_SUPPORTED_CATEGORIES,
31
+ normalizeCategory
32
+ };
33
+ //# sourceMappingURL=memory-categories.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/memory-categories.ts"],
4
+ "sourcesContent": ["// SPDX-License-Identifier: MIT\n/**\n * Memory Categories \u2014 6-category classification system\n *\n * UserMemory: profile, preferences, entities, events\n * AgentMemory: cases, patterns\n */\n\nexport const MEMORY_CATEGORIES = [\n \"profile\",\n \"preferences\",\n \"entities\",\n \"events\",\n \"cases\",\n \"patterns\",\n] as const;\n\nexport type MemoryCategory = (typeof MEMORY_CATEGORIES)[number];\n\n/** Categories that always merge (skip dedup entirely). */\nexport const ALWAYS_MERGE_CATEGORIES = new Set<MemoryCategory>([\"profile\"]);\n\n/** Categories that support MERGE decision from LLM dedup. */\nexport const MERGE_SUPPORTED_CATEGORIES = new Set<MemoryCategory>([\n \"preferences\",\n \"entities\",\n \"patterns\",\n]);\n\n/** Categories that are append-only (CREATE or SKIP only, no MERGE). */\nexport const APPEND_ONLY_CATEGORIES = new Set<MemoryCategory>([\n \"events\",\n \"cases\",\n]);\n\n/** Memory tier levels for lifecycle management. */\nexport type MemoryTier = \"core\" | \"working\" | \"peripheral\";\n\n/** A candidate memory extracted from conversation by LLM. */\nexport type CandidateMemory = {\n category: MemoryCategory;\n abstract: string; // L0: one-sentence index\n overview: string; // L1: structured markdown summary\n content: string; // L2: full narrative\n};\n\n/** Dedup decision from LLM. */\nexport type DedupDecision = \"create\" | \"merge\" | \"skip\" | \"support\" | \"contextualize\" | \"contradict\";\n\nexport type DedupResult = {\n decision: DedupDecision;\n reason: string;\n matchId?: string; // ID of existing memory to merge with\n contextLabel?: string; // Optional context label for support/contextualize/contradict\n};\n\nexport type ExtractionStats = {\n created: number;\n merged: number;\n skipped: number;\n supported?: number; // context-aware support count\n};\n\n/** Validate and normalize a category string. */\nexport function normalizeCategory(raw: string): MemoryCategory | null {\n const lower = raw.toLowerCase().trim();\n if ((MEMORY_CATEGORIES as readonly string[]).includes(lower)) {\n return lower as MemoryCategory;\n }\n return null;\n}\n"],
5
+ "mappings": "AAQO,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,MAAM,0BAA0B,oBAAI,IAAoB,CAAC,SAAS,CAAC;AAGnE,MAAM,6BAA6B,oBAAI,IAAoB;AAAA,EAChE;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,MAAM,yBAAyB,oBAAI,IAAoB;AAAA,EAC5D;AAAA,EACA;AACF,CAAC;AA+BM,SAAS,kBAAkB,KAAoC;AACpE,QAAM,QAAQ,IAAI,YAAY,EAAE,KAAK;AACrC,MAAK,kBAAwC,SAAS,KAAK,GAAG;AAC5D,WAAO;AAAA,EACT;AACA,SAAO;AACT;",
6
+ "names": []
7
+ }