
Stateless agents lose every fact when a session ends, which makes long-running workflows impossible without an external store. The Memory MCP reference server solves this by exposing a knowledge-graph-backed persistence layer that any MCP client can query through standardized tools. This article walks developers through how the Memory primitive actually works, how it differs from vector-store-based recall, and how to wire it into a host application. The focus is the Anthropic-published reference implementation at src/memory in the MCP servers repository, its entity-and-relation data model, and the integration steps that turn it into long-term context for an agent.

Every LLM session begins with a clean slate. Once the session ends, the context window is discarded and any facts the model derived during the run are lost. The next session must rebuild them from scratch, which means re-paying inference cost, re-reading files, and re-asking the user the same onboarding questions. For a one-shot question this is fine. For a coding agent that has been refactoring a codebase for an hour, or a research assistant that has been gathering citations across a long investigation, the loss is total and immediate.
This is the gap that the Model Context Protocol (MCP) is designed to formalize. The MCP architecture describes agent context in three tiers (source):
Without an external store, an agent has access only to the first two tiers. Anything it has learned expires with the session, so each new run starts at zero. That is acceptable for stateless completion, but it breaks the workflows that benefit most from an agent: long-running coding sessions, multi-day research projects, and personal assistants that are expected to remember user preferences, prior decisions, and project history.
The MCP specification leaves room for servers to provide each tier, and the project ships reference implementations to demonstrate how. Among the maintained servers in the modelcontextprotocol/servers repository, the one positioned to fill the long-term tier is the Memory server at src/memory (source). Where the Filesystem or Fetch servers extend what an agent can see in the moment, the Memory server extends what an agent can remember across sessions.
It does this by replacing ad-hoc notes with a structured store: entities and the relations between them, kept in a knowledge graph rather than as free-form text. The design choice matters because it lets an agent recall, traverse, and reason over previously stored facts rather than re-deriving them. In practice, that turns a stateless LLM call into an agent that can accumulate context across the lifetime of a project rather than the lifetime of a context window. The remainder of this article examines how that knowledge graph is structured, what tools the server exposes, and how to wire it into a host application.

The Memory reference server, located at src/memory in the modelcontextprotocol/servers repository, persists information as a small, well-defined knowledge graph. According to the modelcontextprotocol.io/examples documentation, this approach lets MCP clients "store, retrieve, and reason over structured information across sessions" rather than relying on ephemeral chat context. Three primitives make up the graph:
name used as its identifier and an entityType string that classifies it (for example, Person, Project, or Tool). The name is the primary key, so two writes to the same name refer to the same node.from entity name, a to entity name, and a relationType label. Because they are directional, the same pair of entities can participate in multiple relations with different types (for example, Alice works_with Bob and Bob mentors Alice are both legal).This shape follows the standard subject–relation–object triple model that knowledge graphs are built on, where meaning lives in the structure of the labels and edges rather than in similarity scores.
The reference implementation stores the graph as a local JSON file rather than talking to an external database. This keeps the server self-contained: a single process owns the file, reads it on startup, and writes it back after each mutation. The trade-off is operational simplicity over concurrency, which is appropriate for a reference design intended to illustrate MCP integration patterns rather than serve as a production-scale store.
The graph is not write-once. The Memory server exposes MCP tools that let a client add or delete entities, append or remove observations, and create or delete relations. Because every operation goes through a standardized tool call, an agent that is itself an MCP client can mutate its own long-term memory in the same loop where it reasons, without any bespoke storage API. The mutable design also means stale or incorrect facts can be pruned rather than only added.
The schema and the exact tool surface have evolved as the MCP specification has matured. When building against Memory, pin to the implementation published under the modelcontextprotocol/servers repository at the revision you target, and review the tool definitions exposed by that build before relying on a specific field name or operation in client code.

