@jungjaehoon/mama-server 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/package.json +53 -0
- package/src/mama/config-loader.js +218 -0
- package/src/mama/db-adapter/README.md +105 -0
- package/src/mama/db-adapter/base-adapter.js +91 -0
- package/src/mama/db-adapter/index.js +31 -0
- package/src/mama/db-adapter/sqlite-adapter.js +342 -0
- package/src/mama/db-adapter/statement.js +127 -0
- package/src/mama/db-manager.js +584 -0
- package/src/mama/debug-logger.js +78 -0
- package/src/mama/decision-formatter.js +1180 -0
- package/src/mama/decision-tracker.js +565 -0
- package/src/mama/embedding-cache.js +221 -0
- package/src/mama/embeddings.js +265 -0
- package/src/mama/hook-metrics.js +403 -0
- package/src/mama/mama-api.js +913 -0
- package/src/mama/memory-inject.js +243 -0
- package/src/mama/memory-store.js +89 -0
- package/src/mama/ollama-client.js +387 -0
- package/src/mama/outcome-tracker.js +349 -0
- package/src/mama/query-intent.js +236 -0
- package/src/mama/relevance-scorer.js +283 -0
- package/src/mama/time-formatter.js +82 -0
- package/src/mama/transparency-banner.js +301 -0
- package/src/server.js +290 -0
- package/src/tools/checkpoint-tools.js +76 -0
- package/src/tools/index.js +54 -0
- package/src/tools/list-decisions.js +76 -0
- package/src/tools/recall-decision.js +75 -0
- package/src/tools/save-decision.js +113 -0
- package/src/tools/suggest-decision.js +84 -0
- package/src/tools/update-outcome.js +128 -0
package/src/server.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MAMA MCP Server
|
|
5
|
+
*
|
|
6
|
+
* Memory-Augmented MCP Assistant - Standalone MCP Server
|
|
7
|
+
*
|
|
8
|
+
* This server provides MCP tools for decision tracking, semantic search,
|
|
9
|
+
* and decision graph navigation across Claude Code and Claude Desktop.
|
|
10
|
+
*
|
|
11
|
+
* Architecture:
|
|
12
|
+
* - Stdio transport (standard MCP pattern)
|
|
13
|
+
* - SQLite + sqlite-vec for decision storage
|
|
14
|
+
* - Transformers.js for local embeddings
|
|
15
|
+
* - No network dependencies (100% local)
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* node src/server.js # Direct execution
|
|
19
|
+
* mama-server # Via bin (npm install -g)
|
|
20
|
+
* npx @jungjaehoon/mama-server # Via npx
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
24
|
+
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
25
|
+
const {
|
|
26
|
+
CallToolRequestSchema,
|
|
27
|
+
ListToolsRequestSchema,
|
|
28
|
+
} = require('@modelcontextprotocol/sdk/types.js');
|
|
29
|
+
|
|
30
|
+
// Import MAMA tools
|
|
31
|
+
const { saveDecisionTool } = require('./tools/save-decision.js');
|
|
32
|
+
const { recallDecisionTool } = require('./tools/recall-decision.js');
|
|
33
|
+
const { suggestDecisionTool } = require('./tools/suggest-decision.js');
|
|
34
|
+
const { listDecisionsTool } = require('./tools/list-decisions.js');
|
|
35
|
+
const { updateOutcomeTool } = require('./tools/update-outcome.js');
|
|
36
|
+
const { saveCheckpointTool, loadCheckpointTool } = require('./tools/checkpoint-tools.js');
|
|
37
|
+
|
|
38
|
+
// Import core modules
|
|
39
|
+
const { initDB } = require('./mama/db-manager.js');
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* MAMA MCP Server Class
|
|
43
|
+
*/
|
|
44
|
+
class MAMAServer {
|
|
45
|
+
constructor() {
|
|
46
|
+
this.server = new Server(
|
|
47
|
+
{
|
|
48
|
+
name: 'mama-server',
|
|
49
|
+
version: '1.0.0',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
capabilities: {
|
|
53
|
+
tools: {},
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
this.setupHandlers();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
setupHandlers() {
|
|
62
|
+
// List available tools
|
|
63
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
64
|
+
tools: [
|
|
65
|
+
{
|
|
66
|
+
name: 'save_decision',
|
|
67
|
+
description: 'Save a decision or insight to MAMA\'s memory for future reference.',
|
|
68
|
+
inputSchema: {
|
|
69
|
+
type: 'object',
|
|
70
|
+
properties: {
|
|
71
|
+
topic: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
description: 'Decision topic identifier (e.g., \'auth_strategy\'). Use lowercase with underscores.',
|
|
74
|
+
},
|
|
75
|
+
decision: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
description: 'The decision made (e.g., \'Use JWT with refresh tokens\').',
|
|
78
|
+
},
|
|
79
|
+
reasoning: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
description: 'Why this decision was made. REQUIRED - explain the context and rationale.',
|
|
82
|
+
},
|
|
83
|
+
confidence: {
|
|
84
|
+
type: 'number',
|
|
85
|
+
description: 'Confidence score 0.0-1.0. Default: 0.5',
|
|
86
|
+
minimum: 0,
|
|
87
|
+
maximum: 1,
|
|
88
|
+
},
|
|
89
|
+
type: {
|
|
90
|
+
type: 'string',
|
|
91
|
+
enum: ['user_decision', 'assistant_insight'],
|
|
92
|
+
description: 'Decision type. Default: \'user_decision\'',
|
|
93
|
+
},
|
|
94
|
+
outcome: {
|
|
95
|
+
type: 'string',
|
|
96
|
+
enum: ['pending', 'success', 'failure', 'partial', 'superseded'],
|
|
97
|
+
description: 'Outcome status. Default: \'pending\'',
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
required: ['topic', 'decision', 'reasoning'],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'recall_decision',
|
|
105
|
+
description: 'Recall full decision history for a specific topic.',
|
|
106
|
+
inputSchema: {
|
|
107
|
+
type: 'object',
|
|
108
|
+
properties: {
|
|
109
|
+
topic: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
description: 'Decision topic to recall',
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
required: ['topic'],
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'suggest_decision',
|
|
119
|
+
description: 'Auto-suggest relevant past decisions based on user question.',
|
|
120
|
+
inputSchema: {
|
|
121
|
+
type: 'object',
|
|
122
|
+
properties: {
|
|
123
|
+
userQuestion: {
|
|
124
|
+
type: 'string',
|
|
125
|
+
description: 'User\'s question or intent',
|
|
126
|
+
},
|
|
127
|
+
recencyWeight: {
|
|
128
|
+
type: 'number',
|
|
129
|
+
description: 'Weight for recency (0-1). Default: 0.3',
|
|
130
|
+
minimum: 0,
|
|
131
|
+
maximum: 1,
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
required: ['userQuestion'],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'list_decisions',
|
|
139
|
+
description: 'List recent decisions with optional limit',
|
|
140
|
+
inputSchema: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
properties: {
|
|
143
|
+
limit: {
|
|
144
|
+
type: 'number',
|
|
145
|
+
description: 'Maximum number of decisions (default: 10)',
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: 'update_outcome',
|
|
152
|
+
description: 'Update the outcome status of an existing decision',
|
|
153
|
+
inputSchema: {
|
|
154
|
+
type: 'object',
|
|
155
|
+
properties: {
|
|
156
|
+
topic: {
|
|
157
|
+
type: 'string',
|
|
158
|
+
description: 'Decision topic to update',
|
|
159
|
+
},
|
|
160
|
+
outcome: {
|
|
161
|
+
type: 'string',
|
|
162
|
+
enum: ['pending', 'success', 'failure', 'partial', 'superseded'],
|
|
163
|
+
description: 'New outcome status',
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
required: ['topic', 'outcome'],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'save_checkpoint',
|
|
171
|
+
description: 'Save the current session state (checkpoint) to MAMA memory. Use this when ending a session or reaching a major milestone so work can be resumed later.',
|
|
172
|
+
inputSchema: {
|
|
173
|
+
type: 'object',
|
|
174
|
+
properties: {
|
|
175
|
+
summary: {
|
|
176
|
+
type: 'string',
|
|
177
|
+
description: 'Summary of the current session state, what was accomplished, and what is pending.',
|
|
178
|
+
},
|
|
179
|
+
open_files: {
|
|
180
|
+
type: 'array',
|
|
181
|
+
items: { type: 'string' },
|
|
182
|
+
description: 'List of currently relevant or open files.',
|
|
183
|
+
},
|
|
184
|
+
next_steps: {
|
|
185
|
+
type: 'string',
|
|
186
|
+
description: 'Clear instructions for the next session on what to do next.',
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
required: ['summary'],
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: 'load_checkpoint',
|
|
194
|
+
description: 'Load the latest active session checkpoint. Use this at the start of a new session to resume work seamlessly.',
|
|
195
|
+
inputSchema: {
|
|
196
|
+
type: 'object',
|
|
197
|
+
properties: {},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
}));
|
|
202
|
+
|
|
203
|
+
// Handle tool execution
|
|
204
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
205
|
+
const { name, arguments: args } = request.params;
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
let result;
|
|
209
|
+
|
|
210
|
+
switch (name) {
|
|
211
|
+
case 'save_decision':
|
|
212
|
+
result = await saveDecisionTool.handler(args);
|
|
213
|
+
break;
|
|
214
|
+
case 'recall_decision':
|
|
215
|
+
result = await recallDecisionTool.handler(args);
|
|
216
|
+
break;
|
|
217
|
+
case 'suggest_decision':
|
|
218
|
+
result = await suggestDecisionTool.handler(args);
|
|
219
|
+
break;
|
|
220
|
+
case 'list_decisions':
|
|
221
|
+
result = await listDecisionsTool.handler(args);
|
|
222
|
+
break;
|
|
223
|
+
case 'update_outcome':
|
|
224
|
+
result = await updateOutcomeTool.handler(args);
|
|
225
|
+
break;
|
|
226
|
+
case 'save_checkpoint':
|
|
227
|
+
result = await saveCheckpointTool.handler(args);
|
|
228
|
+
break;
|
|
229
|
+
case 'load_checkpoint':
|
|
230
|
+
result = await loadCheckpointTool.handler(args);
|
|
231
|
+
break;
|
|
232
|
+
default:
|
|
233
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
content: [
|
|
238
|
+
{
|
|
239
|
+
type: 'text',
|
|
240
|
+
text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
};
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error('[MAMA MCP] Tool execution error:', error);
|
|
246
|
+
return {
|
|
247
|
+
content: [
|
|
248
|
+
{
|
|
249
|
+
type: 'text',
|
|
250
|
+
text: `Error: ${error.message}`,
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
isError: true,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async start() {
|
|
260
|
+
try {
|
|
261
|
+
// Initialize database
|
|
262
|
+
console.error('[MAMA MCP] Initializing database...');
|
|
263
|
+
await initDB();
|
|
264
|
+
console.error('[MAMA MCP] Database initialized');
|
|
265
|
+
|
|
266
|
+
// Start server with stdio transport
|
|
267
|
+
const transport = new StdioServerTransport();
|
|
268
|
+
await this.server.connect(transport);
|
|
269
|
+
|
|
270
|
+
// Log to stderr (stdout is for MCP JSON-RPC)
|
|
271
|
+
console.error('[MAMA MCP] Server started successfully');
|
|
272
|
+
console.error('[MAMA MCP] Listening on stdio transport');
|
|
273
|
+
console.error('[MAMA MCP] Ready to accept connections');
|
|
274
|
+
} catch (error) {
|
|
275
|
+
console.error('[MAMA MCP] Failed to start server:', error);
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Start server if run directly
|
|
282
|
+
if (require.main === module) {
|
|
283
|
+
const server = new MAMAServer();
|
|
284
|
+
server.start().catch((error) => {
|
|
285
|
+
console.error('[MAMA MCP] Fatal error:', error);
|
|
286
|
+
process.exit(1);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
module.exports = { MAMAServer };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const { saveCheckpoint, loadCheckpoint } = require('../mama/mama-api');
|
|
2
|
+
|
|
3
|
+
const saveCheckpointTool = {
|
|
4
|
+
name: 'save_checkpoint',
|
|
5
|
+
description: 'Save the current session state (checkpoint) to MAMA memory. Use this when ending a session or reaching a major milestone so work can be resumed later.',
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: 'object',
|
|
8
|
+
properties: {
|
|
9
|
+
summary: {
|
|
10
|
+
type: 'string',
|
|
11
|
+
description: 'Summary of the current session state, what was accomplished, and what is pending.',
|
|
12
|
+
},
|
|
13
|
+
open_files: {
|
|
14
|
+
type: 'array',
|
|
15
|
+
items: { type: 'string' },
|
|
16
|
+
description: 'List of currently relevant or open files.',
|
|
17
|
+
},
|
|
18
|
+
next_steps: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'Clear instructions for the next session on what to do next.',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
required: ['summary'],
|
|
24
|
+
},
|
|
25
|
+
handler: async (args) => {
|
|
26
|
+
const { summary, open_files, next_steps } = args;
|
|
27
|
+
const id = await saveCheckpoint(summary, open_files, next_steps);
|
|
28
|
+
return {
|
|
29
|
+
content: [
|
|
30
|
+
{
|
|
31
|
+
type: 'text',
|
|
32
|
+
text: `✅ Checkpoint saved (ID: ${id})\nSummary: ${summary}`,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const loadCheckpointTool = {
|
|
40
|
+
name: 'load_checkpoint',
|
|
41
|
+
description: 'Load the latest active session checkpoint. Use this at the start of a new session to resume work seamlessly.',
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: 'object',
|
|
44
|
+
properties: {},
|
|
45
|
+
},
|
|
46
|
+
handler: async () => {
|
|
47
|
+
const checkpoint = await loadCheckpoint();
|
|
48
|
+
if (!checkpoint) {
|
|
49
|
+
return {
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: 'text',
|
|
53
|
+
text: 'ℹ️ No active checkpoint found.',
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{
|
|
62
|
+
type: 'text',
|
|
63
|
+
text: `🔄 Resuming Session (from ${new Date(checkpoint.timestamp).toLocaleString()})\n\n` +
|
|
64
|
+
`📝 Summary: ${checkpoint.summary}\n` +
|
|
65
|
+
`📂 Files: ${JSON.stringify(checkpoint.open_files)}\n` +
|
|
66
|
+
`👉 Next Steps: ${checkpoint.next_steps || 'None'}`,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
module.exports = {
|
|
74
|
+
saveCheckpointTool,
|
|
75
|
+
loadCheckpointTool,
|
|
76
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MAMA Memory Tools
|
|
3
|
+
*
|
|
4
|
+
* Story M1.3: MCP Tool Surface Port
|
|
5
|
+
* Story M1.5: update_outcome tool added
|
|
6
|
+
* MCP tool wrappers for MAMA's memory system
|
|
7
|
+
*
|
|
8
|
+
* Tools:
|
|
9
|
+
* - save_decision: Save decisions/insights to memory ✅
|
|
10
|
+
* - recall_decision: Retrieve decision history by topic ✅
|
|
11
|
+
* - suggest_decision: Semantic search for relevant decisions ✅
|
|
12
|
+
* - list_decisions: List recent decisions chronologically ✅
|
|
13
|
+
* - update_outcome: Update decision outcome ✅
|
|
14
|
+
*
|
|
15
|
+
* @module tools
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const { saveDecisionTool } = require('./save-decision.js');
|
|
19
|
+
const { recallDecisionTool } = require('./recall-decision.js');
|
|
20
|
+
const { suggestDecisionTool } = require('./suggest-decision.js');
|
|
21
|
+
const { listDecisionsTool } = require('./list-decisions.js');
|
|
22
|
+
const { updateOutcomeTool } = require('./update-outcome.js');
|
|
23
|
+
const { saveCheckpointTool, loadCheckpointTool } = require('./checkpoint-tools.js');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create all MAMA memory tools
|
|
27
|
+
*
|
|
28
|
+
* Database location: ~/.claude/mama-memory.db (or MAMA_DB_PATH env var)
|
|
29
|
+
*
|
|
30
|
+
* @returns Object with tool definitions
|
|
31
|
+
*/
|
|
32
|
+
function createMemoryTools() {
|
|
33
|
+
return {
|
|
34
|
+
save_decision: saveDecisionTool,
|
|
35
|
+
recall_decision: recallDecisionTool,
|
|
36
|
+
suggest_decision: suggestDecisionTool,
|
|
37
|
+
list_decisions: listDecisionsTool,
|
|
38
|
+
update_outcome: updateOutcomeTool,
|
|
39
|
+
save_checkpoint: saveCheckpointTool,
|
|
40
|
+
load_checkpoint: loadCheckpointTool,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Export individual tool creators for testing
|
|
45
|
+
module.exports = {
|
|
46
|
+
createMemoryTools,
|
|
47
|
+
saveDecisionTool,
|
|
48
|
+
recallDecisionTool,
|
|
49
|
+
suggestDecisionTool,
|
|
50
|
+
listDecisionsTool,
|
|
51
|
+
updateOutcomeTool,
|
|
52
|
+
saveCheckpointTool,
|
|
53
|
+
loadCheckpointTool,
|
|
54
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool: list_decisions
|
|
3
|
+
*
|
|
4
|
+
* Lists recent decisions in chronological order.
|
|
5
|
+
* Returns formatted list with time, type, topic, preview, confidence, and status.
|
|
6
|
+
*
|
|
7
|
+
* Flow:
|
|
8
|
+
* 1. User (via Claude Desktop): "Show me recent decisions"
|
|
9
|
+
* 2. Claude: Calls list_decisions MCP tool
|
|
10
|
+
* 3. Tool: Validates input, calls mama.list()
|
|
11
|
+
* 4. mama.list(): Queries recent decisions + formats as markdown
|
|
12
|
+
* 5. Tool: Returns formatted markdown response
|
|
13
|
+
*
|
|
14
|
+
* @module list-decisions
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
// Import MAMA API from core directory
|
|
20
|
+
const mama = require('../mama/mama-api.js');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* List decisions tool definition
|
|
24
|
+
*/
|
|
25
|
+
const listDecisionsTool = {
|
|
26
|
+
name: 'list_decisions',
|
|
27
|
+
description:
|
|
28
|
+
'List recent decisions in chronological order. Returns formatted list showing time, type (user/assistant), topic, preview, confidence, and status. Use this to see recent activity or find decisions by browsing.',
|
|
29
|
+
inputSchema: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
limit: {
|
|
33
|
+
type: 'number',
|
|
34
|
+
description: 'Maximum number of decisions to return (default: 20, max: 100)',
|
|
35
|
+
minimum: 1,
|
|
36
|
+
maximum: 100,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
required: [],
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
async handler(params, context) {
|
|
43
|
+
const { limit = 20 } = params || {};
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
// Validation: Limit range check
|
|
47
|
+
if (limit < 1 || limit > 100) {
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
message: '❌ Validation error: Limit must be between 1 and 100',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Call MAMA API with markdown format for human display
|
|
55
|
+
// mama.list() defaults to JSON (LLM-first), but we need markdown for user display
|
|
56
|
+
const list = await mama.list({ limit, format: 'markdown' });
|
|
57
|
+
|
|
58
|
+
// Return success response with formatted list
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
list,
|
|
62
|
+
message: list, // For backward compatibility with MCP response format
|
|
63
|
+
};
|
|
64
|
+
} catch (error) {
|
|
65
|
+
// Error handling: Return user-friendly message
|
|
66
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
message: `❌ Failed to list decisions: ${errorMessage}`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
module.exports = { listDecisionsTool };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool: recall_decision
|
|
3
|
+
*
|
|
4
|
+
* Story M1.3: MCP Tool - recall_decision (ported from mcp-server)
|
|
5
|
+
* Priority: P1 (Core Feature)
|
|
6
|
+
*
|
|
7
|
+
* Recalls full decision history for a specific topic.
|
|
8
|
+
* This is a wrapper around the existing mama.recall() API.
|
|
9
|
+
*
|
|
10
|
+
* Flow:
|
|
11
|
+
* 1. User (via Claude Desktop): "Recall my decision about auth strategy"
|
|
12
|
+
* 2. Claude: Calls recall_decision MCP tool
|
|
13
|
+
* 3. Tool: Validates input, calls mama.recall()
|
|
14
|
+
* 4. mama.recall(): Queries decision history + formats as markdown
|
|
15
|
+
* 5. Tool: Returns formatted markdown response
|
|
16
|
+
*
|
|
17
|
+
* @module recall-decision
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const mama = require('../mama/mama-api.js');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Recall decision tool definition
|
|
24
|
+
*/
|
|
25
|
+
const recallDecisionTool = {
|
|
26
|
+
name: 'recall_decision',
|
|
27
|
+
description:
|
|
28
|
+
'Recall full decision history for a specific topic. Returns all past decisions on this topic in chronological order with reasoning, confidence, and outcomes. Use this when you need to review previous decisions, understand decision evolution, or check current position on a topic.\n\n⚡ GRAPH TRAVERSAL: When the same topic is reused across multiple decisions, this tool automatically shows the decision evolution chain (supersedes graph), enabling Learn/Unlearn/Relearn workflows.',
|
|
29
|
+
inputSchema: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
topic: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
description:
|
|
35
|
+
"Decision topic to recall (e.g., 'auth_strategy', 'mesh_detail_choice'). Use the EXACT SAME topic name used in save_decision to see full decision evolution graph. Different topic names will show separate, disconnected decisions.",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
required: ['topic'],
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
async handler(params, context) {
|
|
42
|
+
const { topic } = params || {};
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
// Validation: Non-empty string check
|
|
46
|
+
if (!topic || typeof topic !== 'string' || topic.trim() === '') {
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
message: '❌ Validation error: Topic must be a non-empty string',
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Call MAMA API with markdown format for human display
|
|
54
|
+
// mama.recall() defaults to JSON (LLM-first), but we need markdown for user display
|
|
55
|
+
const history = await mama.recall(topic, { format: 'markdown' });
|
|
56
|
+
|
|
57
|
+
// Return success response with formatted history
|
|
58
|
+
return {
|
|
59
|
+
success: true,
|
|
60
|
+
history,
|
|
61
|
+
message: history, // For backward compatibility with MCP response format
|
|
62
|
+
};
|
|
63
|
+
} catch (error) {
|
|
64
|
+
// Error handling: Return user-friendly message
|
|
65
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
message: `❌ Failed to recall decisions: ${errorMessage}`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
module.exports = { recallDecisionTool };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool: save_decision
|
|
3
|
+
*
|
|
4
|
+
* Story M1.3: MCP Tool - save_decision (ported from mcp-server)
|
|
5
|
+
* Priority: P1 (Core Feature)
|
|
6
|
+
*
|
|
7
|
+
* Saves decisions and insights to MAMA's memory for future reference.
|
|
8
|
+
*
|
|
9
|
+
* @module save-decision
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const mama = require('../mama/mama-api.js');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Save decision tool definition
|
|
16
|
+
*/
|
|
17
|
+
const saveDecisionTool = {
|
|
18
|
+
name: 'save_decision',
|
|
19
|
+
description:
|
|
20
|
+
"Save a decision or insight to MAMA's memory for future reference. Use this when the user explicitly wants to remember something important (e.g., architectural decisions, parameter choices, lessons learned). The decision will be stored with semantic embeddings for later retrieval.\n\n⚡ IMPORTANT - Graph Connectivity: Reuse the SAME topic name for related decisions to create decision graphs (supersedes/refines/contradicts edges). Example: Use 'auth_strategy' for all authentication decisions, not 'auth_strategy_v1', 'auth_strategy_v2'. This enables Learn/Unlearn/Relearn workflows.",
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
topic: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description:
|
|
27
|
+
"Decision topic identifier (e.g., 'auth_strategy', 'mesh_detail_choice'). Use lowercase with underscores. Max 200 characters.\n\n⚡ REUSE SAME TOPIC for related decisions to create supersedes edges.",
|
|
28
|
+
},
|
|
29
|
+
decision: {
|
|
30
|
+
type: 'string',
|
|
31
|
+
description: "The decision made (e.g., 'Use JWT with refresh tokens'). Max 2000 characters.",
|
|
32
|
+
},
|
|
33
|
+
reasoning: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
description:
|
|
36
|
+
'Why this decision was made. This is REQUIRED - never leave empty. Explain the context, alternatives considered, and rationale. IMPORTANT: Use English for better semantic search and relationship detection (e.g., use "instead of", "contrary to", "replaces" for conflicting decisions). Max 5000 characters.',
|
|
37
|
+
},
|
|
38
|
+
confidence: {
|
|
39
|
+
type: 'number',
|
|
40
|
+
description:
|
|
41
|
+
'Confidence score 0.0-1.0. Use 0.9 for high confidence, 0.8 for medium, 0.5 for experimental. Default: 0.5',
|
|
42
|
+
minimum: 0,
|
|
43
|
+
maximum: 1,
|
|
44
|
+
},
|
|
45
|
+
type: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
enum: ['user_decision', 'assistant_insight'],
|
|
48
|
+
description: "'user_decision' if user explicitly decided, 'assistant_insight' if this is Claude's suggestion. Default: 'user_decision'",
|
|
49
|
+
},
|
|
50
|
+
outcome: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
enum: ['pending', 'success', 'failure', 'partial', 'superseded'],
|
|
53
|
+
description:
|
|
54
|
+
"Decision outcome status. Use 'pending' for new decisions (default), 'success' when confirmed working, 'failure' when approach failed.",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
required: ['topic', 'decision', 'reasoning'],
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
async handler(params, context) {
|
|
61
|
+
const {
|
|
62
|
+
topic,
|
|
63
|
+
decision,
|
|
64
|
+
reasoning,
|
|
65
|
+
confidence = 0.5,
|
|
66
|
+
type = 'user_decision',
|
|
67
|
+
outcome = 'pending',
|
|
68
|
+
} = params || {};
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
// Validation
|
|
72
|
+
if (!topic || !decision || !reasoning) {
|
|
73
|
+
return {
|
|
74
|
+
success: false,
|
|
75
|
+
message: '❌ Validation error: topic, decision, and reasoning are required',
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (topic.length > 200 || decision.length > 2000 || reasoning.length > 5000) {
|
|
80
|
+
return {
|
|
81
|
+
success: false,
|
|
82
|
+
message: '❌ Validation error: Field length exceeded (topic≤200, decision≤2000, reasoning≤5000)',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Call MAMA API (mama.save will handle outcome mapping to DB format)
|
|
87
|
+
const result = await mama.save({
|
|
88
|
+
topic,
|
|
89
|
+
decision,
|
|
90
|
+
reasoning,
|
|
91
|
+
confidence,
|
|
92
|
+
user_involvement: type,
|
|
93
|
+
outcome,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
success: true,
|
|
98
|
+
decision_id: result.id,
|
|
99
|
+
topic: topic,
|
|
100
|
+
message: `✅ Decision saved successfully (ID: ${result.id})`,
|
|
101
|
+
recall_command: `To recall: mama.recall('${topic}')`,
|
|
102
|
+
};
|
|
103
|
+
} catch (error) {
|
|
104
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
message: `❌ Failed to save decision: ${errorMessage}`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
module.exports = { saveDecisionTool };
|