@melandlabs/memory-store 0.1.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.
Files changed (46) hide show
  1. package/LICENSE +17 -0
  2. package/README.md +377 -0
  3. package/dist/config-MlK9f9CM.d.ts +147 -0
  4. package/dist/contracts.d.ts +62 -0
  5. package/dist/contracts.js +27 -0
  6. package/dist/contracts.js.map +1 -0
  7. package/dist/http.d.ts +38 -0
  8. package/dist/http.js +545 -0
  9. package/dist/http.js.map +1 -0
  10. package/dist/index.d.ts +35 -0
  11. package/dist/index.js +442 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/mcp.d.ts +29 -0
  14. package/dist/mcp.js +589 -0
  15. package/dist/mcp.js.map +1 -0
  16. package/dist/policies/memory-graph-correction-policy.d.ts +14 -0
  17. package/dist/policies/memory-graph-correction-policy.js +41 -0
  18. package/dist/policies/memory-graph-correction-policy.js.map +1 -0
  19. package/dist/policies/memory-graph-write-policy.d.ts +35 -0
  20. package/dist/policies/memory-graph-write-policy.js +78 -0
  21. package/dist/policies/memory-graph-write-policy.js.map +1 -0
  22. package/dist/search/unified-search.d.ts +81 -0
  23. package/dist/search/unified-search.js +399 -0
  24. package/dist/search/unified-search.js.map +1 -0
  25. package/dist/server/cli-http.d.ts +1 -0
  26. package/dist/server/cli-http.js +584 -0
  27. package/dist/server/cli-http.js.map +1 -0
  28. package/dist/server/cli-mcp.d.ts +1 -0
  29. package/dist/server/cli-mcp.js +603 -0
  30. package/dist/server/cli-mcp.js.map +1 -0
  31. package/dist/storage/chroma-memory-index.d.ts +76 -0
  32. package/dist/storage/chroma-memory-index.js +249 -0
  33. package/dist/storage/chroma-memory-index.js.map +1 -0
  34. package/dist/storage/postgres-raw-message-factory.d.ts +48 -0
  35. package/dist/storage/postgres-raw-message-factory.js +19 -0
  36. package/dist/storage/postgres-raw-message-factory.js.map +1 -0
  37. package/dist/storage/raw-message-store.d.ts +47 -0
  38. package/dist/storage/raw-message-store.js +140 -0
  39. package/dist/storage/raw-message-store.js.map +1 -0
  40. package/dist/storage/sqlite-raw-message-store.d.ts +19 -0
  41. package/dist/storage/sqlite-raw-message-store.js +68 -0
  42. package/dist/storage/sqlite-raw-message-store.js.map +1 -0
  43. package/dist/storage/sqlite-vector-index.d.ts +42 -0
  44. package/dist/storage/sqlite-vector-index.js +92 -0
  45. package/dist/storage/sqlite-vector-index.js.map +1 -0
  46. package/package.json +87 -0
