Knowledge Graph Memory Server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Knowledge Graph Memory ServerRemember that I work at Acme as a developer."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Knowledge Graph Memory Server
A basic implementation of persistent memory using a local knowledge graph. This lets AI assistants remember information about the user across chats.
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": "Jaime_Villanueve",
"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": "Jaime_Chicharra",
"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": "Jaime_Chicharra",
"observations": ["Speaks fluent Spanish", "Graduated in 2019", "Prefers morning meetings"]
}Related MCP server: MCP Memory SQLite
Storage
The knowledge graph is stored in a local SQLite database using Node's built-in
node:sqlite module — no native dependencies, requires Node.js >= 24. The
database contains three tables:
entities—name(primary key) andentityTypeobservations— one row per observation, linked to its entity byentityName; removed automatically when the entity is deletedrelations—from,to, andrelationType(primary key across all three)
All mutation operations run inside transactions, so the graph is never left in a half-written state.
Migrating from JSONL
Versions before 0.7.0 stored the graph as a JSONL document (memory.jsonl). On
first start with an empty database, the server automatically imports entities
and relations from a legacy JSONL file next to the database (e.g. memory.jsonl
or memory.json next to memory.db) and logs what it imported. The legacy file
is left in place as a backup.
If MEMORY_FILE_PATH still points at a .jsonl/.json file, the server
redirects the database to the sibling .db path and imports the legacy contents
on first start.
API
this MCP server is designed as a drop-in replacement for mcp-server-memory. we do slightly bend some tools semantric so we can use a stricter schema than the jsonl file, but our intention is to match the upstream tool call signatures.
A caller written against upstream keeps working: upstream's nine tools keep
their names, inputs, and the response fields they read. On top of that we add
fields and one verb where upstream's shape makes the graph hard to work with —
relations come back with their far endpoints (see neighbors), deletes report
what actually matched instead of a blanket success, and update_observations
exists because upstream's edit is a delete plus an add: two calls, non-atomic,
and unverifiable.
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
Ignores entities with existing names
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
Skips duplicate relations
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
Returns added observations per entity
Fails if entity doesn't exist
delete_entities
Remove entities and their relations
Input:
entityNames(string[])Cascading deletion of associated relations
Returns
deletedEntities: the canonical names that were actually removedIdempotent: names that do not exist are skipped, not an error
delete_observations
Remove specific observations from entities
Input:
deletions(array of objects)Each object contains:
entityName(string): Target entityobservations(string[]): Observations to remove
Returns
results: per entity, thedeletedObservationsthat actually matched (messagecarriesdeleted N of M requested)Observation content is the primary key, so the match must be exact
delete_relations
Remove specific relations from the graph
Input:
relations(array of objects)Each object contains:
from(string): Source entity nameto(string): Target entity namerelationType(string): Relationship type
Returns
deletedRelations: the edges that actually matchedA materialized inverse is removed with its primary edge but not reported as a separate deletion
update_observations
Replace the text of existing observations in place
Input:
updates(array of objects)Each object contains:
entityName(string): Entity holding the observationmatch(string): The exact current content to replacereplacement(string): The new content
Returns
updatedObservationsper entityThe row is updated, not rewritten:
created_atkeeps the first-written time andupdated_atrecords the edit; the search index followsFails the whole batch (no partial application) if a
matchis absent, if the entity is unknown, or ifreplacementalready exists on that entity — including whenreplacementequalsmatch, since replacing text with itself is not an edit
read_graph
Read the entire knowledge graph
No input required
Returns complete graph structure with all entities and relations. Every entity is loaded, so there is no frontier:
neighborsis always empty
search_nodes
Search for nodes based on query
Input:
query(string)Searches across:
Entity names
Entity types
Observation content
Returns matching entities, their relations, and the relations' far endpoints as
neighbors
open_nodes
Retrieve specific nodes by name
Input:
names(string[])Returns:
Requested entities
Relations touching those entities
neighbors: the far endpoints of those relations that were not requested themselves, so one call returns a node and everything it points at
Silently skips non-existent nodes
search_nodes and open_nodes return neighbors (deduped, in rowid order);
the list is empty when a result set is closed, and read_graph — which loads
every entity — always returns [].
Resources
knowledge-graph (
memory://knowledge-graph)The full knowledge graph as a readable MCP Resource
MIME type:
application/jsonReturns the same shape as
read_graph(entities, relations, and an emptyneighborslist)Mutation tools (
create_entities,create_relations,add_observations,update_observations,delete_entities,delete_observations,delete_relations) emitnotifications/resources/updatedfor this URI, so subscribed clients see live changes
Usage with MCP clients
Setup
Add this to your mcp.json:
Docker
{
"mcpServers": {
"memory": {
"command": "docker",
"args": ["run", "-i", "-v", "memory-data:/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.db"
}
}
}
}On Windows, use:
{
"mcpServers": {
"memory": {
"command": "cmd",
"args": ["/c", "npx", "-y", "@modelcontextprotocol/server-memory"],
"env": {
"MEMORY_FILE_PATH": "/path/to/custom/memory.db"
}
}
}
}MEMORY_FILE_PATH: Path to the memory SQLite database file (default:memory.dbin the server directory). If the path ends in.jsonlor.json, it is treated as a legacy JSONL memory file: the database is created at the sibling.dbpath and the JSONL contents are imported on first start.
Large responses: the server returns the full result
search_nodes, read_graph, and open_nodes return the full graph of
matches — entities with all their observations, plus every relation touching
them and the far endpoints of those relations (neighbors). On a realistic
graph the serialized tool result is large: 50–100 KiB per search on a live
graph, and much more for the whole graph. Some MCP clients bound the tool
results they expose to the model: the pi coding agent's adapter
(pi-mcp-adapter) replaces any tool result whose JSON exceeds its
detailsMaxBytes (default 16 KiB) with an { omitted: true } summary that
has no entities/relations keys — so on the mcpScript/worker call path a
large search appeared to return "no results".
The server does nothing about this, deliberately: it returns the full
result and leaves the bound to the client. The adapter's guard spills an
oversized result to a temp file (mode 0600) and returns a summary carrying
fullResultPath, so the caller can still read everything — whereas a
server-side trim is lossy with no way back to the dropped data. That bound also
fails in a way the guard does not: a board is a single entity, so a
trim keeps the head and the rest of it cannot be reached with a narrower query
at all. An unbounded reply is noisy; a bounded reply that silently drops half a
board is worse.
If a client's cap is too tight, raise it (pi: settings.outputGuard. detailsMaxBytes in mcp.json — note that setting is global for all servers),
or read less per call: open_nodes on fewer names, a narrower search_nodes
query, or read_graph piped somewhere the model does not have to hold all of
it.
The behavior is pinned by __tests__/output-guard.test.ts (hermetic),
__tests__/pi-adapter-output-guard.integration.test.ts (against the real
adapter, skipped when it is not installed), and
__tests__/pi-client-output-schema.integration.test.ts (against the real pi
client, likewise skipped).
Install Instructions
You can configure the MCP server using one of these methods:
Method 1: User Configuration (Recommended) Add the configuration to your
user-level MCP configuration file. Open the Command Palette (Ctrl + Shift + P)
and run MCP: Open User Configuration. This will open your user mcp.json file
where you can add the server configuration.
Method 2: Workspace Configuration Alternatively, you can add the
configuration to a file called .vscode/mcp.json in your workspace. This will
allow you to share the configuration with others.
For more details about MCP configuration in VS Code, see the official VS Code MCP documentation.
NPX
{
"servers": {
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
}
}
}On Windows, use:
{
"servers": {
"memory": {
"command": "cmd",
"args": ["/c", "npx", "-y", "@modelcontextprotocol/server-memory"]
}
}
}Docker
{
"servers": {
"memory": {
"command": "docker",
"args": ["run", "-i", "-v", "memory-data:/app/dist", "--rm", "mcp/memory"]
}
}
}System Prompt
The prompt for utilizing memory depends on the use case. Changing the prompt will help the model determine the frequency and types of memories created.
Here is an example prompt for chat personalization. You can use this prompt as a system prompt for your AI assistant.
Follow these steps for each interaction:
1. User Identification:
- You should assume that you are interacting with default_user
- If you have not identified default_user, proactively try to do so.
2. Memory Retrieval:
- Always begin your chat by saying only "Remembering..." and retrieve all relevant information from your knowledge graph
- Always refer to your knowledge graph as your "memory"
3. Memory
- While conversing with the user, be attentive to any new information that falls into these categories:
a) Basic Identity (age, gender, location, job title, education level, etc.)
b) Behaviors (interests, habits, etc.)
c) Preferences (communication style, preferred language, etc.)
d) Goals (goals, targets, aspirations, etc.)
e) Relationships (personal and professional relationships up to 3 degrees of separation)
4. Memory Update:
- If any new information was gathered during the interaction, update your memory as follows:
a) Create entities for recurring organizations, people, and significant events
b) Connect them to the current entities using relations
c) Store facts about them as observationsBuilding
The server uses Node's built-in node:sqlite module, which requires Node.js
= 24.
Docker:
docker build -t mcp/memory .For Awareness: the Docker command above persists the server in a named volume
mounted over /app/dist. A volume created by a prior image shadows the new
container's /app/dist, including the compiled schema migrations at
/app/dist/migrations; the server then fails to start with a "Failed to load
migrations" error. If you use a docker volume for storage, delete the old volume
(or at least its contents) before starting the new container so the fresh code
and migrations are used.
License
This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.
This server cannot be deployed
Maintenance
Related MCP Connectors
Persistent, portable memory for AI assistants — your private memory graph, from any MCP client.
Persistent personal memory for AI assistants — save, search, and recall across every MCP client.
- mcpOAuthai.butlerbrain
Persistent memory for AI assistants. Save once; recall from Claude, ChatGPT, or any MCP client.
Personal knowledge graph as an AI memory layer over MCP - read, save, and link your memories.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceProvides persistent memory functionality for AI conversations by creating, managing and querying entities and relationships in a knowledge graph. Features SQLite storage, advanced search capabilities, and Windows auto-start integration for long-term AI memory retention.6MIT
- AlicenseCqualityDmaintenanceProvides persistent memory and knowledge graph capabilities for AI assistants using local SQLite storage. Enables creating, searching, and managing entities, relationships, and observations with vector search support across conversations.71915MIT
- AlicenseNot gradedqualityDmaintenanceEnables Claude to remember information about users across conversations by storing and retrieving data as entities, relations, and observations in a persistent local knowledge graph.152,087-
- AlicenseNot gradedqualityDmaintenanceEnables Claude to remember information about users across chats using a persistent local knowledge graph that stores entities, relationships, and observations.152,087-