Summary
While auditing and hardening local MCP server usage, I reviewed @modelcontextprotocol/server-memory and built a local hardened wrapper for our environment. I am opening this issue to share findings and possible upstream improvements.
This is not a report about a known data loss incident in the upstream package. It is a defense-in-depth report about persistence defaults and operational safety for a memory tool exposed to autonomous agents.
Package/runtime reviewed
- Package:
@modelcontextprotocol/server-memory@2026.1.26
- License observed: MIT
- Author observed: Anthropic, PBC
- Upstream repo/issue tracker:
modelcontextprotocol/servers
- npm maintainers observed from registry during local review:
jspahrsummers, pcarleton, thedsp, ashwin-ant, ochafik
Findings
-
Default persistence path can land inside the package directory.
Local source evidence showed a default path based on path.dirname(fileURLToPath(import.meta.url)), with memory.jsonl under the package dist directory when MEMORY_FILE_PATH is not configured. This creates operational fragility:
- package reinstall/update can remove or overwrite memory state
- global/package directories are not intuitive user data locations
- backup/sync behavior is unclear
-
Writes appear to be whole-file writes without explicit atomic replace and lock discipline.
For agent memory, interrupted writes or concurrent host usage can corrupt or lose state. This is especially relevant when the same memory server is configured across multiple MCP hosts.
-
No obvious mutation journal or backup trail.
Debugging accidental writes or deletes is hard without append-only audit entries or backup snapshots.
-
Destructive tools are available by default.
delete_entities, delete_observations, and delete_relations are useful, but high-impact. In an agent context, accidental deletion should require explicit operator opt-in or confirmation mode.
-
No obvious quotas/caps.
Large observations or graphs can become a memory/latency issue. Whole-graph reads and writes are also sensitive to unbounded growth.
-
No obvious secret redaction before persistence.
Memory can become a persistent prompt-injection and secret-retention surface if fetched web content, logs, stack traces, or credentials are persisted without sanitization.
-
No namespace isolation by default.
A single global memory file shared across workspace/host contexts can mix unrelated operational memories unless the user manually configures paths.
Local hardening behavior that worked well
For our local wrapper, we preserved the upstream-compatible 9 tool names:
create_entities, create_relations, add_observations, delete_entities,
delete_observations, delete_relations, read_graph, search_nodes, open_nodes
We added:
- explicit persistence outside
node_modules, defaulting to a user data path
- refusal to persist under
node_modules
- namespace support for workspace separation
- cross-process lock with stale-lock cleanup
- temp-write plus rename, with backup file
- append-only mutation audit journal
- quotas for entity/relation counts and observation sizes
- secret redaction before writes
- destructive tools disabled unless
LCV_MCP_MEMORY_ALLOW_DESTRUCTIVE=1
Validation from local wrapper
Smoke output from the hardened local wrapper:
memory tools: add_observations,create_entities,create_relations,delete_entities,delete_observations,delete_relations,open_nodes,read_graph,search_nodes
memory read_graph entities=0 relations=0
A redaction/destructive-operation check also behaved as intended in local testing:
create {"entities":[{"name":"redaction-proof","entityType":"test","observations":["token [REDACTED]"]}]}
delete [{"type":"text","text":"delete_entities is disabled by default. Set LCV_MCP_MEMORY_ALLOW_DESTRUCTIVE=1 to enable destructive memory mutations."}]
Suggested upstream changes
- Default persistence to an OS/user data directory instead of the installed package directory.
- Refuse or strongly warn when
MEMORY_FILE_PATH resolves inside node_modules or another package-managed path.
- Use atomic write/replace and cross-process locking.
- Add backup and append-only mutation audit journal options.
- Add quotas for graph size, entity count, relation count, and observation length.
- Redact common secret patterns before persistence.
- Add namespace support or document recommended per-workspace file paths.
- Gate destructive tools behind an explicit environment flag or confirmation mechanism.
Compatibility note
Most of these can be additive and opt-in, except the safer default persistence path. If changing the default is too disruptive, a migration warning plus documented MEMORY_FILE_PATH recommendation would still help users avoid package-dir persistence.
Summary
While auditing and hardening local MCP server usage, I reviewed
@modelcontextprotocol/server-memoryand built a local hardened wrapper for our environment. I am opening this issue to share findings and possible upstream improvements.This is not a report about a known data loss incident in the upstream package. It is a defense-in-depth report about persistence defaults and operational safety for a memory tool exposed to autonomous agents.
Package/runtime reviewed
@modelcontextprotocol/server-memory@2026.1.26modelcontextprotocol/serversjspahrsummers,pcarleton,thedsp,ashwin-ant,ochafikFindings
Default persistence path can land inside the package directory.
Local source evidence showed a default path based on
path.dirname(fileURLToPath(import.meta.url)), withmemory.jsonlunder the packagedistdirectory whenMEMORY_FILE_PATHis not configured. This creates operational fragility:Writes appear to be whole-file writes without explicit atomic replace and lock discipline.
For agent memory, interrupted writes or concurrent host usage can corrupt or lose state. This is especially relevant when the same memory server is configured across multiple MCP hosts.
No obvious mutation journal or backup trail.
Debugging accidental writes or deletes is hard without append-only audit entries or backup snapshots.
Destructive tools are available by default.
delete_entities,delete_observations, anddelete_relationsare useful, but high-impact. In an agent context, accidental deletion should require explicit operator opt-in or confirmation mode.No obvious quotas/caps.
Large observations or graphs can become a memory/latency issue. Whole-graph reads and writes are also sensitive to unbounded growth.
No obvious secret redaction before persistence.
Memory can become a persistent prompt-injection and secret-retention surface if fetched web content, logs, stack traces, or credentials are persisted without sanitization.
No namespace isolation by default.
A single global memory file shared across workspace/host contexts can mix unrelated operational memories unless the user manually configures paths.
Local hardening behavior that worked well
For our local wrapper, we preserved the upstream-compatible 9 tool names:
We added:
node_modules, defaulting to a user data pathnode_modulesLCV_MCP_MEMORY_ALLOW_DESTRUCTIVE=1Validation from local wrapper
Smoke output from the hardened local wrapper:
A redaction/destructive-operation check also behaved as intended in local testing:
Suggested upstream changes
MEMORY_FILE_PATHresolves insidenode_modulesor another package-managed path.Compatibility note
Most of these can be additive and opt-in, except the safer default persistence path. If changing the default is too disruptive, a migration warning plus documented
MEMORY_FILE_PATHrecommendation would still help users avoid package-dir persistence.