Bug Description
update_memory and delete_memory MCP tools silently fail when operating on memories with Snowflake IDs that exceed JavaScript's Number.MAX_SAFE_INTEGER (2^53 − 1 = 9007199254740991). All Snowflake IDs in this system are 64-bit integers (e.g., 725653563933458432), which are approximately 10× larger than this limit.
Root Cause
The bug spans two layers:
1. MCP Tool Schema — int declared as JSON integer
In src/powermem/mcp/server.py, memory_id parameters are typed as Python int:
# Lines 215, 238, 269, 517
async def get_memory_by_id(memory_id: int, ...): ...
async def update_memory(memory_id: int, ...): ...
async def delete_memory(memory_id: int, ...): ...
async def delete_memory_with_profile(memory_id: int, ...): ...
FastMCP auto-generates the JSON Schema from these type hints, emitting "type": "integer" for memory_id. This causes MCP clients (including Claude Code, which runs in a JavaScript/V8 environment) to parse the returned memory_id as a JSON number.
2. MCP Response Serialization — json.dumps() emits bare JSON numbers
The _fmt() helper (line 99–101 of server.py) serializes responses with standard json.dumps():
def _fmt(data) -> str:
return json.dumps(data, cls=_DateTimeEncoder)
When a Snowflake ID like 725653563933458432 is serialized this way and parsed by a JavaScript client, it becomes 725653563933458400 — losing the last 2 significant digits. The client then passes this rounded value back as the memory_id parameter on a subsequent update_memory or delete_memory call, and the server correctly returns not found.
Contrast: REST API is Already Fixed
The REST API layer (src/server/models/response.py) already handles this correctly via Pydantic field serializers:
# Lines 58–61
@field_serializer('memory_id')
def serialize_memory_id(self, value: int, _info) -> str:
"""Serialize as string to prevent JavaScript precision loss for large Snowflake IDs."""
return str(value)
REST endpoints also receive memory_id as a URL path string and do int(memory_id) internally — completely avoiding the JSON number precision issue. The MCP layer lacks this protection.
Reproduction Steps
- Add any memory via
add_memory MCP tool — observe the returned id field (e.g., 725653563933458432)
- Call
update_memory or delete_memory with that id as memory_id
- Observe
null / {"success": false} response — the ID was silently rounded to 725653563933458400 before reaching the server
Impact
- All
update_memory, delete_memory, get_memory_by_id, delete_memory_with_profile MCP tools are effectively broken for any memory added in an MCP session (since the returned ID is immediately subject to precision loss on the client side)
- Users relying on the Claude Code plugin for memory management cannot update or delete specific memories
- The failure is silent — no error is raised, just a
null or success: false result
Proposed Fix
Change the memory_id parameter type from int to str in the affected MCP tool signatures, and convert to int inside the function body. This causes FastMCP to emit "type": "string" in the JSON Schema, ensuring clients treat the ID as an opaque string and preserve all digits.
# Before
async def update_memory(memory_id: int, content: str, ...) -> str:
result = await memory.update(memory_id=memory_id, ...)
# After
async def update_memory(memory_id: str, content: str, ...) -> str:
result = await memory.update(memory_id=int(memory_id), ...)
Apply the same change to get_memory_by_id, delete_memory, and delete_memory_with_profile.
Additionally, ensure MCP response serialization converts id/memory_id fields to strings consistently (mirroring the REST layer's @field_serializer), so the round-trip is safe end-to-end.
Environment
- PowerMem version: 1.1.5
- Connection mode: MCP (
http://[host]:8001/mcp)
- MCP client: Claude Code (V8/JavaScript runtime)
- Affected tools:
update_memory, delete_memory, get_memory_by_id, delete_memory_with_profile
- All Snowflake IDs generated by this system are affected (they all exceed 2^53)
Bug Description
update_memoryanddelete_memoryMCP tools silently fail when operating on memories with Snowflake IDs that exceed JavaScript'sNumber.MAX_SAFE_INTEGER(2^53 − 1 =9007199254740991). All Snowflake IDs in this system are 64-bit integers (e.g.,725653563933458432), which are approximately 10× larger than this limit.Root Cause
The bug spans two layers:
1. MCP Tool Schema —
intdeclared as JSONintegerIn
src/powermem/mcp/server.py,memory_idparameters are typed as Pythonint:FastMCP auto-generates the JSON Schema from these type hints, emitting
"type": "integer"formemory_id. This causes MCP clients (including Claude Code, which runs in a JavaScript/V8 environment) to parse the returnedmemory_idas a JSON number.2. MCP Response Serialization —
json.dumps()emits bare JSON numbersThe
_fmt()helper (line 99–101 ofserver.py) serializes responses with standardjson.dumps():When a Snowflake ID like
725653563933458432is serialized this way and parsed by a JavaScript client, it becomes725653563933458400— losing the last 2 significant digits. The client then passes this rounded value back as thememory_idparameter on a subsequentupdate_memoryordelete_memorycall, and the server correctly returnsnot found.Contrast: REST API is Already Fixed
The REST API layer (
src/server/models/response.py) already handles this correctly via Pydantic field serializers:REST endpoints also receive
memory_idas a URL path string and doint(memory_id)internally — completely avoiding the JSON number precision issue. The MCP layer lacks this protection.Reproduction Steps
add_memoryMCP tool — observe the returnedidfield (e.g.,725653563933458432)update_memoryordelete_memorywith thatidasmemory_idnull/{"success": false}response — the ID was silently rounded to725653563933458400before reaching the serverImpact
update_memory,delete_memory,get_memory_by_id,delete_memory_with_profileMCP tools are effectively broken for any memory added in an MCP session (since the returned ID is immediately subject to precision loss on the client side)nullorsuccess: falseresultProposed Fix
Change the
memory_idparameter type frominttostrin the affected MCP tool signatures, and convert tointinside the function body. This causes FastMCP to emit"type": "string"in the JSON Schema, ensuring clients treat the ID as an opaque string and preserve all digits.Apply the same change to
get_memory_by_id,delete_memory, anddelete_memory_with_profile.Additionally, ensure MCP response serialization converts
id/memory_idfields to strings consistently (mirroring the REST layer's@field_serializer), so the round-trip is safe end-to-end.Environment
http://[host]:8001/mcp)update_memory,delete_memory,get_memory_by_id,delete_memory_with_profile