recall
Retrieve relevant memories from the MCP server using smart relevance ranking that prioritizes frequent interests while naturally deprioritizing old one-time questions.
Instructions
Retrieve relevant memories ranked by smart relevance (decay × frequency × match). Old one-time questions naturally rank low. Frequent interests rank high.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | What to search for. Leave empty to see all memories ranked by relevance. | |
| limit | No | Max results (default: 10) | |
| min_relevance | No | Minimum relevance score 0-1 (default: 0.05) |
Implementation Reference
- index.js:174-235 (handler)The `handleRecall` function implements the retrieval logic for the 'recall' tool, calculating relevance scores based on decay, frequency, and keyword matching.
function handleRecall(args) { const { query = '', limit = 10, min_relevance = 0.05 } = args; const memories = loadMemories(); const now = Date.now(); // Score all memories let scored = memories.map(m => { const rel = computeRelevance(m, now); // Text match bonus let match_score = 0; if (query) { const q = query.toLowerCase(); const c = m.content.toLowerCase(); const t = (m.tags || []).join(' ').toLowerCase(); if (c.includes(q)) match_score = 1.0; else if (t.includes(q)) match_score = 0.8; else { // Word overlap const qWords = q.split(/\s+/); const cWords = c.split(/\s+/); const overlap = qWords.filter(w => cWords.some(cw => cw.includes(w))).length; match_score = overlap / qWords.length; } } else { match_score = 1.0; // No query = return all } const final_score = rel.relevance * (0.3 + 0.7 * match_score); return { id: m.id, content: m.content, category: m.category, tags: m.tags, mention_count: m.mention_count, relevance: rel.relevance, match_score: Math.round(match_score * 100) / 100, final_score: Math.round(final_score * 1000) / 1000, age_days: rel.age_days, status: rel.status, decay: rel.decay, }; }); // Filter and sort scored = scored .filter(s => s.final_score >= min_relevance) .sort((a, b) => b.final_score - a.final_score) .slice(0, limit); return { query: query || '(all)', results: scored, total_memories: memories.length, returned: scored.length, message: scored.length === 0 ? 'No relevant memories found. Either none stored or all have decayed below threshold.' : `${scored.length} memories found, ranked by relevance × match.` }; } - index.js:386-396 (registration)The definition of the 'recall' tool, including its schema and description.
name: 'recall', description: 'Retrieve relevant memories ranked by smart relevance (decay × frequency × match). Old one-time questions naturally rank low. Frequent interests rank high.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'What to search for. Leave empty to see all memories ranked by relevance.' }, limit: { type: 'number', description: 'Max results (default: 10)' }, min_relevance: { type: 'number', description: 'Minimum relevance score 0-1 (default: 0.05)' } } } }, - index.js:462-462 (registration)The tool handler dispatch mapping for 'recall'.
case 'recall': result = handleRecall(args); break;