@jungjaehoon/mama-server 1.10.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -231,7 +231,7 @@ Interactive visualization of your reasoning graph.
231
231
  ## Technical Details
232
232
 
233
233
  - **Database:** SQLite + pure-TS cosine similarity
234
- - **Embeddings:** Transformers.js (Xenova/multilingual-e5-small, 384-dim)
234
+ - **Embeddings:** Transformers.js (Xenova/multilingual-e5-large, 1024-dim)
235
235
  - **Transport:** stdio-based MCP protocol (default) + optional HTTP embedding server (port 3849)
236
236
  - **Storage:** ~/.claude/mama-memory.db (configurable via MAMA_DB_PATH)
237
237
  - **Port File:** ~/.mama-embedding-port (for client discovery)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jungjaehoon/mama-server",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "description": "MAMA MCP Server - Memory-Augmented MCP Assistant for Claude Code & Desktop",
5
5
  "main": "src/server.js",
6
6
  "bin": {
@@ -119,7 +119,7 @@ CREATE INDEX IF NOT EXISTS idx_sessions_last_active ON sessions(last_active_at);
119
119
  -- because sqlite-vss requires extension loading first
120
120
  --
121
121
  -- CREATE VIRTUAL TABLE vss_memories USING vss0(
122
- -- embedding(384) -- multilingual-e5-small embeddings
122
+ -- embedding(1024) -- multilingual-e5-large embeddings
123
123
  -- );
124
124
 
125
125
  -- ══════════════════════════════════════════════════════════════
@@ -33,7 +33,7 @@ CREATE TABLE IF NOT EXISTS error_patterns (
33
33
  first_seen INTEGER NOT NULL, -- First occurrence timestamp
34
34
 
35
35
  -- Vector Embedding (for semantic matching)
36
- embedding BLOB, -- 384-dim embedding (multilingual-e5-small)
36
+ embedding BLOB, -- 1024-dim embedding (multilingual-e5-large)
37
37
 
38
38
  -- Metadata
39
39
  created_at INTEGER DEFAULT (unixepoch()),
@@ -56,7 +56,7 @@ const FIX_INSTRUCTIONS = {
56
56
  steps: [
57
57
  '1. Install Transformers.js: npm install @xenova/transformers',
58
58
  '2. Configure model in ~/.mama/config.json:',
59
- ' { "embeddingModel": "Xenova/multilingual-e5-small" }',
59
+ ' { "embeddingModel": "Xenova/multilingual-e5-large" }',
60
60
  '3. Restart Claude Code to reload configuration',
61
61
  ],
62
62
  impact: 'Without embeddings, MAMA falls back to keyword search (30% less accurate)',
package/src/server.js CHANGED
@@ -28,9 +28,9 @@ const {
28
28
  } = require('@modelcontextprotocol/sdk/types.js');
29
29
  const path = require('path');
30
30
 
31
- // Import MAMA tools - Simplified to 4 core tools (2025-11-25 refactor)
32
- // Rationale: LLM can infer relationships from search results, fewer tools = more flexibility
33
- const { loadCheckpointTool } = require('./tools/checkpoint-tools.js');
31
+ // Import all MAMA tools from src/tools/ single source of truth for tool definitions
32
+ const { createMemoryTools } = require('./tools/index.js');
33
+ const memoryTools = createMemoryTools();
34
34
  const mama = require('@jungjaehoon/mama-core/mama-api');
35
35
 
36
36
  // Import core modules from mama-core
@@ -248,6 +248,28 @@ type='checkpoint': session state for resumption (ALSO requires search first!)`,
248
248
  minimum: 0,
249
249
  maximum: 1,
250
250
  },
251
+ // Scope & temporal fields
252
+ scopes: {
253
+ type: 'array',
254
+ items: {
255
+ type: 'object',
256
+ properties: {
257
+ kind: {
258
+ type: 'string',
259
+ enum: ['global', 'user', 'channel', 'project'],
260
+ },
261
+ id: { type: 'string' },
262
+ },
263
+ required: ['kind', 'id'],
264
+ },
265
+ description:
266
+ '[Decision] Memory scopes for isolation. Example: [{"kind": "project", "id": "/path/to/project"}]',
267
+ },
268
+ event_date: {
269
+ type: 'string',
270
+ description:
271
+ '[Decision] ISO 8601 date when the event occurred (e.g., "2024-01-15"). Defaults to now.',
272
+ },
251
273
  // Checkpoint fields
252
274
  summary: {
253
275
  type: 'string',
@@ -311,6 +333,21 @@ When presenting search results to the user or agent, include a brief **Reasoning
311
333
  type: 'number',
312
334
  description: 'Maximum results. Default: 10',
313
335
  },
336
+ scopes: {
337
+ type: 'array',
338
+ items: {
339
+ type: 'object',
340
+ properties: {
341
+ kind: {
342
+ type: 'string',
343
+ enum: ['global', 'user', 'channel', 'project'],
344
+ },
345
+ id: { type: 'string' },
346
+ },
347
+ required: ['kind', 'id'],
348
+ },
349
+ description: 'Filter search results by scope.',
350
+ },
314
351
  },
315
352
  },
316
353
  },
@@ -409,6 +446,14 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
409
446
  properties: {},
410
447
  },
411
448
  },
449
+ // === v2 tools from src/tools/ ===
450
+ ...Object.values(memoryTools)
451
+ .filter((t) => t.name && t.inputSchema)
452
+ .map((t) => ({
453
+ name: t.name,
454
+ description: t.description,
455
+ inputSchema: t.inputSchema,
456
+ })),
412
457
  ],
413
458
  }));
414
459
 
@@ -435,10 +480,15 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
435
480
  result = await this.handleSearchDecisionsAndContracts(args);
436
481
  break;
437
482
  case 'load_checkpoint':
438
- result = await loadCheckpointTool.handler(args);
483
+ result = await memoryTools.load_checkpoint.handler(args);
439
484
  break;
440
485
  default:
441
- throw new Error(`Unknown tool: ${name}`);
486
+ // Route to src/tools/ handlers
487
+ if (memoryTools[name] && typeof memoryTools[name].handler === 'function') {
488
+ result = await memoryTools[name].handler(args);
489
+ } else {
490
+ throw new Error(`Unknown tool: ${name}`);
491
+ }
442
492
  }
443
493
 
444
494
  const shouldInjectLegacyNotice =
@@ -490,11 +540,19 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
490
540
  const { type } = args;
491
541
 
492
542
  if (type === 'decision') {
493
- const { topic, decision, reasoning, confidence = 0.5 } = args;
543
+ const { topic, decision, reasoning, confidence = 0.5, scopes, event_date } = args;
494
544
  if (!topic || !decision || !reasoning) {
495
545
  return { success: false, message: '❌ Decision requires: topic, decision, reasoning' };
496
546
  }
497
- const id = await mama.save({ type: 'user_decision', topic, decision, reasoning, confidence });
547
+ const id = await mama.save({
548
+ type: 'user_decision',
549
+ topic,
550
+ decision,
551
+ reasoning,
552
+ confidence,
553
+ ...(scopes && { scopes }),
554
+ ...(event_date && { event_date }),
555
+ });
498
556
  return {
499
557
  success: true,
500
558
  id,
@@ -524,7 +582,7 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
524
582
  * Handle unified search (decisions + checkpoints)
525
583
  */
526
584
  async handleSearch(args) {
527
- const { query, type = 'all', limit = 10 } = args;
585
+ const { query, type = 'all', limit = 10, scopes } = args;
528
586
 
529
587
  const results = [];
530
588
 
@@ -532,12 +590,13 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
532
590
  if (type === 'all' || type === 'decision') {
533
591
  let decisions;
534
592
  if (query) {
535
- // suggest() returns { results: [...] } object or null
536
- // Note: suggest() takes options object as second parameter
537
- const suggestResult = await mama.suggest(query, { limit });
593
+ const suggestResult = await mama.suggest(query, {
594
+ limit,
595
+ ...(scopes && { scopes }),
596
+ });
538
597
  decisions = suggestResult?.results || [];
539
598
  } else {
540
- decisions = await mama.list(limit);
599
+ decisions = await mama.list({ limit, ...(scopes && { scopes }) });
541
600
  }
542
601
  // Ensure decisions is an array
543
602
  if (Array.isArray(decisions)) {
@@ -564,9 +623,13 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
564
623
  );
565
624
  }
566
625
 
567
- // Sort by time (newest first) and limit
568
- results.sort((a, b) => (b.created_at || 0) - (a.created_at || 0));
569
- const limited = results.slice(0, limit);
626
+ // Decisions are already sorted by similarity from suggest().
627
+ // Only sort checkpoints by time. Keep decisions first (relevance), checkpoints after (recency).
628
+ const decisions = results.filter((r) => r._type === 'decision');
629
+ const checkpoints = results
630
+ .filter((r) => r._type === 'checkpoint')
631
+ .sort((a, b) => (b.created_at || 0) - (a.created_at || 0));
632
+ const limited = [...decisions, ...checkpoints].slice(0, limit);
570
633
 
571
634
  return {
572
635
  success: true,