Skip to main content
Glama

recall

Retrieve memories by topic, with automatic reinforcement of strong matches and pruning of irrelevant ones. Leave query empty to get all active memories ranked by relevance.

Instructions

Search memories by topic. Auto-reinforces strong matches. Auto-prunes dead memories. Leave query empty to get all active memories ranked by relevance.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryNoSearch query. Leave empty for all.
limitNoMax results. Default: 10.
min_relevanceNoMin relevance 0-1. Default: 0.05.

Implementation Reference

  • The handleRecall function is the core handler for the 'recall' tool. It loads memories, auto-prunes dead ones (relevance < 0.01), scores each memory by a combination of relevance decay and query similarity (using bigram overlap), filters/sorts by final_score, and auto-reinforces the top match if match_score > 0.25. Returns query info, results list, counts, and a message.
    function handleRecall(args) {
      const { query = '', limit = 10, min_relevance = 0.05 } = args;
      let memories = loadMemories();
      const now = Date.now();
      let pruned = 0;
    
      // Auto-prune dead memories on every recall
      const before = memories.length;
      memories = memories.filter(m => computeRelevance(m, now).relevance >= 0.01);
      pruned = before - memories.length;
      if (pruned > 0) saveMemories(memories);
    
      // Score all memories
      let scored = memories.map(m => {
        const rel = computeRelevance(m, now);
    
        let match_score = 0;
        if (query) {
          // Use similarity function instead of basic substring
          match_score = similarity(query, m.content);
          // Also check tags
          const tagText = (m.tags || []).join(' ');
          if (tagText) {
            match_score = Math.max(match_score, similarity(query, tagText) * 0.8);
          }
        } else {
          match_score = 1.0; // No query = return all
        }
    
        const final_score = rel.relevance * (0.3 + 0.7 * match_score);
    
        return {
          _memory: m, // internal ref for auto-reinforce
          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);
    
      // Auto-reinforce: if query matched well enough to be the top result, it's a mention
      if (query && scored.length > 0 && scored[0].match_score > 0.25) {
        reinforceMemory(scored[0]._memory);
        saveMemories(memories);
        scored[0].mention_count = scored[0]._memory.mention_count;
      }
    
      // Strip internal refs from output
      const results = scored.map(({ _memory, ...rest }) => rest);
    
      return {
        query: query || '(all)',
        results,
        total_memories: memories.length,
        returned: results.length,
        auto_pruned: pruned,
        message: results.length === 0
          ? 'No relevant memories found.'
          : `${results.length} memories found.${pruned > 0 ? ` ${pruned} dead memories pruned.` : ''}`
      };
    }
  • Tool definition schema for 'recall' in getToolDefinitions(). Name 'recall', description explaining auto-reinforce/auto-prune behavior, and inputSchema with optional query (string), limit (number, default 10), and min_relevance (number, default 0.05).
    {
      name: 'recall',
      description: 'Search memories by topic. Auto-reinforces strong matches. Auto-prunes dead memories. Leave query empty to get all active memories ranked by relevance.',
      inputSchema: {
        type: 'object',
        properties: {
          query: { type: 'string', description: 'Search query. Leave empty for all.' },
          limit: { type: 'number', description: 'Max results. Default: 10.' },
          min_relevance: { type: 'number', description: 'Min relevance 0-1. Default: 0.05.' }
        }
      }
    },
  • index.js:511-511 (registration)
    The 'recall' case in the tools/call switch statement inside handleRequest. Dispatches to handleRecall(args) when the tool name matches 'recall'.
    case 'recall': result = handleRecall(args); break;
  • The reinforceMemory helper function, shared by remember and recall. Increments mention_count, updates last_reinforced timestamp, and upgrades category from 'question' to 'interest' if mention_count >= 5.
    function reinforceMemory(memory) {
      memory.mention_count += 1;
      memory.last_reinforced = Date.now();
      if (memory.mention_count >= 5 && memory.category === 'question') {
        memory.category = 'interest';
        memory.base_weight = CATEGORY_CONFIG['interest'].base_weight;
        memory.decay_halflife_days = CATEGORY_CONFIG['interest'].decay_halflife_days;
      }
    }
  • The similarity function (tokenize + bigram-based overlap) used by handleRecall to match queries against memory content and tags.
    function tokenize(text) {
      return text.toLowerCase().replace(/[^a-z0-9 ]/g, '').split(/\s+/).filter(w => w.length > 1);
    }
    
    function similarity(a, b) {
      const wordsA = tokenize(a);
      const wordsB = tokenize(b);
      if (wordsA.length === 0 || wordsB.length === 0) return 0;
    
      // Build bigram sets (unigrams + bigrams)
      const setA = new Set(wordsA);
      const setB = new Set(wordsB);
      for (let i = 0; i < wordsA.length - 1; i++) setA.add(wordsA[i] + ' ' + wordsA[i + 1]);
      for (let i = 0; i < wordsB.length - 1; i++) setB.add(wordsB[i] + ' ' + wordsB[i + 1]);
    
      let overlap = 0;
      for (const gram of setA) {
        if (setB.has(gram)) overlap++;
      }
      return overlap / Math.max(setA.size, setB.size);
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description discloses important side effects: auto-reinforces strong matches and auto-prunes dead memories. This adds behavioral context beyond a simple search.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with purpose, no wasted words. Every sentence adds meaningful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema and no description of return format or error cases. While side effects are noted, the output nature is vaguely described as 'get all active memories'. Incomplete for full tool understanding.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, baseline 3. Description adds value by explaining empty query returns all active memories ranked by relevance, which supplements schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states 'Search memories by topic', specifying verb and resource. Leaving query empty for all memories distinguishes from sibling tools (forget, inspect, remember).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Description implies usage for searching memories and provides context for empty query, but lacks explicit when-not or alternatives. However, sibling tool names clarify scope.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ShipItAndPray/mcp-memory'

If you have feedback or need assistance with the MCP directory API, please join our Discord server