The Memory server participates in MCP's standard discovery handshake. When an MCP client opens a session, it sends a tools/list request to enumerate every callable function the server exposes. The Memory server responds with the metadata for its nine tools — name, description, and a JSON inputSchema for each. Servers are expected to return tools in a deterministic order so clients can cache the listing and improve prompt-cache hit rates (MCP Server Tools Specification). Once the client has the list, it passes the tool definitions to the language model as ordinary function calls; when the model decides to invoke one, the client sends a tools/call request carrying the tool's name and arguments, and receives a structured result back.
MCP defines three server-side primitives: Tools (executable), Resources (readable contextual data), and Prompts (reusable templates) (MCP Architecture). The Memory server exposes its functionality exclusively through the Tools primitive. The underlying knowledge graph is not published as a Resource — clients cannot fetch it via resources/get. Instead, every read and write goes through a tool call, which gives the server a single chokepoint for validation, persistence, and access control. This is a deliberate choice: tools are designed to be model-controlled and require explicit invocation, whereas resources are typically fetched by the host application on the model's behalf (MCP Server Concepts).
The Memory server advertises nine tools, organized into three groups:
create_entities, create_relations, add_observations, and the corresponding delete_entities, delete_observations, delete_relations for pruning.read_graph returns the full graph state, search_nodes performs a text-based lookup against entity names and observation contents, and open_nodes fetches specific entities by name along with their direct relations.Each tool accepts a JSON object validated against its declared inputSchema. For example, create_entities takes an array of entity records (name, type, optional metadata), add_observations accepts an array of (entityName, contents) pairs to append, and search_nodes takes a single query string.
Consider an agent that needs to remember a user preference across sessions:
create_entities with [{ "name": "pref-tab-width", "type": "preference", "metadata": { "scope": "project-acme" } }].add_observations with { "entityName": "pref-tab-width", "contents": ["User prefers 2-space indentation", "Confirmed during 2026-08 review"] }.search_nodes with { "query": "indentation" }. The Memory server returns the entity and its accumulated observations, restoring long-term context without any retraining or prompt-engineering tricks.
The Memory MCP server stores information as typed entities connected by named relationships — the classic knowledge-graph triple of (subject, predicate, object) such as (Jane, PREFERS, "dark mode") or (Project Atlas, OWNS, server-cluster-3). A read against Memory returns exact nodes and traversable edges, not ranked approximations of meaning.
A vector store takes the opposite path. Documents and facts are chunked, embedded into high-dimensional vectors, and retrieved by approximate nearest neighbor over a similarity metric such as cosine distance. The result is a ranked list of passages whose meaning is closest to the query, regardless of whether the underlying entities are named or even present in any single chunk. This makes vector recall strong on fuzzy prose and weak on structural questions that require linking specific named items.
Writing to Memory is an explicit, structured operation: the client creates entities, declares their types, and links them with typed relations. Updates are deterministic — renaming a node or changing a relation overwrites it without disturbing unrelated facts. The cost is schema discipline: the caller must know what to write and how to label it.
Vector stores trade that discipline for ingestion speed. Any chunk of text can be embedded and indexed without prior modeling, but updates require re-embedding affected chunks and, often, re-indexing a shard. There is no native notion of "this fact superseded that fact," which is why frameworks such as Zep's temporal context graph attach validity windows to graph edges instead of relying on embeddings alone.
Graph-backed memory answers questions of the form "what is connected to this, and how?" — multi-hop traversals like user → owns → project → depends_on → library → has_known_issue → CVE-2025-1234. Each hop is an exact, inspectable path.
Vector recall answers questions of the form "what is similar to this?" It excels at surfacing relevant passages from large unstructured corpora but cannot guarantee that two retrieved chunks refer to the same entity, nor can it chain relations explicitly.
Memory itself does not embed, does not perform semantic search, and does not chunk text. If the workload needs similarity ranking, pair it with a vector index upstream of the graph.