@@ -0,0 +1,603 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { z } from 'zod';
5
+ import { buildMemoryRecordEmbeddingDocument } from '@melandlabs/ai/memory';
6
+ import { ChromaVectorStore } from '@melandlabs/rag';
7
+ import { mkdirSync } from 'fs';
8
+ import { dirname } from 'path';
9
+ import { SQLiteRawMessageManager } from '@melandlabs/sqlite';
10
+
11
+ // src/contracts.ts
12
+ function normalizeTimestampToMs(value) {
13
+ if (!Number.isFinite(value)) {
14
+ return 0;
15
+ }
16
+ if (value < 1e11) {
17
+ return Math.floor(value * 1e3);
18
+ }
19
+ return Math.floor(value);
20
+ }
21
+ function rawMessageToMemoryRecord(message) {
22
+ return {
23
+ id: message.messageId,
24
+ userId: message.userId,
25
+ timestamp: normalizeTimestampToMs(message.timestamp),
26
+ text: message.archivedAt ? void 0 : message.content,
27
+ mediaRefs: message.attachments?.map((item) => item.url).filter(Boolean),
28
+ embedding: message.embedding,
29
+ embeddingModel: message.embeddingModel,
30
+ embeddingContentHash: message.embeddingContentHash
31
+ };
32
+ }
33
+
34
+ // src/storage/chroma-memory-index.ts
35
+ var DEFAULT_RAW_MESSAGES_COLLECTION = "opencontext_raw_messages";
36
+ var RAW_VECTOR_BACKEND_ENV_KEYS = [
37
+ "RAW_MESSAGE_VECTOR_STORE_BACKEND",
38
+ "MEMORY_VECTOR_STORE_BACKEND",
39
+ "VECTOR_STORE_BACKEND"
40
+ ];
41
+ function getBackend(keys) {
42
+ for (const key of keys) {
43
+ const value = process.env[key]?.trim().toLowerCase();
44
+ if (value) {
45
+ return value;
46
+ }
47
+ }
48
+ return "";
49
+ }
50
+ function isRawMessageChromaEnabled() {
51
+ return getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === "chroma";
52
+ }
53
+ function getRawMessagesCollectionName() {
54
+ return process.env.CHROMA_RAW_MESSAGES_COLLECTION || process.env.CHROMA_MEMORY_COLLECTION || DEFAULT_RAW_MESSAGES_COLLECTION;
55
+ }
56
+ function getChromaStore(collectionName) {
57
+ return new ChromaVectorStore({
58
+ url: process.env.CHROMA_URL,
59
+ collectionName
60
+ });
61
+ }
62
+ function normalizeTimestampToMs2(value) {
63
+ if (!Number.isFinite(value)) {
64
+ return 0;
65
+ }
66
+ if (value < 1e11) {
67
+ return Math.floor(value * 1e3);
68
+ }
69
+ return Math.floor(value);
70
+ }
71
+ function toBooleanValue(value) {
72
+ return value === true || value === "true" || value === 1 || value === "1";
73
+ }
74
+ function rawMessageToChunk(message) {
75
+ if (!message.embedding || message.embedding.length === 0) {
76
+ return null;
77
+ }
78
+ const record = rawMessageToMemoryRecord(message);
79
+ const document = buildMemoryRecordEmbeddingDocument(record);
80
+ if (!document.content) {
81
+ return null;
82
+ }
83
+ return {
84
+ id: message.messageId,
85
+ documentId: message.messageId,
86
+ content: document.content,
87
+ embedding: message.embedding,
88
+ metadata: {
89
+ sourceType: "raw_message",
90
+ userId: message.userId,
91
+ platform: message.platform,
92
+ botId: message.botId,
93
+ channel: message.channel,
94
+ person: message.person,
95
+ timestamp: normalizeTimestampToMs2(message.timestamp),
96
+ memoryStage: message.memoryStage,
97
+ embeddingModel: message.embeddingModel,
98
+ embeddingDimensions: message.embeddingDimensions,
99
+ contentHash: message.embeddingContentHash,
100
+ archived: Boolean(message.archivedAt),
101
+ role: typeof message.metadata?.role === "string" ? message.metadata.role : void 0
102
+ }
103
+ };
104
+ }
105
+ async function upsertRawMessagesToChroma(messages) {
106
+ if (!isRawMessageChromaEnabled() || messages.length === 0) {
107
+ return 0;
108
+ }
109
+ const chunks = messages.map(rawMessageToChunk).filter((chunk) => chunk !== null);
110
+ if (chunks.length === 0) {
111
+ return 0;
112
+ }
113
+ const store = getChromaStore(getRawMessagesCollectionName());
114
+ await store.addChunks(chunks);
115
+ return chunks.length;
116
+ }
117
+ async function searchRawMessagesWithChroma(input) {
118
+ if (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {
119
+ return [];
120
+ }
121
+ const store = getChromaStore(getRawMessagesCollectionName());
122
+ const results = await store.similaritySearch(
123
+ input.queryEmbedding,
124
+ Math.max(input.limit * 5, input.limit),
125
+ input.userId
126
+ );
127
+ return results.filter((result) => {
128
+ const metadata = result.metadata ?? {};
129
+ if (toBooleanValue(metadata.archived)) {
130
+ return false;
131
+ }
132
+ if (input.botId && metadata.botId !== input.botId) {
133
+ return false;
134
+ }
135
+ return result.score >= input.threshold;
136
+ }).map((result) => ({
137
+ id: result.id,
138
+ content: result.content,
139
+ similarity: result.score,
140
+ metadata: result.metadata ?? {}
141
+ })).slice(0, input.limit);
142
+ }
143
+
144
+ // src/storage/postgres-raw-message-factory.ts
145
+ var factory = null;
146
+ async function resolvePostgresFactory(env) {
147
+ return null;
148
+ }
149
+ function hasPostgresFactory() {
150
+ return factory !== null;
151
+ }
152
+ var manager = null;
153
+ function isSQLiteRawMessageStorageAvailable(env) {
154
+ return resolveEnv(env).isTauriMode();
155
+ }
156
+ async function getSQLiteRawMessageManager(env) {
157
+ const e = resolveEnv(env);
158
+ if (!e.isTauriMode()) {
159
+ throw new Error("SQLite raw message storage is only available in Tauri mode.");
160
+ }
161
+ if (!manager) {
162
+ const dbPath = e.getTauriDbPath?.() ?? process.env.TAURI_DB_PATH ?? "";
163
+ mkdirSync(dirname(dbPath), { recursive: true });
164
+ manager = new SQLiteRawMessageManager({
165
+ dbPath,
166
+ enableVectorSearch: !isRawMessageChromaEnabled()
167
+ });
168
+ await manager.init();
169
+ }
170
+ return manager;
171
+ }
172
+ async function closeSQLiteRawMessageManager() {
173
+ if (!manager) {
174
+ return;
175
+ }
176
+ await manager.close();
177
+ manager = null;
178
+ }
179
+ function resolveEnv(env) {
180
+ if (env) return env;
181
+ return {
182
+ isTauriMode: () => process.env.IS_TAURI === "true" || typeof process.env.TAURI_MODE === "string",
183
+ getTauriDbPath: () => process.env.TAURI_DB_PATH ?? "",
184
+ getTauriDataDir: () => process.env.TAURI_DATA_DIR ?? ""
185
+ };
186
+ }
187
+
188
+ // src/storage/raw-message-store.ts
189
+ function resolveEnv2(env) {
190
+ if (env) return env;
191
+ return {
192
+ isTauriMode: () => process.env.IS_TAURI === "true" || typeof process.env.TAURI_MODE === "string",
193
+ getTauriDbPath: () => process.env.TAURI_DB_PATH ?? "",
194
+ getTauriDataDir: () => process.env.TAURI_DATA_DIR ?? ""
195
+ };
196
+ }
197
+ function createRawMessageStore(options = {}) {
198
+ const env = resolveEnv2(options.env);
199
+ return {
200
+ getBackend() {
201
+ return isSQLiteRawMessageStorageAvailable(env) ? "sqlite" : "postgres";
202
+ },
203
+ isAvailable() {
204
+ return isSQLiteRawMessageStorageAvailable(env) || hasPostgresFactory();
205
+ },
206
+ async getManager() {
207
+ if (isSQLiteRawMessageStorageAvailable(env)) {
208
+ return await getSQLiteRawMessageManager(env);
209
+ }
210
+ const pg = await resolvePostgresFactory();
211
+ if (!pg) {
212
+ throw new Error(
213
+ "No raw-message backend available. SQLite is disabled (not Tauri) and no Postgres factory is registered."
214
+ );
215
+ }
216
+ return pg;
217
+ },
218
+ async close() {
219
+ if (isSQLiteRawMessageStorageAvailable(env)) {
220
+ await closeSQLiteRawMessageManager();
221
+ }
222
+ }
223
+ };
224
+ }
225
+ var moduleStore = null;
226
+ var moduleConfig = null;
227
+ function isRawMessageStorageAvailable() {
228
+ if (!moduleStore) {
229
+ moduleStore = createRawMessageStore({ env: moduleConfig?.env });
230
+ }
231
+ return moduleStore.isAvailable();
232
+ }
233
+
234
+ // src/search/utilities.ts
235
+ var DEFAULT_LIMIT = 10;
236
+ var DEFAULT_THRESHOLD = 0.7;
237
+ var DEFAULT_SOURCES = ["memory", "insights", "knowledge"];
238
+ var SOURCE_SET = new Set(DEFAULT_SOURCES);
239
+ function normalizeUnifiedMemorySearchSources(sources) {
240
+ if (!Array.isArray(sources) || sources.length === 0) {
241
+ return [...DEFAULT_SOURCES];
242
+ }
243
+ const normalized = sources.filter((source) => typeof source === "string").map((source) => source.trim().toLowerCase()).filter(
244
+ (source) => SOURCE_SET.has(source)
245
+ );
246
+ return normalized.length > 0 ? Array.from(new Set(normalized)) : [...DEFAULT_SOURCES];
247
+ }
248
+ function clampUnifiedMemorySearchLimit(limit) {
249
+ const parsed = typeof limit === "number" ? limit : Number(limit ?? DEFAULT_LIMIT);
250
+ if (!Number.isFinite(parsed)) {
251
+ return DEFAULT_LIMIT;
252
+ }
253
+ return Math.min(50, Math.max(1, Math.floor(parsed)));
254
+ }
255
+ function clampUnifiedMemorySearchThreshold(threshold) {
256
+ const parsed = typeof threshold === "number" ? threshold : Number(threshold ?? DEFAULT_THRESHOLD);
257
+ if (!Number.isFinite(parsed)) {
258
+ return DEFAULT_THRESHOLD;
259
+ }
260
+ return Math.min(1, Math.max(-1, parsed));
261
+ }
262
+ function mergeUnifiedMemorySearchResults(results, limit) {
263
+ return [...results].sort((a, b) => {
264
+ const scoreDelta = b.similarity - a.similarity;
265
+ if (scoreDelta !== 0) {
266
+ return scoreDelta;
267
+ }
268
+ return a.type.localeCompare(b.type) || a.id.localeCompare(b.id);
269
+ }).slice(0, limit);
270
+ }
271
+ function toKnowledgeResult(result) {
272
+ return {
273
+ type: "knowledge",
274
+ id: result.chunkId,
275
+ content: result.content,
276
+ similarity: result.similarity,
277
+ metadata: {
278
+ documentId: result.documentId,
279
+ documentName: result.documentName,
280
+ chunkIndex: result.chunkIndex
281
+ }
282
+ };
283
+ }
284
+ function toMemoryResult(result) {
285
+ return {
286
+ type: "memory",
287
+ id: result.id,
288
+ content: result.content,
289
+ similarity: result.similarity,
290
+ metadata: result.metadata
291
+ };
292
+ }
293
+ function isRawMemorySemanticResult(result) {
294
+ if (!result || typeof result !== "object") {
295
+ return false;
296
+ }
297
+ const item = result;
298
+ return typeof item.id === "string" && typeof item.content === "string" && typeof item.similarity === "number" && Boolean(item.metadata) && typeof item.metadata === "object";
299
+ }
300
+
301
+ // src/search/unified-search.ts
302
+ function createUnifiedSearch(deps = {}) {
303
+ const logger = deps.logger ?? console;
304
+ async function searchUnifiedMemory(input) {
305
+ const query = input.query.trim();
306
+ const sources = normalizeUnifiedMemorySearchSources(input.sources);
307
+ const limit = clampUnifiedMemorySearchLimit(input.limit);
308
+ const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
309
+ const warnings = [];
310
+ const results = [];
311
+ if (!query) {
312
+ return {
313
+ query,
314
+ sources,
315
+ results: [],
316
+ count: 0,
317
+ warnings
318
+ };
319
+ }
320
+ if (sources.includes("memory")) {
321
+ if (isRawMessageStorageAvailable()) {
322
+ try {
323
+ const memoryHits = await runMemorySource(input, limit, threshold);
324
+ results.push(...memoryHits);
325
+ } catch (error) {
326
+ logger.warn?.("[memory-store] memory source failed:", error);
327
+ warnings.push({
328
+ source: "memory",
329
+ code: "memory_search_failed",
330
+ message: error.message ?? "memory_search_failed"
331
+ });
332
+ }
333
+ } else {
334
+ warnings.push({
335
+ source: "memory",
336
+ code: "raw_message_storage_unavailable",
337
+ message: "Raw memory storage is not available in this environment."
338
+ });
339
+ }
340
+ }
341
+ if (sources.includes("insights") && typeof deps.searchInsights === "function") {
342
+ try {
343
+ const insightHits = await deps.searchInsights({
344
+ userId: input.userId,
345
+ query: input.query,
346
+ limit,
347
+ threshold,
348
+ botIds: input.botIds,
349
+ includeArchived: input.includeArchivedInsights,
350
+ authToken: input.authToken
351
+ });
352
+ for (const hit of insightHits) {
353
+ results.push({
354
+ type: "insight",
355
+ id: hit.id,
356
+ content: hit.content,
357
+ similarity: hit.similarity,
358
+ metadata: hit.metadata
359
+ });
360
+ }
361
+ } catch (error) {
362
+ logger.warn?.("[memory-store] insights source failed:", error);
363
+ warnings.push({
364
+ source: "insights",
365
+ code: "insights_search_failed",
366
+ message: error.message ?? "insights_search_failed"
367
+ });
368
+ }
369
+ } else if (sources.includes("insights")) {
370
+ warnings.push({
371
+ source: "insights",
372
+ code: "insights_search_not_configured",
373
+ message: "Insights search is not configured for this host."
374
+ });
375
+ }
376
+ if (sources.includes("knowledge") && typeof deps.searchKnowledge === "function") {
377
+ try {
378
+ const knowledgeHits = await deps.searchKnowledge({
379
+ userId: input.userId,
380
+ query: input.query,
381
+ options: {
382
+ limit,
383
+ threshold,
384
+ documentIds: input.documentIds
385
+ },
386
+ authToken: input.authToken
387
+ });
388
+ for (const hit of knowledgeHits) {
389
+ results.push(toKnowledgeResult(hit));
390
+ }
391
+ } catch (error) {
392
+ logger.warn?.("[memory-store] knowledge source failed:", error);
393
+ warnings.push({
394
+ source: "knowledge",
395
+ code: "knowledge_search_failed",
396
+ message: error.message ?? "knowledge_search_failed"
397
+ });
398
+ }
399
+ } else if (sources.includes("knowledge")) {
400
+ warnings.push({
401
+ source: "knowledge",
402
+ code: "knowledge_search_not_configured",
403
+ message: "Knowledge search is not configured for this host."
404
+ });
405
+ }
406
+ const merged = mergeUnifiedMemorySearchResults(results, limit);
407
+ return {
408
+ query: input.query,
409
+ sources,
410
+ results: merged,
411
+ count: merged.length,
412
+ warnings
413
+ };
414
+ }
415
+ async function runMemorySource(input, limit, threshold) {
416
+ if (typeof deps.embedQuery !== "function") {
417
+ throw new Error("embedQuery is not configured");
418
+ }
419
+ const queryEmbedding = await deps.embedQuery({
420
+ userId: input.userId,
421
+ query: input.query,
422
+ authToken: input.authToken
423
+ });
424
+ const filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];
425
+ if (isRawMessageChromaEnabled()) {
426
+ try {
427
+ const chromaHits = (await Promise.all(
428
+ filters.map((filter) => {
429
+ const botId = "botId" in filter ? filter.botId : void 0;
430
+ return searchRawMessagesWithChroma({
431
+ userId: input.userId,
432
+ queryEmbedding,
433
+ limit,
434
+ threshold,
435
+ botId
436
+ });
437
+ })
438
+ )).flat().map(toMemoryResult);
439
+ logger.log?.("[memory-store] Raw message semantic search completed", {
440
+ backend: "chroma",
441
+ dimensions: queryEmbedding.length,
442
+ count: chromaHits.length
443
+ });
444
+ return chromaHits;
445
+ } catch (error) {
446
+ logger.warn?.(
447
+ "[memory-store] Chroma raw message search failed; falling back to database search:",
448
+ error
449
+ );
450
+ }
451
+ }
452
+ if (typeof deps.searchRawMessagesAnn === "function") {
453
+ const rows = (await Promise.all(
454
+ filters.map(
455
+ (filter) => deps.searchRawMessagesAnn({
456
+ userId: input.userId,
457
+ queryEmbedding,
458
+ limit,
459
+ threshold,
460
+ botId: "botId" in filter ? filter.botId : void 0
461
+ })
462
+ )
463
+ )).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
464
+ return rows;
465
+ }
466
+ return [];
467
+ }
468
+ async function searchRawMemorySemantically(input) {
469
+ const limit = clampUnifiedMemorySearchLimit(input.limit);
470
+ const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
471
+ return runMemorySource(input, limit, threshold);
472
+ }
473
+ return { searchUnifiedMemory, searchRawMemorySemantically };
474
+ }
475
+
476
+ // src/mcp.ts
477
+ var DEFAULT_NAME = "@melandlabs/memory-store";
478
+ var DEFAULT_VERSION = "0.1.0";
479
+ async function startMcpServer(options = {}) {
480
+ const server = new McpServer({
481
+ name: options.name ?? DEFAULT_NAME,
482
+ version: options.version ?? DEFAULT_VERSION
483
+ });
484
+ const rawStore = createRawMessageStore({
485
+ env: options.env
486
+ });
487
+ const search = createUnifiedSearch(options.unified);
488
+ server.tool("memory.health", "Returns the health status of the memory store.", async () => ({
489
+ content: [{ type: "text", text: JSON.stringify({ ok: true }) }]
490
+ }));
491
+ const searchSchema = {
492
+ userId: z.string(),
493
+ query: z.string().min(1),
494
+ sources: z.array(z.enum(["memory", "insights", "knowledge"])).optional().describe("Default: ['memory','insights','knowledge']"),
495
+ limit: z.number().int().min(1).max(50).default(10),
496
+ threshold: z.number().min(-1).max(1).default(0.7),
497
+ botIds: z.array(z.string()).optional(),
498
+ documentIds: z.array(z.string()).optional(),
499
+ includeArchivedInsights: z.boolean().default(false),
500
+ authToken: z.string().optional()
501
+ };
502
+ const writeSchema = {
503
+ userId: z.string(),
504
+ message: z.object({
505
+ id: z.string().optional(),
506
+ messageId: z.string().optional(),
507
+ role: z.string(),
508
+ content: z.union([z.string(), z.array(z.unknown())]),
509
+ platform: z.string().optional(),
510
+ botId: z.string().optional(),
511
+ channel: z.string().optional(),
512
+ person: z.string().optional(),
513
+ timestamp: z.number().optional(),
514
+ metadata: z.record(z.string(), z.unknown()).optional()
515
+ }).passthrough()
516
+ };
517
+ const getSchema = {
518
+ userId: z.string(),
519
+ messageId: z.string()
520
+ };
521
+ server.registerTool(
522
+ "memory.searchUnified",
523
+ {
524
+ title: "Search Unified Memory",
525
+ description: "Semantic search across raw messages (always), and optionally insights and uploaded knowledge.",
526
+ inputSchema: searchSchema
527
+ },
528
+ async (args) => {
529
+ const a = args;
530
+ const result = await search.searchUnifiedMemory(a);
531
+ return {
532
+ content: [{ type: "text", text: JSON.stringify(result) }]
533
+ };
534
+ }
535
+ );
536
+ server.registerTool(
537
+ "memory.writeRawMessage",
538
+ {
539
+ title: "Write Raw Message",
540
+ description: "Persist a single raw message to the user's memory store.",
541
+ inputSchema: writeSchema
542
+ },
543
+ async (args) => {
544
+ const a = args;
545
+ const manager2 = await rawStore.getManager();
546
+ const result = await manager2.upsertRawMessages?.({
547
+ userId: a.userId,
548
+ messages: [a.message]
549
+ });
550
+ try {
551
+ await upsertRawMessagesToChroma([a.message]);
552
+ } catch (error) {
553
+ console.warn("[memory-store/mcp] chroma upsert failed:", error);
554
+ }
555
+ return {
556
+ content: [{ type: "text", text: JSON.stringify({ ok: true, result }) }]
557
+ };
558
+ }
559
+ );
560
+ server.registerTool(
561
+ "memory.getRawMessage",
562
+ {
563
+ title: "Get Raw Message",
564
+ description: "Fetch a single raw message by its message id.",
565
+ inputSchema: getSchema
566
+ },
567
+ async (args) => {
568
+ const a = args;
569
+ const manager2 = await rawStore.getManager();
570
+ const row = await manager2.getMessageById?.(a.messageId);
571
+ return {
572
+ content: [
573
+ {
574
+ type: "text",
575
+ text: JSON.stringify({ message: row ?? null })
576
+ }
577
+ ]
578
+ };
579
+ }
580
+ );
581
+ const transport = new StdioServerTransport();
582
+ await server.connect(transport);
583
+ return server;
584
+ }
585
+
586
+ // src/server/cli-mcp.ts
587
+ async function main() {
588
+ const server = await startMcpServer();
589
+ console.error("[memory-store/mcp] listening on stdio");
590
+ const shutdown = async (signal) => {
591
+ console.error(`[memory-store/mcp] ${signal} received, shutting down\u2026`);
592
+ await server.close();
593
+ process.exit(0);
594
+ };
595
+ process.once("SIGINT", shutdown);
596
+ process.once("SIGTERM", shutdown);
597
+ }
598
+ main().catch((error) => {
599
+ console.error("[memory-store/mcp] fatal:", error);
600
+ process.exit(1);
601
+ });
602
+ //# sourceMappingURL=cli-mcp.js.map
603
+ //# sourceMappingURL=cli-mcp.js.map