Before submitting
📝 Manual Bug Report
Bug Description
observation_add and memory_add MCP tools always fail with a 400 ValidationError in server-beta mode. The content field is provided by the caller but arrives as undefined at the server.
Server beta POST /v1/memories returned 400:
{"error":"ValidationError","issues":[{"expected":"string","code":"invalid_type","path":["content"],"message":"Invalid input: expected string, received undefined"}]}
Root cause: In mcp-server.cjs, the buildAddObservationPayload method in the ServerBetaClient class maps the content value to the legacy field name narrative instead of content:
buildAddObservationPayload(e) {
let r = e.content, // ← reads content correctly
n = e.kind ?? "manual",
...
return {
projectId: e.projectId,
kind: n,
type: n,
narrative: r, // ← BUG: should be `content: r`
...
}
}
The server-beta POST /v1/memories endpoint expects content, not narrative. The field narrative is the legacy worker-mode name and was not updated when the server-beta payload builder was written.
Read operations (observation_search, get_observations, timeline) are unaffected — they use a separate buildSearchPayload method that doesn't touch the content/narrative field.
Steps to Reproduce
- Configure claude-mem in server-beta mode (PostgreSQL + Valkey/BullMQ)
- Call the
observation_add MCP tool with a content parameter
- Receive 400 ValidationError —
content is undefined
- Same result with
memory_add (and its narrative legacy alias)
Expected Behavior
The observation should be created and returned with the provided content.
Environment
- Claude-mem version: 13.6.1 (latest on npm)
- Claude Code version: 2.1.179
- OS: Linux 6.12.90+deb13.1-amd64 x86_64
- Platform: Debian 13, server-beta mode with PostgreSQL + Valkey
Logs
The 400 error is surfaced client-side in the MCP tool result, not in the worker log. Worker log shows no corresponding error for these calls — the request is rejected by the server-beta HTTP layer before reaching the queue.
Server beta POST /v1/memories returned 400:
{"error":"ValidationError","issues":[{"expected":"string","code":"invalid_type","path":["content"],"message":"Invalid input: expected string, received undefined"}]}
Additional Context
- Fix confirmed locally: changing
narrative: r to content: r in buildAddObservationPayload resolves the issue — write-read round-trip verified after patching and restarting the session.
- Only the write path is affected. All read/search tools work correctly.
- The
memory_add compatibility alias constructs content from t?.content ?? t?.narrative ?? "" then feeds it into the same broken buildAddObservationPayload, so it fails identically.
Before submitting
📝 Manual Bug Report
Bug Description
observation_addandmemory_addMCP tools always fail with a 400 ValidationError in server-beta mode. Thecontentfield is provided by the caller but arrives asundefinedat the server.Root cause: In
mcp-server.cjs, thebuildAddObservationPayloadmethod in theServerBetaClientclass maps the content value to the legacy field namenarrativeinstead ofcontent:The server-beta
POST /v1/memoriesendpoint expectscontent, notnarrative. The fieldnarrativeis the legacy worker-mode name and was not updated when the server-beta payload builder was written.Read operations (
observation_search,get_observations,timeline) are unaffected — they use a separatebuildSearchPayloadmethod that doesn't touch the content/narrative field.Steps to Reproduce
observation_addMCP tool with acontentparametercontentisundefinedmemory_add(and itsnarrativelegacy alias)Expected Behavior
The observation should be created and returned with the provided content.
Environment
Logs
The 400 error is surfaced client-side in the MCP tool result, not in the worker log. Worker log shows no corresponding error for these calls — the request is rejected by the server-beta HTTP layer before reaching the queue.
Additional Context
narrative: rtocontent: rinbuildAddObservationPayloadresolves the issue — write-read round-trip verified after patching and restarting the session.memory_addcompatibility alias constructscontentfromt?.content ?? t?.narrative ?? ""then feeds it into the same brokenbuildAddObservationPayload, so it fails identically.