The Memory reference server is a TypeScript package, so the simplest way to start it locally is through npx, which fetches and runs the package on demand without a manual install step:
npx -y @modelcontextprotocol/server-memory
Under the default stdio transport, the server process communicates with its host over the process's standard input and standard output, exchanging newline-delimited JSON-RPC 2.0 messages. No external database, network port, or service daemon is involved — the server is a child subprocess that the host launches and manages.
In the MCP architecture, three roles cooperate: a host (the LLM application such as Claude Desktop or a custom agent runtime), a client (a connector inside the host that owns one server session), and the server itself. To wire Memory in, the host loads a configuration entry that names the command and arguments to spawn:
{
"mcpServers": {
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
}
}
}
The host instantiates a dedicated client for this entry and starts the server subprocess as part of session startup.
Once the subprocess is running, the client kicks off the lifecycle's first phase by sending an initialize request that declares its protocol version and the client-side capabilities it supports (such as sampling, elicitation, or roots). The Memory server replies with its own capabilities — typically tools, plus any optional features — along with its name and version. The client then sends a notifications/initialized notification, at which point capabilities are considered negotiated and the operational phase begins.
Per the MCP architecture spec, both sides must respect only the capabilities that were explicitly declared, which is what allows clients and servers to evolve independently while remaining backwards compatible.
Immediately after initialization, the host typically issues a tools/list request to enumerate everything the server exposes. For Memory, that includes create_entities, create_relations, add_observations, search_nodes, and the read/delete counterparts. The host feeds the resulting tool definitions (each with a name, description, and JSON inputSchema) into the model's function-calling context. From that point on, the model — not the host code — decides when to invoke create_entities or search_nodes based on the conversation.
By default the server writes the knowledge graph to a local JSON file, and some releases accept a flag such as --memory-path to override that location. Because argument names and default paths differ across versions, treat this flag as version-sensitive and consult the package's README for the exact syntax in the release you are running. The result is a single, portable JSON file that is straightforward to back up, inspect, or move between environments.
The Memory reference server treats entity names as identity keys, so any inconsistency at write time becomes a permanent split in the graph. Use canonical strings — slug-style identifiers, well-known external IDs, or kind:value patterns — instead of pasting raw user text into the name field. Raw text drifts across capitalisation, punctuation, and whitespace, and the server has no built-in merge step that can repair that retroactively. Relation types benefit from the same discipline: a closed verb vocabulary (works_on, manages, depends_on) keeps traversals predictable and prevents near-duplicate edges such as owns and owns_asset from accumulating.
Observations are the lowest-cost write the Memory server accepts, which makes them the easiest place for noise to enter the graph. Agents tend to re-record the same fact with slight rewording each session, so the same truth accumulates under many near-identical strings. Two patterns help: have the host application dedupe on a hash of the normalised observation before forwarding the write, and schedule periodic pruning of low-value observations (stale, redundant, or unsupported by any active relation). Without pruning, the retrieval context the agent sees grows noisier over time even though the underlying signal is unchanged.
The reference server persists its graph to a local JSON file, which is effectively a single-writer store. A single MCP client issuing sequential create_entities, add_observations, and create_relations calls works fine; parallel writers from multiple clients, or multiple host processes pointing at the same file, risk lost updates and corrupted JSON. The MCP servers repository documents the local JSON store as a development-grade default. For any deployment with multiple users, remote clients, or temporal validity requirements, the right move is to migrate the backing store to a hosted graph database (Neo4j, Memgraph, or a managed temporal graph such as Graphiti) behind the same MCP tool surface.
The MCP ecosystem contains several graph-oriented servers that overlap with or extend Memory:
These are alternatives for code-centric or multi-user contexts, and complements (running alongside Memory) when an agent needs both user/project memory and codebase structure.
Tool names, the on-disk persistence format, and configuration flags all change between releases of the MCP servers repository. Pin the server version in your host configuration and re-read the schema before upgrading; treating the Memory server as an immutable API will eventually produce parse errors or silent data-shape drift. The Memory server is best understood as a starting point that teams evolve toward dedicated graph infrastructure once scale, multi-user access, or temporal validity windows become real requirements.