github
MCPReads and writes GitHub issues, pull requests, files and repository metadata.
Stores and retrieves facts across sessions through a persistent knowledge graph.
Claude Code
$ claude mcp add memory -- npx @modelcontextprotocol/server-memory
Codex
$ codex mcp add memory -- npx @modelcontextprotocol/server-memory
Cursor
{ "mcpServers": { "memory": { "command": "npx", "args": [ "@modelcontextprotocol/server-memory" ] } } }
Add it to mcp.json.
Gemini CLI
$ gemini mcp add memory npx @modelcontextprotocol/server-memory
GitHub Copilot
$ copilot mcp add memory -- npx @modelcontextprotocol/server-memory
OpenCode
{ "mcp": { "memory": { "type": "local", "command": [ "npx", "@modelcontextprotocol/server-memory" ] } } }
Add it to opencode.json.
Windsurf
{ "mcpServers": { "memory": { "command": "npx", "args": [ "@modelcontextprotocol/server-memory" ] } } }
Add it to mcp_config.json.
From the README
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
Jul 23, 2026
Last push
Licence
Not published
Runs as
npx
On your machine
Deprecated
No
Signals from public registries, not an audit. Checked Nov 14, 2026.
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.
Entities are the primary nodes in the knowledge graph. Each entity has:
Example:
{
"name": "John_Smith",
"entityType": "person",
"observations": ["Speaks fluent Spanish"]
}
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 are discrete pieces of information about an entity. They are:
Example:
{
"entityName": "John_Smith",
"observations": [
"Speaks fluent Spanish",
"Graduated in 2019",
"Prefers morning meetings"
]
}
create_entities
entities (array of objects)
name (string): Entity identifierentityType (string): Type classificationobservations (string[]): Associated observationsskipped, and a second text item says which were skipped (use add_observations to extend an existing entity)create_relations
relations (array of objects)
from (string): Source entity nameto (string): Target entity namerelationType (string): Relationship type in active voiceadd_observations
observations (array of objects)
entityName (string): Target entitycontents (string[]): New observations to adddelete_entities
entityNames (string[])delete_relations; to remove facts from an entity, use delete_observationsdelete_observations
deletions (array of objects)
entityName (string): Target entityobservations (string[]): Observations to removedelete_relations
delete_entities)relations (array of objects)
from (string): Source entity nameto (string): Target entity namerelationType (string): Relationship typefrom, to and relationType all match a stored one exactly; read the stored relationType with open_nodes (or search_nodes) first if unsureread_graph
entityTypes (string[], at least one): return only entities of these types, and the relations that touch one of themobservationLimit (integer, 0 or more): see belowobservationLimit, each entity carries at most that many observations (the first ones, in the order they were added) and an observationCount with its total. observationLimit: 0 returns names, types and counts only: a cheap overview of a large graph, from which open_nodes reads the entities you need in fullsearch_nodes
query (string, at most 2048 characters; a longer query is rejected)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 for read_graphopen_nodes
names (string[])observationLimit (integer, 0 or more), as for read_graphmemory://knowledge-graph)
application/jsonread_graph (entities and relations)create_entities, create_relations, add_observations, delete_entities, delete_observations, delete_relations) emit notifications/resources/updated for this URI, so subscribed clients see live changesresourceSubscriptions of its subscriptions/listen request and gets the updates on that stream; a 2025-era client calls resources/subscribeThe 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.
Node.js 24 or later, when the server runs through npx or from source.
Add this to your claude_desktop_config.json:
{
"mcpServers": {
"memory": {
"command": "docker",
"args": ["run", "-i", "-v", "claude-memory:/app/dist", "--rm", "mcp/memory"]
}
}
}
{
"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"
]
}
}
}
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.jsonl in 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.
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.
node_modules directory, 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./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.
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).
<memory file>.lock.break file.For quick installation, use one of the one-click installation buttons below:
This repository demonstrates how to use Claude Code to do real engineering work, not just writing code. 本项目是极客时间专栏 《Claude Code 工程化实战》 的官方配套示例仓库,目标就是: 👉 把 Claude Code 从“对话式编码工具”,变成 可设计、可复用、可治理的工程系统。
Reads and writes GitHub issues, pull requests, files and repository metadata.
Ships with ai-learning-coach: 用真实 Agent 项目学会 TypeScript。教练记住你卡在哪里,带你预测、调试、修改,并用实际证据判断下一步。 首要面向已经会 Java 或其他后端语言、希望进入 TypeScript /…