@slorenzot/memento-mcp-server 0.9.0 → 1.0.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/dist/index.js CHANGED
@@ -1,5 +1,38 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
3
36
  Object.defineProperty(exports, "__esModule", { value: true });
4
37
  const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
38
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
@@ -7,6 +40,7 @@ const zod_1 = require("zod");
7
40
  const memento_core_1 = require("@slorenzot/memento-core");
8
41
  const fs_1 = require("fs");
9
42
  const path_1 = require("path");
43
+ const fs = __importStar(require("fs"));
10
44
  // Helper function to handle errors in tool execution
11
45
  function handleToolError(error) {
12
46
  console.error('Tool execution error:', error.message);
@@ -19,11 +53,7 @@ function handleToolError(error) {
19
53
  content: [
20
54
  {
21
55
  type: 'text',
22
- text: JSON.stringify({
23
- success: false,
24
- error: error.message,
25
- hint,
26
- }, null, 2),
56
+ text: JSON.stringify({ success: false, error: error.message, hint }, null, 2),
27
57
  },
28
58
  ],
29
59
  };
@@ -34,17 +64,21 @@ const projectId = (0, memento_core_1.getProjectId)(config);
34
64
  const engine = new memento_core_1.MemoryEngine(dbPath);
35
65
  let activeSessionId = null;
36
66
  const server = new mcp_js_1.McpServer({
37
- name: 'memento-mcp-server',
38
- version: '0.4.0',
67
+ name: 'memento',
68
+ version: '1.0.0',
39
69
  });
40
- server.tool('mem_save', 'Save an observation to memory. Types: decision, bug, discovery, note.', {
41
- title: zod_1.z.string().describe('Title of observation'),
42
- content: zod_1.z.string().describe('Content of observation'),
70
+ // ─── Observation Tools ──────────────────────────────────────
71
+ server.tool('memento_mem_save', 'Save an observation to persistent memory. Types: decision, bug, discovery, note. Call this PROACTIVELY after making decisions, fixing bugs, or discovering something non-obvious.', {
72
+ title: zod_1.z.string().describe('Short, searchable title (e.g. "Fixed N+1 in UserList")'),
73
+ content: zod_1.z.string().describe('Structured content: What/Why/Where/Learned format'),
43
74
  type: zod_1.z
44
75
  .enum(['decision', 'bug', 'discovery', 'note'])
45
76
  .optional()
46
77
  .describe('Type of observation (default: note)'),
47
- topic_key: zod_1.z.string().optional().describe('Topic key for grouping'),
78
+ topic_key: zod_1.z
79
+ .string()
80
+ .optional()
81
+ .describe('Stable topic key for grouping (e.g. "architecture/auth-model")'),
48
82
  project_id: zod_1.z.string().optional().describe('Project identifier'),
49
83
  metadata: zod_1.z.record(zod_1.z.unknown()).optional().describe('Additional metadata'),
50
84
  }, async ({ title, content, type, topic_key, project_id, metadata }) => {
@@ -82,185 +116,362 @@ server.tool('mem_save', 'Save an observation to memory. Types: decision, bug, di
82
116
  return handleToolError(error);
83
117
  }
84
118
  });
85
- server.tool('mem_search', 'Search observations using text matching.', {
86
- query: zod_1.z.string().optional().describe('Search query'),
119
+ server.tool('memento_mem_search', 'Search observations using full-text search (FTS5). Start with small limits and expand only if needed.', {
120
+ query: zod_1.z.string().optional().describe('Search query (FTS5 syntax)'),
87
121
  type: zod_1.z.enum(['decision', 'bug', 'discovery', 'note']).optional(),
88
122
  project_id: zod_1.z.string().optional(),
89
123
  topic_key: zod_1.z.string().optional(),
90
- limit: zod_1.z.number().optional(),
124
+ limit: zod_1.z.number().optional().describe('Max results (default: 10)'),
91
125
  offset: zod_1.z.number().optional(),
92
- }, async ({ query, type, project_id, topic_key, limit, offset }) => {
126
+ include_deleted: zod_1.z.boolean().optional().describe('Include soft-deleted observations'),
127
+ }, async ({ query, type, project_id, topic_key, limit, offset, include_deleted }) => {
93
128
  try {
94
129
  const result = await engine.search({
95
130
  query,
96
131
  type: type,
97
132
  projectId: project_id,
98
133
  topicKey: topic_key,
99
- limit,
134
+ limit: limit || 10,
100
135
  offset,
136
+ includeDeleted: include_deleted,
101
137
  });
102
138
  return {
103
- content: [
104
- {
105
- type: 'text',
106
- text: JSON.stringify(result, null, 2),
107
- },
108
- ],
139
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
109
140
  };
110
141
  }
111
142
  catch (error) {
112
143
  return handleToolError(error);
113
144
  }
114
145
  });
115
- server.tool('mem_get_observation', 'Get a specific observation by ID.', {
146
+ server.tool('memento_mem_get_observation', 'Get full content of a specific observation by ID.', {
116
147
  id: zod_1.z.number().describe('Observation ID'),
117
148
  }, async ({ id }) => {
118
- const obs = await engine.getObservation(id);
119
- if (!obs)
120
- throw new Error(`Observation ${id} not found`);
121
- return {
122
- content: [{ type: 'text', text: JSON.stringify(obs, null, 2) }],
123
- };
149
+ try {
150
+ const obs = await engine.getObservation(id);
151
+ if (!obs)
152
+ throw new Error(`Observation ${id} not found`);
153
+ return {
154
+ content: [{ type: 'text', text: JSON.stringify(obs, null, 2) }],
155
+ };
156
+ }
157
+ catch (error) {
158
+ return handleToolError(error);
159
+ }
124
160
  });
125
- server.tool('mem_update', 'Update an existing observation.', {
161
+ server.tool('memento_mem_update', 'Update an existing observation.', {
126
162
  id: zod_1.z.number().describe('Observation ID'),
127
163
  title: zod_1.z.string().optional(),
128
164
  content: zod_1.z.string().optional(),
129
165
  type: zod_1.z.enum(['decision', 'bug', 'discovery', 'note']).optional(),
130
166
  topic_key: zod_1.z.string().optional(),
131
167
  }, async ({ id, title, content, type, topic_key }) => {
132
- const updated = await engine.updateObservation(id, {
133
- title,
134
- content,
135
- type: type,
136
- topicKey: topic_key,
137
- });
138
- return {
139
- content: [
140
- {
141
- type: 'text',
142
- text: JSON.stringify({ id: updated.id, success: true }, null, 2),
143
- },
144
- ],
145
- };
168
+ try {
169
+ const updated = await engine.updateObservation(id, {
170
+ title,
171
+ content,
172
+ type: type,
173
+ topicKey: topic_key,
174
+ });
175
+ return {
176
+ content: [
177
+ { type: 'text', text: JSON.stringify({ id: updated.id, success: true }, null, 2) },
178
+ ],
179
+ };
180
+ }
181
+ catch (error) {
182
+ return handleToolError(error);
183
+ }
146
184
  });
147
- server.tool('mem_delete', 'Delete an observation.', {
148
- id: zod_1.z.number().describe('Observation ID'),
185
+ // ─── Soft Delete / Restore / Purge ──────────────────────────
186
+ server.tool('memento_mem_delete', 'Soft-delete an observation. The record is hidden from searches but can be restored with memento_mem_restore. Use memento_mem_purge for permanent deletion.', {
187
+ id: zod_1.z.number().describe('Observation ID to soft-delete'),
188
+ reason: zod_1.z.string().optional().describe('Reason for deletion (stored in metadata)'),
189
+ }, async ({ id, reason }) => {
190
+ try {
191
+ await engine.deleteObservation(id, reason);
192
+ return {
193
+ content: [
194
+ { type: 'text', text: JSON.stringify({ id, deleted: true, success: true }, null, 2) },
195
+ ],
196
+ };
197
+ }
198
+ catch (error) {
199
+ return handleToolError(error);
200
+ }
201
+ });
202
+ server.tool('memento_mem_restore', 'Restore a soft-deleted observation back to active state.', {
203
+ id: zod_1.z.number().describe('Observation ID to restore'),
149
204
  }, async ({ id }) => {
150
- await engine.deleteObservation(id);
151
- return {
152
- content: [
153
- {
154
- type: 'text',
155
- text: JSON.stringify({ id, success: true }, null, 2),
156
- },
157
- ],
158
- };
205
+ try {
206
+ const restored = await engine.restoreObservation(id);
207
+ return {
208
+ content: [
209
+ {
210
+ type: 'text',
211
+ text: JSON.stringify({ id: restored.id, restored: true, success: true }, null, 2),
212
+ },
213
+ ],
214
+ };
215
+ }
216
+ catch (error) {
217
+ return handleToolError(error);
218
+ }
219
+ });
220
+ server.tool('memento_mem_purge', 'PERMANENTLY delete soft-deleted observations. This is IRREVERSIBLE. Requires confirm: true.', {
221
+ confirm: zod_1.z.boolean().describe('Must be true to execute purge'),
222
+ project_id: zod_1.z.string().optional().describe('Purge all deleted obs in this project'),
223
+ observation_ids: zod_1.z
224
+ .array(zod_1.z.number())
225
+ .optional()
226
+ .describe('Specific soft-deleted observation IDs to purge'),
227
+ }, async ({ confirm, project_id, observation_ids }) => {
228
+ try {
229
+ if (!confirm) {
230
+ return {
231
+ content: [
232
+ {
233
+ type: 'text',
234
+ text: JSON.stringify({ success: false, error: 'confirm must be true to execute purge' }, null, 2),
235
+ },
236
+ ],
237
+ };
238
+ }
239
+ const result = await engine.purgeObservations({
240
+ projectId: project_id,
241
+ observationIds: observation_ids,
242
+ });
243
+ return {
244
+ content: [{ type: 'text', text: JSON.stringify({ ...result, success: true }, null, 2) }],
245
+ };
246
+ }
247
+ catch (error) {
248
+ return handleToolError(error);
249
+ }
250
+ });
251
+ server.tool('memento_mem_list_deleted', 'List soft-deleted observations that can be restored or purged.', {
252
+ project_id: zod_1.z.string().optional(),
253
+ limit: zod_1.z.number().optional().describe('Max results (default: 20)'),
254
+ }, async ({ project_id, limit }) => {
255
+ try {
256
+ const result = await engine.listDeleted({ projectId: project_id, limit });
257
+ return {
258
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
259
+ };
260
+ }
261
+ catch (error) {
262
+ return handleToolError(error);
263
+ }
264
+ });
265
+ // ─── Merge ──────────────────────────────────────────────────
266
+ server.tool('memento_mem_merge', 'Merge related observations into a single synthesized record. Identifies candidates automatically by topic_key or content similarity (Jaccard > 0.85). Use dry_run to preview without executing.', {
267
+ project_id: zod_1.z.string().describe('Project to merge observations in (required)'),
268
+ topic_key: zod_1.z.string().optional().describe('Merge all observations with this topic_key'),
269
+ observation_ids: zod_1.z
270
+ .array(zod_1.z.number())
271
+ .optional()
272
+ .describe('Specific observation IDs to merge (overrides auto-detection)'),
273
+ strategy: zod_1.z
274
+ .enum(['by_topic', 'by_similarity', 'by_ids'])
275
+ .optional()
276
+ .describe('Merge strategy (default: by_topic)'),
277
+ dry_run: zod_1.z.boolean().optional().describe('If true, returns candidates without executing merge'),
278
+ }, async ({ project_id, topic_key, observation_ids, strategy, dry_run }) => {
279
+ try {
280
+ const results = await engine.mergeObservations({
281
+ projectId: project_id,
282
+ topicKey: topic_key,
283
+ observationIds: observation_ids,
284
+ strategy: strategy || 'by_topic',
285
+ dryRun: dry_run,
286
+ });
287
+ return {
288
+ content: [
289
+ {
290
+ type: 'text',
291
+ text: JSON.stringify({
292
+ success: true,
293
+ dryRun: dry_run || false,
294
+ mergeCount: results.length,
295
+ results: results.map((r) => ({
296
+ mergedObservationId: r.mergedObservation.id,
297
+ deletedIds: r.deletedIds,
298
+ originalCount: r.originalCount,
299
+ strategy: r.strategy,
300
+ })),
301
+ }, null, 2),
302
+ },
303
+ ],
304
+ };
305
+ }
306
+ catch (error) {
307
+ return handleToolError(error);
308
+ }
309
+ });
310
+ // ─── Export ──────────────────────────────────────────────────
311
+ server.tool('memento_mem_export', 'Export observations to JSON, XML, or TXT format. Use filters to reduce scope.', {
312
+ format: zod_1.z.enum(['json', 'xml', 'txt']).optional().describe('Export format (default: json)'),
313
+ project_id: zod_1.z.string().optional().describe('Filter by project'),
314
+ type: zod_1.z.enum(['decision', 'bug', 'discovery', 'note']).optional(),
315
+ topic_key: zod_1.z.string().optional(),
316
+ date_from: zod_1.z.string().optional().describe('ISO date string — export from this date'),
317
+ date_to: zod_1.z.string().optional().describe('ISO date string — export until this date'),
318
+ include_deleted: zod_1.z.boolean().optional().describe('Include soft-deleted observations'),
319
+ }, async ({ format, project_id, type, topic_key, date_from, date_to, include_deleted }) => {
320
+ try {
321
+ const result = await engine.exportObservations({
322
+ format: format || 'json',
323
+ projectId: project_id,
324
+ type: type,
325
+ topicKey: topic_key,
326
+ dateFrom: date_from ? new Date(date_from) : undefined,
327
+ dateTo: date_to ? new Date(date_to) : undefined,
328
+ includeDeleted: include_deleted,
329
+ });
330
+ return {
331
+ content: [
332
+ {
333
+ type: 'text',
334
+ text: JSON.stringify({
335
+ success: true,
336
+ format: result.format,
337
+ recordCount: result.recordCount,
338
+ exportedAt: result.exportedAt.toISOString(),
339
+ content: result.content,
340
+ }, null, 2),
341
+ },
342
+ ],
343
+ };
344
+ }
345
+ catch (error) {
346
+ return handleToolError(error);
347
+ }
159
348
  });
160
- server.tool('mem_session_start', 'Start a new memory session.', {
349
+ // ─── Session Tools ──────────────────────────────────────────
350
+ server.tool('memento_mem_session_start', 'Start a new memory session for tracking a coding conversation.', {
161
351
  project_id: zod_1.z.string().describe('Project identifier'),
162
352
  metadata: zod_1.z.record(zod_1.z.unknown()).optional(),
163
353
  }, async ({ project_id, metadata }) => {
164
- const session = await engine.createSession({
165
- projectId: project_id,
166
- endedAt: null,
167
- metadata: metadata || {},
168
- });
169
- activeSessionId = session.id;
170
- return {
171
- content: [
172
- {
173
- type: 'text',
174
- text: JSON.stringify({ id: session.id, uuid: session.uuid, success: true }, null, 2),
175
- },
176
- ],
177
- };
354
+ try {
355
+ const session = await engine.createSession({
356
+ projectId: project_id,
357
+ endedAt: null,
358
+ metadata: metadata || {},
359
+ });
360
+ activeSessionId = session.id;
361
+ return {
362
+ content: [
363
+ {
364
+ type: 'text',
365
+ text: JSON.stringify({ id: session.id, uuid: session.uuid, success: true }, null, 2),
366
+ },
367
+ ],
368
+ };
369
+ }
370
+ catch (error) {
371
+ return handleToolError(error);
372
+ }
178
373
  });
179
- server.tool('mem_session_end', 'End current active session.', {}, async () => {
180
- if (!activeSessionId)
181
- throw new Error('No active session');
182
- const ended = await engine.endSession(activeSessionId);
183
- activeSessionId = null;
184
- return {
185
- content: [
186
- {
187
- type: 'text',
188
- text: JSON.stringify({ id: ended.id, uuid: ended.uuid, endedAt: ended.endedAt, success: true }, null, 2),
189
- },
190
- ],
191
- };
374
+ server.tool('memento_mem_session_end', 'End current active session.', {}, async () => {
375
+ try {
376
+ if (!activeSessionId)
377
+ throw new Error('No active session');
378
+ const ended = await engine.endSession(activeSessionId);
379
+ activeSessionId = null;
380
+ return {
381
+ content: [
382
+ {
383
+ type: 'text',
384
+ text: JSON.stringify({ id: ended.id, uuid: ended.uuid, endedAt: ended.endedAt, success: true }, null, 2),
385
+ },
386
+ ],
387
+ };
388
+ }
389
+ catch (error) {
390
+ return handleToolError(error);
391
+ }
192
392
  });
193
- server.tool('mem_list_sessions', 'List all sessions.', {
393
+ server.tool('memento_mem_list_sessions', 'List all sessions.', {
194
394
  project_id: zod_1.z.string().optional(),
195
395
  limit: zod_1.z.number().optional(),
196
396
  }, async ({ project_id, limit }) => {
197
- const result = await engine.search({
198
- projectId: project_id,
199
- limit: limit || 20,
200
- });
201
- const uniqueSessions = new Set(result.observations.map((o) => o.sessionId));
202
- const sessions = await Promise.all(Array.from(uniqueSessions).map((id) => engine.getSession(id)));
203
- return {
204
- content: [
205
- {
206
- type: 'text',
207
- text: JSON.stringify({ sessions: sessions.filter(Boolean), total: sessions.length }, null, 2),
208
- },
209
- ],
210
- };
397
+ try {
398
+ const result = await engine.search({ projectId: project_id, limit: limit || 20 });
399
+ const uniqueSessions = new Set(result.observations.map((o) => o.sessionId));
400
+ const sessions = await Promise.all(Array.from(uniqueSessions).map((id) => engine.getSession(id)));
401
+ return {
402
+ content: [
403
+ {
404
+ type: 'text',
405
+ text: JSON.stringify({ sessions: sessions.filter(Boolean), total: sessions.length }, null, 2),
406
+ },
407
+ ],
408
+ };
409
+ }
410
+ catch (error) {
411
+ return handleToolError(error);
412
+ }
211
413
  });
212
- server.tool('mem_get_session', 'Get a specific session by ID.', {
414
+ server.tool('memento_mem_get_session', 'Get a specific session by ID.', {
213
415
  id: zod_1.z.number().describe('Session ID'),
214
416
  }, async ({ id }) => {
215
- const s = await engine.getSession(id);
216
- if (!s)
217
- throw new Error(`Session ${id} not found`);
218
- return {
219
- content: [{ type: 'text', text: JSON.stringify(s, null, 2) }],
220
- };
417
+ try {
418
+ const s = await engine.getSession(id);
419
+ if (!s)
420
+ throw new Error(`Session ${id} not found`);
421
+ return {
422
+ content: [{ type: 'text', text: JSON.stringify(s, null, 2) }],
423
+ };
424
+ }
425
+ catch (error) {
426
+ return handleToolError(error);
427
+ }
221
428
  });
222
- server.tool('mem_timeline', 'Get chronological timeline of observations.', {
429
+ // ─── Utility Tools ──────────────────────────────────────────
430
+ server.tool('memento_mem_timeline', 'Get chronological timeline of observations.', {
223
431
  project_id: zod_1.z.string().optional(),
224
432
  limit: zod_1.z.number().optional(),
225
433
  offset: zod_1.z.number().optional(),
226
434
  }, async ({ project_id, limit, offset }) => {
227
- const result = await engine.search({
228
- projectId: project_id,
229
- limit,
230
- offset,
231
- });
232
- return {
233
- content: [
234
- {
235
- type: 'text',
236
- text: JSON.stringify(result, null, 2),
237
- },
238
- ],
239
- };
435
+ try {
436
+ const result = await engine.search({ projectId: project_id, limit, offset });
437
+ return {
438
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
439
+ };
440
+ }
441
+ catch (error) {
442
+ return handleToolError(error);
443
+ }
240
444
  });
241
- server.tool('mem_stats', 'Get memory statistics.', {}, async () => {
242
- const result = await engine.search({});
243
- const byType = {};
244
- const byProject = {};
245
- for (const o of result.observations) {
246
- byType[o.type] = (byType[o.type] || 0) + 1;
247
- byProject[o.projectId] = (byProject[o.projectId] || 0) + 1;
445
+ server.tool('memento_mem_stats', 'Get memory statistics.', {}, async () => {
446
+ try {
447
+ const result = await engine.search({});
448
+ const deleted = await engine.listDeleted({});
449
+ const byType = {};
450
+ const byProject = {};
451
+ for (const o of result.observations) {
452
+ byType[o.type] = (byType[o.type] || 0) + 1;
453
+ byProject[o.projectId] = (byProject[o.projectId] || 0) + 1;
454
+ }
455
+ return {
456
+ content: [
457
+ {
458
+ type: 'text',
459
+ text: JSON.stringify({
460
+ totalObservations: result.total,
461
+ deletedObservations: deleted.total,
462
+ byType,
463
+ byProject,
464
+ activeSessionId,
465
+ }, null, 2),
466
+ },
467
+ ],
468
+ };
469
+ }
470
+ catch (error) {
471
+ return handleToolError(error);
248
472
  }
249
- return {
250
- content: [
251
- {
252
- type: 'text',
253
- text: JSON.stringify({
254
- totalObservations: result.total,
255
- byType,
256
- byProject,
257
- activeSessionId,
258
- }, null, 2),
259
- },
260
- ],
261
- };
262
473
  });
263
- server.tool('mem_health', 'Check system health.', {}, async () => {
474
+ server.tool('memento_mem_health', 'Check system health.', {}, async () => {
264
475
  try {
265
476
  const isHealthy = engine.isHealthy();
266
477
  const result = isHealthy ? await engine.search({}) : { total: 0, observations: [] };
@@ -271,7 +482,7 @@ server.tool('mem_health', 'Check system health.', {}, async () => {
271
482
  type: 'text',
272
483
  text: JSON.stringify({
273
484
  status: isHealthy ? 'healthy' : 'unhealthy',
274
- version: '0.7.0',
485
+ version: '1.0.0',
275
486
  storage: 'sqlite-persistent',
276
487
  databasePath: dbPath,
277
488
  projectId: projectId,
@@ -288,77 +499,99 @@ server.tool('mem_health', 'Check system health.', {}, async () => {
288
499
  return handleToolError(error);
289
500
  }
290
501
  });
291
- server.tool('mem_config', 'Get current memento configuration and system status.', {}, async () => {
292
- const searchResult = await engine.search({});
293
- const dbPath = engine.getDatabasePath();
294
- const byType = {};
295
- for (const o of searchResult.observations) {
296
- byType[o.type] = (byType[o.type] || 0) + 1;
297
- }
298
- const dbStats = getDatabaseStats(dbPath);
299
- return {
300
- content: [
301
- {
302
- type: 'text',
303
- text: JSON.stringify({
304
- name: 'memento-mcp-server',
305
- version: '0.5.0',
306
- config: {
307
- storagePath: dbPath,
308
- projectId: projectId,
309
- projectRoot: process.cwd(),
310
- hasConfigFile: (0, fs_1.existsSync)((0, path_1.join)(process.cwd(), '.mementorc')),
311
- },
312
- storage: {
313
- type: 'SQLite Persistent',
314
- method: 'bun:sqlite',
315
- databasePath: dbPath,
316
- walEnabled: true,
317
- },
318
- diskUsage: dbStats,
319
- statistics: {
320
- totalObservations: searchResult.total,
321
- byType,
322
- activeSession: activeSessionId,
323
- },
324
- environment: {
325
- nodeVersion: process.version,
326
- platform: process.platform,
327
- arch: process.arch,
328
- bunVersion: process.versions?.bun || 'unknown',
329
- },
330
- }, null, 2),
331
- },
332
- ],
333
- };
502
+ server.tool('memento_mem_config', 'Get current memento configuration and system status.', {}, async () => {
503
+ try {
504
+ const searchResult = await engine.search({});
505
+ const currentDbPath = engine.getDatabasePath();
506
+ const byType = {};
507
+ for (const o of searchResult.observations) {
508
+ byType[o.type] = (byType[o.type] || 0) + 1;
509
+ }
510
+ const dbStats = getDatabaseStats(currentDbPath);
511
+ return {
512
+ content: [
513
+ {
514
+ type: 'text',
515
+ text: JSON.stringify({
516
+ name: 'memento',
517
+ version: '1.0.0',
518
+ config: {
519
+ storagePath: currentDbPath,
520
+ projectId: projectId,
521
+ projectRoot: process.cwd(),
522
+ hasConfigFile: (0, fs_1.existsSync)((0, path_1.join)(process.cwd(), '.mementorc')),
523
+ },
524
+ storage: {
525
+ type: 'SQLite Persistent',
526
+ method: 'bun:sqlite',
527
+ databasePath: currentDbPath,
528
+ walEnabled: true,
529
+ },
530
+ diskUsage: dbStats,
531
+ statistics: {
532
+ totalObservations: searchResult.total,
533
+ byType,
534
+ activeSession: activeSessionId,
535
+ },
536
+ environment: {
537
+ nodeVersion: process.version,
538
+ platform: process.platform,
539
+ arch: process.arch,
540
+ bunVersion: process.versions?.bun || 'unknown',
541
+ },
542
+ tools: [
543
+ 'memento_mem_save',
544
+ 'memento_mem_search',
545
+ 'memento_mem_get_observation',
546
+ 'memento_mem_update',
547
+ 'memento_mem_delete',
548
+ 'memento_mem_restore',
549
+ 'memento_mem_purge',
550
+ 'memento_mem_list_deleted',
551
+ 'memento_mem_merge',
552
+ 'memento_mem_export',
553
+ 'memento_mem_session_start',
554
+ 'memento_mem_session_end',
555
+ 'memento_mem_list_sessions',
556
+ 'memento_mem_get_session',
557
+ 'memento_mem_timeline',
558
+ 'memento_mem_stats',
559
+ 'memento_mem_health',
560
+ 'memento_mem_config',
561
+ ],
562
+ }, null, 2),
563
+ },
564
+ ],
565
+ };
566
+ }
567
+ catch (error) {
568
+ return handleToolError(error);
569
+ }
334
570
  });
571
+ // ─── Helpers ────────────────────────────────────────────────
335
572
  function getDatabaseStats(dbPath) {
336
- const fs = require('fs');
337
573
  let totalSize = 0;
338
574
  let walSize = 0;
339
575
  let shmSize = 0;
340
576
  try {
341
- const mainDb = fs.statSync(dbPath);
342
- totalSize += mainDb.size;
577
+ totalSize += fs.statSync(dbPath).size;
343
578
  }
344
- catch (e) {
345
- totalSize += 0;
579
+ catch {
580
+ /* empty */
346
581
  }
347
582
  try {
348
- const walFile = fs.statSync(`${dbPath}-wal`);
349
- walSize = walFile.size;
583
+ walSize = fs.statSync(`${dbPath}-wal`).size;
350
584
  totalSize += walSize;
351
585
  }
352
- catch (e) {
353
- walSize = 0;
586
+ catch {
587
+ /* empty */
354
588
  }
355
589
  try {
356
- const shmFile = fs.statSync(`${dbPath}-shm`);
357
- shmSize = shmFile.size;
590
+ shmSize = fs.statSync(`${dbPath}-shm`).size;
358
591
  totalSize += shmSize;
359
592
  }
360
- catch (e) {
361
- shmSize = 0;
593
+ catch {
594
+ /* empty */
362
595
  }
363
596
  return {
364
597
  totalBytes: totalSize,
@@ -367,8 +600,6 @@ function getDatabaseStats(dbPath) {
367
600
  mainDbSizeHuman: formatBytes(totalSize - walSize - shmSize),
368
601
  walBytes: walSize,
369
602
  walSizeHuman: formatBytes(walSize),
370
- shmBytes: shmSize,
371
- shmSizeHuman: formatBytes(shmSize),
372
603
  };
373
604
  }
374
605
  function formatBytes(bytes) {
@@ -385,38 +616,27 @@ function formatBytes(bytes) {
385
616
  return `${(bytes / m).toFixed(2)} MB`;
386
617
  return `${(bytes / g).toFixed(2)} GB`;
387
618
  }
619
+ // ─── Server Startup ─────────────────────────────────────────
388
620
  const BANNER = `
389
- ╔═════════════════════════════════════════════════════════╗
390
-
391
- ██╗ ██╗███████╗██╗ ██╗██╗███╗ ███████╗
392
- ██║ ██║██╔════╝██║ ██║██║██╔██╗ ██╔════╝
393
- ██║ █╗ ██║█████╗ ██║ ██║██║███████║███████╗
394
- ╚███╔╝██╚════██╗██║ ██║██║╚════██║╚════██║
395
- ╚══╝ ╚███████╔╝╚█████╔╝╚█████╔╝ ╚███████╔╝
396
- ╚═════╝ ╚═════╝ ╚═════╝
397
-
398
- ║ ╔═══════════════════════════════════════╗ ║
399
- ║ ║ ║ ║
400
- ║ ║ MEMENTO - Persistent Memory System ║ ║
401
- ║ ║ ║ ║
402
- ║ ║ Version: 0.5.0 ║ ║
403
- ║ ║ Storage: SQLite Persistent ║ ║
404
- ║ ╚═══════════════════════════════════════╝ ║
405
- ╚═════════════════════════════════════════════════════════╝
621
+ ╔══════════════════════════════════════════════════╗
622
+
623
+ MEMENTO — Persistent Memory System
624
+
625
+ Version: 1.0.0
626
+ MCP Server: memento
627
+ Storage: SQLite Persistent
628
+ Tools: memento_mem_*
629
+
630
+ ╚══════════════════════════════════════════════════╝
406
631
  `;
407
632
  async function main() {
408
633
  console.error(BANNER);
409
- // Check database health and show warnings if needed
410
634
  if (!engine.isHealthy()) {
411
635
  const initError = engine.getInitError();
412
636
  console.error('\n⚠️ WARNING: Database initialization failed');
413
637
  console.error(` Error: ${initError?.message || 'Unknown error'}`);
414
638
  console.error(` Database path: ${dbPath}`);
415
639
  console.error('\n The server will start, but database operations will fail.');
416
- console.error(' Please check:');
417
- console.error(' - Directory permissions');
418
- console.error(' - Disk space');
419
- console.error(' - Path configuration in .mementorc\n');
420
640
  }
421
641
  const transport = new stdio_js_1.StdioServerTransport();
422
642
  await server.connect(transport);
@@ -424,11 +644,11 @@ async function main() {
424
644
  console.error(` Database: ${dbPath}`);
425
645
  console.error(` Project: ${projectId}`);
426
646
  console.error(` Health: ${engine.isHealthy() ? '✓ Healthy' : '✗ Unhealthy'}`);
647
+ console.error(` Tools: 18 (memento_mem_*)`);
427
648
  console.error(` Ready to accept connections...\n`);
428
649
  }
429
650
  main().catch((err) => {
430
651
  console.error('Fatal error during server startup:', err);
431
- console.error('\nThe server failed to start. Please check the error above.');
432
652
  process.exit(1);
433
653
  });
434
654
  //# sourceMappingURL=index.js.map