Skip to content

MCP memory_recall is aliased to smart-search and drops format param - full content unreachable via MCP #440

@MarvinFS

Description

@MarvinFS

Summary

In @agentmemory/mcp v0.9.17 the standalone proxy makes full memory content unreachable through MCP. Three related defects in src/mcp/standalone.ts:

  1. memory_recall and memory_smart_search are aliased to the same endpoint. Both hit /agentmemory/smart-search, which is compact-by-design (returns {obsId, sessionId, title, type, score, timestamp} only). memory_recall should hit /agentmemory/search, which honors the format parameter.
  2. The format parameter is advertised but silently dropped. src/mcp/tools-registry.ts:27-30 declares memory_recall accepts format: full | compact | narrative defaulting to full. The validator in src/mcp/standalone.ts only extracts query and limit - format never reaches the daemon.
  3. smart-search's expandIds parameter is unreachable via MCP. The validator doesn't extract it either, so the documented compact-then-expand pattern can only be used via direct REST.

Net effect: through MCP, callers only ever see titles + scores. The actual content IS in the database - calling /agentmemory/search directly with {"query":"...", "format":"full"} returns full observations including narrative, facts, rules, and concepts.

Reproduction

# Through MCP - compact only
{ "tool": "memory_recall", "arguments": { "query": "chatterbox", "format": "full" } }
# Returns: { mode: "compact", results: [{obsId, title, score, ...}] }  - no content

# Through REST directly - full content
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"query":"chatterbox","limit":5,"format":"full"}' \
  https://daemon/agentmemory/search
# Returns: { format: "full", results: [{observation: {title, concepts, facts: [full text], ...}}] }

Source locations

  • Validator that drops format: src/mcp/standalone.ts lines 113-120 (case memory_recall / memory_smart_search)
  • Proxy handler that calls wrong endpoint: src/mcp/standalone.ts lines 162-168
  • Tool schema declaring format: src/mcp/tools-registry.ts lines 13-50
  • Working REST handler honoring format: src/functions/search.ts line 178

Suggested fix

Split the two cases in both the validator and the proxy handler:

// validate()
case "memory_recall": {
  const query = args["query"];
  if (typeof query !== "string" || !query.trim()) throw new Error("query is required");
  v.query = query.trim();
  v.limit = parseLimit(args["limit"]);
  v.format = (args["format"] as string) || "full";
  v.tokenBudget = typeof args["token_budget"] === "number" ? args["token_budget"] : undefined;
  return v;
}
case "memory_smart_search": {
  // unchanged + add expandIds extraction
  v.query = (args["query"] as string)?.trim();
  v.limit = parseLimit(args["limit"]);
  v.expandIds = normalizeList(args["expandIds"]);
  return v;
}

// handleProxy()
case "memory_recall": {
  const result = await handle.call("/agentmemory/search", {
    method: "POST",
    body: JSON.stringify({
      query: v.query,
      limit: v.limit,
      format: v.format,
      token_budget: v.tokenBudget,
    }),
  });
  return textResponse(result, true);
}
case "memory_smart_search": {
  const result = await handle.call("/agentmemory/smart-search", {
    method: "POST",
    body: JSON.stringify({ query: v.query, limit: v.limit, expandIds: v.expandIds }),
  });
  return textResponse(result, true);
}

The handleLocal() path should mirror the same split so the in-process fallback also returns content rather than just titles.

Workaround for users

Until this ships, hit the REST API directly. A small bash helper:

curl -sk -H "Authorization: Bearer $AGENTMEMORY_SECRET" -H "Content-Type: application/json" \
  -d '{"query":"...","limit":5,"format":"full"}' \
  "$AGENTMEMORY_URL/agentmemory/search"

This returns the full observation including facts[], narrative, concepts, etc. - which is what every caller of memory_recall actually wants.

Why this matters

The whole point of a memory system is to return the memories. Returning rankings without content forces every caller into a second tool call to retrieve bodies - except that second tool call doesn't exist in the MCP surface (expandIds is also dropped), so today the only working path is direct REST. That defeats MCP integration for every downstream agent.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions