memory
Persistent knowledge graph for cross-session facts
Claude Code
$ claude mcp add memory -- npx -y @modelcontextprotocol/server-memory
Codex
$ codex mcp add memory -- npx -y @modelcontextprotocol/server-memory
Cursor
{ "mcpServers": { "memory": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-memory" ] } } }
Add it to mcp.json.
Gemini CLI
{ "mcpServers": { "memory": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-memory" ] } } }
Add it to settings.json.
GitHub Copilot
$ copilot mcp add memory -- npx -y @modelcontextprotocol/server-memory
OpenCode
{ "mcp": { "memory": { "type": "local", "command": [ "npx", "-y", "@modelcontextprotocol/server-memory" ] } } }
Add it to opencode.json.
Windsurf
{ "mcpServers": { "memory": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-memory" ] } } }
Add it to mcp_config.json.
From the README
What can you do with memory?
create_entities
Create multiple new entities in the knowledge graph
create_relations
Create multiple new relations between entities
add_observations
Add new observations to existing entities
delete_entities
Remove whole entities, with all their observations
delete_observations
Remove specific observations from entities
delete_relations
Remove specific relations from the graph, keeping the entities they connect (to remove an entity itself, use delete_entities)
Security report
Low risk
Known flaws
None known
Signed build
Yes
Build provenance published
Maintained
Apr 27, 2026
Last push
Licence
MIT
Runs as
npx
On your machine
Deprecated
No
Signals from public registries, not an audit. Checked Nov 12, 2026.
memory README
Knowledge Graph Memory Server
A basic implementation of persistent memory using a local knowledge graph. This lets Claude remember information about the user across chats.
Published on npm as @modelcontextprotocol/server-memory.
Core Concepts
Entities
Entities are the primary nodes in the knowledge graph. Each entity has:
- A unique name (identifier)
- An entity type (e.g., "person", "organization", "event")
- A list of observations
Example:
{
"name": "John_Smith",
"entityType": "person",
"observations": ["Speaks fluent Spanish"]
}
Relations
Relations define directed connections between entities. They are always stored in active voice and describe how entities interact or relate to each other.
Example:
{
"from": "John_Smith",
"to": "Anthropic",
"relationType": "works_at"
}
Observations
Observations are discrete pieces of information about an entity. They are:
- Stored as strings
- Attached to specific entities
- Can be added or removed independently
- Should be atomic (one fact per observation)
Example:
{
"entityName": "John_Smith",
"observations": [
"Speaks fluent Spanish",
"Graduated in 2019",
"Prefers morning meetings"
]
}
API
Tools
-
create_entities
- Create multiple new entities in the knowledge graph
- Input:
entities(array of objects)- Each object contains:
name(string): Entity identifierentityType(string): Type classificationobservations(string[]): Associated observations
- Each object contains:
- Ignores entities with existing names (and repeats of a name earlier in the same call); their observations are not added
- Returns the created entities. When any were skipped, the structured result also lists their names in
skipped, and a second text item says which were skipped (useadd_observationsto extend an existing entity)
-
create_relations
- Create multiple new relations between entities
- Input:
relations(array of objects)- Each object contains:
from(string): Source entity nameto(string): Target entity namerelationType(string): Relationship type in active voice
- Each object contains:
- Skips duplicate relations
- Fails if either the source or target entity doesn't exist
-
add_observations
- Add new observations to existing entities
- Input:
observations(array of objects)- Each object contains:
entityName(string): Target entitycontents(string[]): New observations to add
- Each object contains:
- Returns added observations per entity
- Fails if entity doesn't exist
-
delete_entities
- Remove whole entities, with all their observations
- Input:
entityNames(string[]) - Cascading deletion of every relation that points to or from a deleted entity
- To remove a link between two entities and keep both, use
delete_relations; to remove facts from an entity, usedelete_observations - No error if an entity doesn't exist; the response reports which names were not found
-
delete_observations
- Remove specific observations from entities
- Input:
deletions(array of objects)- Each object contains:
entityName(string): Target entityobservations(string[]): Observations to remove
- Each object contains:
- No error if an observation doesn't exist; the response reports how many were deleted
-
delete_relations
- Remove specific relations from the graph, keeping the entities they connect (to remove an entity itself, use
delete_entities) - Input:
relations(array of objects)- Each object contains:
from(string): Source entity nameto(string): Target entity namerelationType(string): Relationship type
- Each object contains:
- A relation is deleted only when
from,toandrelationTypeall match a stored one exactly; read the storedrelationTypewithopen_nodes(orsearch_nodes) first if unsure - No error if a relation doesn't exist; the response reports how many were deleted
- Remove specific relations from the graph, keeping the entities they connect (to remove an entity itself, use
-
read_graph
- Read the entire knowledge graph
- Optional input:
entityTypes(string[], at least one): return only entities of these types, and the relations that touch one of themobservationLimit(integer, 0 or more): see below
- Returns complete graph structure with all entities and relations
- With
observationLimit, each entity carries at most that many observations (the first ones, in the order they were added) and anobservationCountwith its total.observationLimit: 0returns names, types and counts only: a cheap overview of a large graph, from whichopen_nodesreads the entities you need in full
-
search_nodes
- Search for nodes based on query
- Input:
query(string, at most 2048 characters; a longer query is rejected) - Searches across:
- Entity names
- Entity types
- Observation content
- Returns matching entities and their relations
- Optional input:
limit(integer, 1 or more): return at most this many matches (the first, in stored order), with the relations that touch themobservationLimit(integer, 0 or more): as forread_graph
-
open_nodes
- Retrieve specific nodes by name
- Input:
names(string[]) - Returns:
- Requested entities
- Relations between requested entities
- Silently skips non-existent nodes
- Optional input:
observationLimit(integer, 0 or more), as forread_graph
Resources
- knowledge-graph (
memory://knowledge-graph)- The full knowledge graph as a readable MCP Resource
- MIME type:
application/json - Returns the same shape as
read_graph(entities and relations) - Mutation tools (
create_entities,create_relations,add_observations,delete_entities,delete_observations,delete_relations) emitnotifications/resources/updatedfor this URI, so subscribed clients see live changes - How a client subscribes depends on its protocol version: a 2026-07-28 client names the URI in the
resourceSubscriptionsof itssubscriptions/listenrequest and gets the updates on that stream; a 2025-era client callsresources/subscribe
Protocol versions
The server serves both protocol eras on stdio from the same process. The client's first message picks the era of the connection: a 2026-07-28 client opens with server/discover and sends its protocol version, identity and capabilities with each request, and a 2025-era client opens with the initialize handshake. The tools and the resource are the same on both.
Requirements
Node.js 24 or later, when the server runs through npx or from source.
Usage with Claude Desktop
Setup
Add this to your claude_desktop_config.json:
Docker
{
"mcpServers": {
"memory": {
"command": "docker",
"args": ["run", "-i", "-v", "claude-memory:/app/dist", "--rm", "mcp/memory"]
}
}
}
NPX
{
"mcpServers": {
"memory": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-memory"
]
}
}
}
On Windows, use cmd /c to launch npx:
{
"mcpServers": {
"memory": {
"command": "cmd",
"args": [
"/c",
"npx",
"-y",
"@modelcontextprotocol/server-memory"
]
}
}
}
NPX with custom setting
The server can be configured using the following environment variables:
{
"mcpServers": {
"memory": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-memory"
],
"env": {
"MEMORY_FILE_PATH": "/path/to/custom/memory.jsonl"
}
}
}
}
On Windows, use:
{
"mcpServers": {
"memory": {
"command": "cmd",
"args": [
"/c",
"npx",
"-y",
"@modelcontextprotocol/server-memory"
],
"env": {
"MEMORY_FILE_PATH": "/path/to/custom/memory.jsonl"
}
}
}
}
MEMORY_FILE_PATH: Path to the memory storage JSONL file (default:memory.jsonlin the server directory). A leading~expands to your home directory; a relative path resolves against the server directory. Set it to an absolute path you own; see Choosing where the graph is stored.
When MEMORY_FILE_PATH is not set and the server directory still holds a legacy memory.json but no memory.jsonl, the server renames memory.json to memory.jsonl at startup. If that rename fails, the server exits with an error naming both paths and the cause, rather than starting on an empty graph; fix the cause (a permission problem, say) and restart, or set MEMORY_FILE_PATH to choose a file explicitly.
Choosing where the graph is stored
Set MEMORY_FILE_PATH to an absolute path you own, such as ~/memory.jsonl, as in the configuration above. The default memory.jsonl sits in the server's own directory, next to its code. Under npx or an npm install, that directory is inside a node_modules tree, which npm manages as its own: reinstalling or updating the server, or clearing the npx cache, can delete the file and the knowledge graph in it. A relative MEMORY_FILE_PATH resolves against that same directory, so it has the same problem.
- When the memory file it resolves is inside a
node_modulesdirectory, the server prints a warning on stderr at startup naming the file; most clients show a server's stderr in its log. Move the file to the new path when you set the variable, or the server starts on an empty graph. - The directory must already exist: the server creates the memory file, not the directories above it.
- The default stays where it is so that existing graphs keep loading. The Docker setup above keeps it in a named volume mounted over
/app/dist, so the graph there survives restarts and draws no warning.
Saves are atomic. Every write tool writes the whole graph to a temporary file in the same directory and renames it over the memory file, so a server stopped or killed mid-save leaves the previous graph intact rather than a half-written file. The file's permission bits are kept across the rename. Writes from several processes are serialized by a lock, described next.
Sharing one memory file between clients
Each MCP client starts its own server process, so two clients using the same MEMORY_FILE_PATH (or both using the default) are two processes writing one file. Every write tool takes an exclusive lock file, <memory file>.lock, next to the memory file while it reads, changes and saves the graph, so writes from different processes take turns and none is lost. The lock file exists only while a write is in progress, so the directory holding the memory file must be writable (it already must be, for the atomic save).
- A lock left behind by a server that crashed mid-write is removed automatically: at once if its process is known to have exited on the same machine, otherwise once it has gone 30 seconds without being refreshed (a server holding the lock refreshes it every 15 seconds while it works). Only one waiting server breaks a stale lock at a time, guarded by a momentary
<memory file>.lock.breakfile. - A write that cannot get the lock within 60 seconds fails with a tool error rather than overwriting the file.
- The lock relies on exclusive file creation, which local filesystems provide; a network filesystem that does not honour it cannot be shared safely this way.
VS Code Installation Instructions
For quick installation, use one of the one-click installation buttons below:
Claude Code için Türkçe profesyonel işletim sistemi — 10 uzman agent, 22 komut, 993 skill, 6 katmanlı hafıza
More MCP servers from other plugins.
nimbalyst-local
MCPShips with nimbalyst: Nimbalyst - The open-source visual workspace for Claude Code, Codex, and OpenCode. Run multiple coding…
dex-core
MCPShips with dex: One personal Dex, built around your work. Keep your priorities, people, meeting notes and tasks in a folder you…
Questions about memory.
- Which coding agents can use memory?
- memory works in any agent that reads an MCP config file: Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf. Each agent reads it from its own file; this page names the file for each one.
- How do I add memory to Claude Code?
- Run this in your terminal: claude mcp add memory -- npx -y @modelcontextprotocol/server-memory
- Is memory safe to install?
- Low risk. Signals from public registries, not an audit.

