Skip to content
Development
MCP

memory

Stores and retrieves facts across sessions through a persistent knowledge graph.

From plugin
open-agent-hub
1k105 skills5 agents3 commands6 MCP

Claude Code

> /plugin marketplace add guanyang/open-agent-hub
> /plugin install open-agent-hub@open-agent-hub

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

Note

Review first

This package is deprecated.

  • Known flaws

    None known

  • Signed build

    No

    No build provenance published

  • Maintained

    Nov 15, 2026

    Last push

  • Licence

    MIT

  • Runs as

    npx

    On your machine

  • Deprecated

    Yes

Signals from public registries, not an audit. Checked Nov 15, 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 identifier
        • entityType (string): Type classification
        • observations (string[]): Associated observations
    • 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 (use add_observations to extend an existing entity)
  • create_relations

    • Create multiple new relations between entities
    • Input: relations (array of objects)
      • Each object contains:
        • from (string): Source entity name
        • to (string): Target entity name
        • relationType (string): Relationship type in active voice
    • 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 entity
        • contents (string[]): New observations to add
    • 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, use delete_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 entity
        • observations (string[]): Observations to remove
    • 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 name
        • to (string): Target entity name
        • relationType (string): Relationship type
    • A relation is deleted only when from, to and relationType all match a stored one exactly; read the stored relationType with open_nodes (or search_nodes) first if unsure
    • No error if a relation doesn't exist; the response reports how many were deleted
  • 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 them
      • observationLimit (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 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 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 them
      • observationLimit (integer, 0 or more): as for read_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 for read_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) emit notifications/resources/updated for 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 resourceSubscriptions of its subscriptions/listen request and gets the updates on that stream; a 2025-era client calls resources/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.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.

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_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.
  • 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.break file.
  • 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:

@guanyang
Ships withopen-agent-hub

A lightweight, zero-dependency CLI tool to manage and activate capabilities for AI coding assistants (such as Claude Code, Cursor, Trae, etc.).

1k105 skills5 agents6 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
1.0k
Star history of guanyang/open-agent-hub on GitHub, a chart by star-history.com

More MCP servers from other plugins.

chrome-devtools
Auto-invoked

chrome-devtools

MCP

Connects to Chrome over the DevTools Protocol to inspect the DOM, network requests and console output.

ecc2w293k
@affaan-m@affaan-mInstall MCP
supabase

supabase

MCP

Queries a Supabase project: Postgres tables, auth users, storage and edge functions.

supabase2w114k
@supabase@supabaseInstall MCP

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 these in order, one at a time. 1. In Claude Code: /plugin marketplace add guanyang/open-agent-hub 2. In Claude Code: /plugin install open-agent-hub@open-agent-hub
Is memory safe to install?
Review first. This package is deprecated. Signals from public registries, not an audit.