Skip to content

MCP mem_save tool silently drops observation body — content column always empty #363

@AshrafAKRahman

Description

@AshrafAKRahman

Bug Summary

The MCP mem_save tool handler returns success (with a valid observation ID) but does not write the observation parameter body to the SQLite content column. Every save via MCP results in an empty content field. The CLI engram save command writes content correctly — the bug is isolated to the MCP JSON-RPC code path.

Version

engram 1.15.11 (Homebrew, macOS arm64)

Previously reproduced on 1.15.8 as well. Upgrading to 1.15.11 did not fix it.

Steps to Reproduce

  1. Start an MCP session: engram mcp --tools=agent
  2. Send a mem_save tool call with an observation parameter containing text
  3. Tool returns success: {"id": 103, "result": "Memory saved: \"Title\" (manual)"}
  4. Check SQLite: sqlite3 ~/.engram/engram.db "SELECT id, length(content) FROM observations WHERE id = 103;"
  5. Result: 103|0 — content is empty

Expected Behavior

The observation parameter value should be written to the content column in the observations table.

Actual Behavior

  • content column is empty (length 0)
  • title column IS written correctly
  • type, project, scope, sync_id — all written correctly
  • Only content is silently dropped

Impact

  • Data loss: All observations saved via MCP have empty bodies
  • Cloud sync blocked: sync_mutations reference observations with missing content field, causing engram doctor to report sync_mutation_required_fields as blocked
  • Search degraded: FTS index has no content to match against, so mem_search can't find observations by body text

In our case, this caused 65+ broken sync mutations and 10 irrecoverably lost observations before we noticed (the tool was returning success, so there was no indication of failure).

CLI vs MCP Comparison

Path Title written? Content written?
engram save "text" --project X Yes Yes
MCP mem_save tool Yes No

Workaround

We built a Claude Code PostToolUse hook that fires after every mem_save call, reads back the observation from SQLite, and if content is empty, auto-repairs by writing the original observation text from the MCP tool_input directly into the database and fixing the corresponding sync_mutation payload.

Environment

  • macOS 15 (Darwin 25.3.0, arm64)
  • engram 1.15.11 installed via brew install gentleman-programming/tap/engram
  • MCP server started as: engram mcp --tools=agent
  • Claude Code (Anthropic CLI) as the MCP client

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions