How the MCP Memory Server Stores Entities, Relations, and Observations
The MCP Memory server persists entities, relations, and observations as discrete JSON objects in a JSON Lines (JSONL) file, loading them into an in-memory KnowledgeGraph structure that is atomically rewritten to disk after every mutation.
The modelcontextprotocol/servers repository implements a lightweight, file-based knowledge graph for AI agent memory. This server stores structured data—entities with their observations and the relations between them—using a simple JSONL format that eliminates external database dependencies while maintaining data integrity through atomic write operations.
Storage Architecture and File Format
The MCP Memory server adopts a flat-file persistence strategy centered on the JSON Lines (JSONL) format. This approach treats each line of the storage file as an independent, valid JSON object, enabling efficient append operations and line-by-line streaming without requiring complex parsing logic.
The JSON Lines Persistence Layer
According to the implementation in src/memory/index.ts, the server defaults to a file named memory.jsonl in the working directory. Developers can override this location by setting the MEMORY_FILE_PATH environment variable. The ensureMemoryFilePath() function (lines 10-25) resolves the final path and automatically migrates legacy memory.json files to the current JSONL format, ensuring backward compatibility.
Data Models for Entities and Relations
The storage schema distinguishes between two primary record types, defined by TypeScript interfaces at lines 49-65:
Entity records store nodes in the graph with the following fields:
type: "entity"(type discriminator)name: Unique identifier stringentityType: Categorical classification (e.g., "person", "organization")observations: Array of textual notes or timestamped observations
Relation records store directed edges between entities:
type: "relation"(type discriminator)from: Name of the source entityto: Name of the target entityrelationType: Semantic descriptor defining the connection (e.g., "employee_of")
Loading and Persistence Mechanisms
The KnowledgeGraphManager class encapsulates all storage I/O, maintaining the working graph state in memory while ensuring durable, consistent disk writes.
Initializing the Knowledge Graph
The loadGraph() method (lines 71-92) reads the JSONL file line-by-line using Node.js streaming interfaces. It parses each JSON object and populates the internal KnowledgeGraph structure, which maintains separate arrays for entities and relations. This separation enables O(1) entity lookup by name and efficient relation traversal without full file rescans during operations.
Atomic Write Operations
When the graph mutates, saveGraph() (lines 101-117) serializes the current entities and relations arrays to JSONL format—converting each object to a string line—and writes the entire file atomically. This write-replace strategy ensures that the on-disk representation is always transactionally consistent; readers never encounter partially written JSON or corrupted intermediate states.
CRUD Operations on the Knowledge Graph
The manager exposes specific methods for manipulating the graph, all following the pattern: validate and modify the in-memory arrays, then invoke saveGraph() to persist.
Creating and Managing Entities
The createEntities() method accepts an array of Entity objects, validates uniqueness against existing names to prevent collisions, appends valid entities to the internal array, and triggers persistence. The deleteEntities() method removes entities by name and automatically cascades deletions to any relations referencing those entities, maintaining referential integrity.
Defining Relations Between Entities
Relations are created via createRelations(), which validates that both from and to entities exist in the current graph before adding the directed edge. The deleteRelations() method filters the relations array by source entity, target entity, or relation type criteria, removing matching edges before saving.
Adding and Removing Observations
Observations attach contextual text data to entities. The addObservations() method accepts an array of objects containing entityName and contents (a string array), appending these strings to the target entity's observations property. Deletion supports removing specific observation strings by exact match or clearing all observations from a specified entity.
MCP Tool Integration
These storage primitives are exposed as Model Context Protocol (MCP) tools registered in src/memory/index.ts, enabling AI agents to manipulate the graph through standardized interfaces:
create_entities: WrapscreateEntities()to add new nodescreate_relations: WrapscreateRelations()to establish connectionsadd_observations: WrapsaddObservations()to append entity metadataread_graph: Returns the completeKnowledgeGraphobjectsearch_nodes: Filters entities by name or observation content using substring matchingopen_nodes: Retrieves specific entities by exact name lookup
Summary
- The MCP Memory server uses a JSON Lines (JSONL) file format, defaulting to
memory.jsonlor using a custom path specified viaMEMORY_FILE_PATH. - Storage records are polymorphic JSON objects distinguished by a
typefield: entities containname,entityType, andobservations[], while relations containfrom,to, andrelationType. - The
KnowledgeGraphManagerclass loads data vialoadGraph()(lines 71-92) and persists changes atomically viasaveGraph()(lines 101-117). - All write operations modify an in-memory copy of the graph before rewriting the entire JSONL file to ensure consistency.
- Legacy storage files are automatically detected and migrated from
memory.jsontomemory.jsonlduring server initialization.
Frequently Asked Questions
What file format does the MCP Memory server use?
The server uses JSON Lines (JSONL), where each line is a self-contained JSON object representing either an entity or a relation. As implemented in src/memory/index.ts, this format supports simple line-by-line parsing and atomic file replacement, ensuring the storage layer remains portable and free of external database dependencies.
How does the MCP Memory server handle concurrent writes?
The server handles concurrency through atomic file replacement in the saveGraph() method. Rather than appending incrementally, the method serializes the entire current state to a buffer and writes it to disk atomically, ensuring that any process reading the file always sees a complete, valid JSONL structure rather than a partial write.
Can I change the storage location for the memory file?
Yes. Set the MEMORY_FILE_PATH environment variable to specify an absolute or relative path. The ensureMemoryFilePath() function in src/memory/index.ts (lines 10-25) resolves this path, creates parent directories if necessary, and handles migration of legacy files to the new location.
What is the difference between an entity and a relation in MCP Memory?
An entity represents a node in the knowledge graph—such as a person, place, or concept—and maintains an array of observations (textual data). A relation represents a directed edge connecting two entities, defined by from (source name), to (target name), and relationType (semantic label). Both are stored as JSON objects in the same file, distinguished by their type property.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →