@jungjaehoon/mama-server 1.11.0 β†’ 1.11.1

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/server.js +65 -263
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jungjaehoon/mama-server",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "MAMA MCP Server - Memory-Augmented MCP Assistant for Claude Code & Desktop",
5
5
  "main": "src/server.js",
6
6
  "bin": {
package/src/server.js CHANGED
@@ -192,272 +192,79 @@ class MAMAServer {
192
192
  }
193
193
 
194
194
  setupHandlers() {
195
- // List available tools - Simplified to 4 core tools (2025-11-25)
196
- // Design principle: LLM infers relationships from search results
197
- // Fewer tools = more flexibility, less constraint
198
- this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
199
- tools: [
200
- // 1. SAVE - Unified save for decisions and checkpoints
201
- {
202
- name: 'save',
203
- description: `${this.legacyHttpEmbeddingMode ? `${this.getLegacyMigrationNotice()}\n\n` : ''}🀝 Save a decision or checkpoint to your reasoning graph.
204
-
205
- ⚑ TRIGGERS - Call this when:
206
- β€’ User says: "κΈ°μ–΅ν•΄μ€˜", "remember", "decided", "κ²°μ •ν–ˆμ–΄"
207
- β€’ Lesson learned: "κΉ¨λ‹¬μ•˜μ–΄", "μ•Œκ²Œλμ–΄", "this worked/failed"
208
- β€’ Architectural choice made
209
- β€’ Session ending β†’ use type='checkpoint'
210
-
211
- πŸ”— REQUIRED WORKFLOW (Don't create orphans!):
212
- 1. Call 'search' FIRST to find related decisions
213
- 2. Check if same topic exists (yours will supersede it)
214
- 3. MUST include link in reasoning/summary field
215
-
216
- πŸ“Ž LINKING FORMAT:
217
- β€’ [Decision] reasoning: End with 'builds_on: <id>' or 'debates: <id>' or 'synthesizes: [id1, id2]'
218
- β€’ [Checkpoint] summary: Include 'Related decisions: decision_xxx, decision_yyy'
219
-
220
- type='decision': choices & lessons (same topic = evolution chain)
221
- type='checkpoint': session state for resumption (ALSO requires search first!)`,
222
- inputSchema: {
223
- type: 'object',
224
- properties: {
225
- type: {
226
- type: 'string',
227
- enum: ['decision', 'checkpoint'],
228
- description: "What to save: 'decision' or 'checkpoint'",
229
- },
230
- // Decision fields
231
- topic: {
232
- type: 'string',
233
- description:
234
- "[Decision] Topic identifier (e.g., 'auth_strategy'). ⚑ REUSE same topic = supersedes previous, creating evolution chain.",
235
- },
236
- decision: {
237
- type: 'string',
238
- description: "[Decision] The decision made (e.g., 'Use JWT with refresh tokens').",
239
- },
240
- reasoning: {
241
- type: 'string',
242
- description:
243
- "[Decision] Why this decision was made. Include 5-layer narrative: (1) Context - what problem/situation; (2) Evidence - what proves this works (tests, benchmarks, prior experience); (3) Alternatives - what other options were considered and why rejected; (4) Risks - known limitations or failure modes; (5) Rationale - final reasoning for this choice. ⚠️ REQUIRED: End with 'builds_on: <id>' or 'debates: <id>' or 'synthesizes: [id1, id2]' to link related decisions.",
244
- },
245
- confidence: {
246
- type: 'number',
247
- description: '[Decision] Confidence 0.0-1.0. Default: 0.5',
248
- minimum: 0,
249
- maximum: 1,
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
- },
273
- // Checkpoint fields
274
- summary: {
275
- type: 'string',
276
- description:
277
- "[Checkpoint] Session state summary. Use 4-section format: (1) 🎯 Goal & Progress - what was the goal, where did you stop; (2) βœ… Evidence - mark each item as Verified/Not run/Assumed with proof; (3) ⏳ Unfinished & Risks - incomplete work, blockers, unknowns; (4) 🚦 Next Agent Briefing - Definition of Done, quick health checks to run first. ⚠️ Include 'Related decisions: decision_xxx, decision_yyy' to link context.",
278
- },
279
- next_steps: {
280
- type: 'string',
281
- description:
282
- '[Checkpoint] Instructions for next session: DoD (Definition of Done), quick verification commands (npm test, curl health), constraints/cautions.',
283
- },
284
- open_files: {
285
- type: 'array',
286
- items: { type: 'string' },
287
- description: '[Checkpoint] Currently relevant files.',
288
- },
195
+ // Tool definitions come from src/tools/ (single source of truth).
196
+ // Legacy unified tools (save, search, update) kept as wrappers for backward compat.
197
+ const legacyNotice = this.legacyHttpEmbeddingMode
198
+ ? `${this.getLegacyMigrationNotice()}\n\n`
199
+ : '';
200
+
201
+ const legacyTools = [
202
+ {
203
+ name: 'save',
204
+ description: `${legacyNotice}${memoryTools.save_decision.description}\n\nAlso supports type='checkpoint' for session state.`,
205
+ inputSchema: {
206
+ type: 'object',
207
+ properties: {
208
+ ...memoryTools.save_decision.inputSchema.properties,
209
+ type: {
210
+ type: 'string',
211
+ enum: ['decision', 'checkpoint'],
212
+ description: "What to save: 'decision' or 'checkpoint'",
289
213
  },
290
- required: ['type'],
291
- },
292
- },
293
- // 2. SEARCH - Unified search across decisions and checkpoints
294
- {
295
- name: 'search',
296
- description: `πŸ” Search the reasoning graph before acting.
297
-
298
- ⚑ TRIGGERS - Call this BEFORE:
299
- β€’ ⚠️ REQUIRED before 'save' (find links first!)
300
- β€’ Making architectural choices (check prior art)
301
- β€’ Debugging (find past failures on similar issues)
302
- β€’ Starting work on a topic (load context)
303
- β€’ User asks: "λ­μ˜€λ”λΌ", "what did we decide", "이전에"
304
-
305
- πŸ”— USE FOR REASONING GRAPH:
306
- β€’ Find decisions to supersede (same topic)
307
- β€’ Find decisions to link (builds_on, debates, synthesizes)
308
- β€’ Understand decision evolution (time-ordered results)
309
-
310
- Cross-lingual: Works in Korean and English.
311
- ⚠️ High similarity (>0.8) = MUST link with builds_on/debates/synthesizes.
312
-
313
- 🧠 OUTPUT EXPECTATION:
314
- When presenting search results to the user or agent, include a brief **Reasoning Summary** grounded in the actual results:
315
- - Why these results match (tokens/endpoint/field overlap)
316
- - What is known vs unknown (explicitly mark unknowns)
317
- - What to do next (use contract fields, avoid guessing)`,
318
- inputSchema: {
319
- type: 'object',
320
- properties: {
321
- query: {
322
- type: 'string',
323
- description:
324
- 'Search query (optional). Semantic search finds related decisions even with different wording. If empty, returns recent items sorted by time.',
325
- },
326
- type: {
327
- type: 'string',
328
- enum: ['all', 'decision', 'checkpoint'],
329
- description:
330
- "Filter by type: 'decision' for architectural choices, 'checkpoint' for session states, 'all' for both. Default: 'all'",
331
- },
332
- limit: {
333
- type: 'number',
334
- description: 'Maximum results. Default: 10',
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
- },
214
+ summary: {
215
+ type: 'string',
216
+ description: '[Checkpoint] Session state summary.',
351
217
  },
352
- },
353
- },
354
- // 3. UPDATE - Update decision outcome
355
- {
356
- name: 'update',
357
- description: `πŸ“ Update decision outcome after real-world validation.
358
-
359
- ⚑ TRIGGERS - Call this when:
360
- β€’ Days/weeks later: issues discovered β†’ mark 'failed' + reason
361
- β€’ Production success confirmed β†’ mark 'success'
362
- β€’ Partial results with caveats β†’ mark 'partial'
363
- β€’ User says: "이거 μ•ˆλμ–΄", "this didn't work", "μ„±κ³΅ν–ˆμ–΄"
364
-
365
- πŸ”— REASONING GRAPH IMPACT:
366
- β€’ 'failed' outcomes teach future LLMs what to avoid
367
- β€’ After failure β†’ save NEW decision with same topic to supersede
368
-
369
- πŸ’‘ TIP: Don't just update - if approach changed, save a NEW decision with same topic. This creates evolution history.`,
370
- inputSchema: {
371
- type: 'object',
372
- properties: {
373
- id: {
374
- type: 'string',
375
- description: 'Decision ID to update.',
376
- },
377
- outcome: {
378
- type: 'string',
379
- description:
380
- "New outcome status (case-insensitive): 'success' or 'SUCCESS', 'failed' or 'FAILED', 'partial' or 'PARTIAL'.",
381
- },
382
- reason: {
383
- type: 'string',
384
- description:
385
- 'Why it succeeded/failed/was partial. Include specific evidence: error logs, metrics, user feedback, or what broke.',
386
- },
218
+ next_steps: {
219
+ type: 'string',
220
+ description: '[Checkpoint] Instructions for next session.',
387
221
  },
388
- required: ['id', 'outcome'],
389
- },
390
- },
391
- // 4. SEARCH_DECISIONS_AND_CONTRACTS - PreToolUse RPC for hooks
392
- {
393
- name: 'search_decisions_and_contracts',
394
- description:
395
- 'Search decisions and related contracts for PreToolUse injection (MAMA v2 hooks).',
396
- inputSchema: {
397
- type: 'object',
398
- properties: {
399
- query: {
400
- type: 'string',
401
- description: 'Search query for decisions.',
402
- },
403
- filePath: {
404
- type: 'string',
405
- description: 'File path context for contract search.',
406
- },
407
- toolName: {
408
- type: 'string',
409
- description: 'Tool name context (Edit/Write/apply_patch).',
410
- },
411
- decisionLimit: {
412
- type: 'number',
413
- description: 'Max decision results (default: 5).',
414
- },
415
- contractLimit: {
416
- type: 'number',
417
- description: 'Max contract results (default: 3).',
418
- },
419
- similarityThreshold: {
420
- type: 'number',
421
- description: 'Similarity threshold for vector search (default: 0.7).',
422
- },
222
+ open_files: {
223
+ type: 'array',
224
+ items: { type: 'string' },
225
+ description: '[Checkpoint] Currently relevant files.',
423
226
  },
424
227
  },
228
+ required: ['type'],
425
229
  },
426
- // 5. LOAD_CHECKPOINT - Resume previous session
427
- {
428
- name: 'load_checkpoint',
429
- description: `πŸ”„ Resume a previous session with full context.
430
-
431
- ⚑ TRIGGERS - Call this:
432
- β€’ At session start
433
- β€’ User says: "μ΄μ–΄μ„œ", "continue", "where were we", "μ§€λ‚œλ²ˆ"
434
- β€’ After long break from project
435
-
436
- πŸ”— AFTER LOADING:
437
- 1. Verify Evidence items (code may have changed!)
438
- 2. Run health checks from next_steps first
439
- 3. Call 'search' to refresh related decisions
440
-
441
- Returns: summary (4-section), next_steps (DoD + commands), open_files
442
-
443
- ⚠️ WARNING: Checkpoint may be stale. Always verify before continuing.`,
444
- inputSchema: {
445
- type: 'object',
446
- properties: {},
230
+ },
231
+ {
232
+ name: 'search',
233
+ description: memoryTools.suggest_decision.description,
234
+ inputSchema: {
235
+ type: 'object',
236
+ properties: {
237
+ query: {
238
+ type: 'string',
239
+ description: 'Search query. Semantic search finds related decisions.',
240
+ },
241
+ type: {
242
+ type: 'string',
243
+ enum: ['all', 'decision', 'checkpoint'],
244
+ description: "Filter by type. Default: 'all'",
245
+ },
246
+ limit: { type: 'number', description: 'Maximum results. Default: 10' },
247
+ scopes: memoryTools.save_decision.inputSchema.properties.scopes,
447
248
  },
448
249
  },
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
- })),
457
- ],
250
+ },
251
+ {
252
+ name: 'update',
253
+ description: memoryTools.update_outcome.description,
254
+ inputSchema: memoryTools.update_outcome.inputSchema,
255
+ },
256
+ ];
257
+
258
+ // All tools: legacy wrappers + all v2 tools from src/tools/
259
+ const v2Tools = Object.values(memoryTools)
260
+ .filter((t) => t.name && t.inputSchema)
261
+ .map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema }));
262
+
263
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
264
+ tools: [...legacyTools, ...v2Tools],
458
265
  }));
459
266
 
460
- // Handle tool execution - 4 core tools only
267
+ // Handle tool execution β€” legacy wrappers + v2 tools from src/tools/
461
268
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
462
269
  const { name, arguments: args } = request.params;
463
270
  const toolStart = Date.now();
@@ -467,6 +274,7 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
467
274
  let result;
468
275
 
469
276
  switch (name) {
277
+ // Legacy unified wrappers (backward compat)
470
278
  case 'save':
471
279
  result = await this.handleSave(args);
472
280
  break;
@@ -476,14 +284,8 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
476
284
  case 'update':
477
285
  result = await this.handleUpdate(args);
478
286
  break;
479
- case 'search_decisions_and_contracts':
480
- result = await this.handleSearchDecisionsAndContracts(args);
481
- break;
482
- case 'load_checkpoint':
483
- result = await memoryTools.load_checkpoint.handler(args);
484
- break;
485
287
  default:
486
- // Route to src/tools/ handlers
288
+ // All other tools β†’ src/tools/ handlers (single source of truth)
487
289
  if (memoryTools[name] && typeof memoryTools[name].handler === 'function') {
488
290
  result = await memoryTools[name].handler(args);
489
291
  } else {