MCP Memory Server: What the Protocol Standardises, What It Leaves to the Backend, and How to Choose or Build One

AI Agent MemoryClaude Code & Coding AgentsGaurav Dadhich29 October 202619 min read
MCP Memory Server: What the Protocol Standardises, What It Leaves to the Backend, and How to Choose or Build One
On this page
  1. What MCP standardises for a memory server, and what it leaves to the backend
  2. What MCP standardises
  3. What MCP 2026-07-28 changed for memory servers
  4. What MCP leaves to the memory backend
  5. The official reference memory server: what it does, and where it stops
  6. How to choose an MCP memory server
  7. How to build an MCP memory server
  8. Codebase memory over MCP
  9. How to test an MCP memory server before you rely on it
  10. Where Synap fits
  11. Frequently asked questions
  12. Sources

Published 29 October 2026. Every protocol detail below was read from the MCP specification, revision 2026-07-28, and every server detail from that project's own README or documentation, on 29 October 2026.

An MCP memory server is an ordinary Model Context Protocol server whose tools happen to read and write memory, and the protocol knows almost nothing about the memory part. MCP standardises how a client discovers and calls those tools, how a store can be read as a resource and watched for changes, the two transports a server can run on, and OAuth 2.1 for servers reached over HTTP. It defines no memory schema, no extraction step, no rule for which fact wins when two disagree, no notion of whose memory a call is allowed to see, no meaning for "delete" beyond a hint, and no concept of a fact going stale. The spec itself uses memory as its example of a closed system: the openWorldHint annotation is documented with the line "the world of a web search tool is open, whereas that of a memory tool is not" (schema reference).

That split decides almost every choice you make. Two memory servers can expose the same verbs, pass the same tools/list, and still behave in opposite ways the first time a user changes their mind, because MCP carries the call and the backend decides what the call means. The official reference memory server (@modelcontextprotocol/server-memory, version 2.0.1, published to npm on 28 October 2026) is a clean illustration: nine tools, a local JSONL file, string matching, and nothing that reconciles a contradiction.

What MCP standardises for a memory server, and what it leaves to the backend

LayerWhat MCP 2026-07-28 standardisesWhat the memory backend decides
ToolsDiscovery through tools/list, JSON Schema inputs and outputs, structured results, behaviour hints (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)Which verbs exist, what each one stores, and whether the hints are true
Resourcesresources/read, URI templates, change notifications over subscriptions/listen, cache hints (ttlMs, cacheScope)Whether memory is exposed as a resource at all, and how fresh a read really is
Transportstdio for a client-launched local process, Streamable HTTP for a server many clients reachWhether the store behind either transport is shared, per machine or per process
AuthOAuth 2.1 resource-server rules for HTTP, credentials from the environment for stdio, tokens bound to one serverWhich user, tenant or project a valid token maps to
ExtractionNothingWhat gets written: raw text, model-written facts, or facts the backend extracts with its own LLM
ConflictsNothingAppend, overwrite, or supersede with history
ScopingNothing since sessions were removed; cross-call state travels as ordinary tool argumentsIsolation between users, agents, projects and tenants
DeletionA destructiveHint on the toolWhat is actually removed, from which indexes and copies, and how you prove it
StalenessCache lifetimes for list and read resultsWhether a fact carries time, and whether retrieval prefers the current one

If MCP itself is new to you, MCP Servers Explained covers hosts, clients and servers first.

What MCP standardises

Tools: discovery, schemas and behaviour hints

Tools are the surface a model actually uses. A client lists them with tools/list, each tool declares an inputSchema (JSON Schema, 2020-12 by default) and may declare an outputSchema, and results can carry structuredContent alongside text (tools spec). The spec says there SHOULD always be a human in the loop with the ability to deny a tool invocation, which matters more for a forget tool than for most.

Annotations are the part memory servers most often skip. readOnlyHint defaults to false, destructiveHint defaults to true, idempotentHint defaults to false and openWorldHint defaults to true, so a memory server that declares nothing is telling every client that each of its tools may destroy data in an open world. The reference server gets this right: its create and add tools declare destructiveHint: false, its three delete tools declare destructiveHint: true and idempotentHint: true, its read tools declare readOnlyHint: true, and every tool declares openWorldHint: false (source). The schema also says plainly that annotations are hints, that they are not guaranteed to describe the tool faithfully, and that clients should never make tool-use decisions based on annotations from untrusted servers.

The 2026-07-28 revision added one rule that has a cost attached for memory: servers SHOULD return tools/list in a deterministic order "to enable client-side caching and improve LLM prompt cache hit rates" (changelog). Every tool description sits in the model's context on every turn, so a memory server with a long, reshuffling tool list costs tokens and cache hits on every call, which is why some servers now list a small core set and keep the rest callable by name.

Resources: memory as something a client can read and watch

A server can also expose memory as a resource with a URI. The reference server publishes the whole graph as memory://knowledge-graph with MIME type application/json, and every mutation tool emits notifications/resources/updated for that URI so a subscribed client sees the change. Under 2026-07-28 a client subscribes by naming the URI in the resourceSubscriptions of a subscriptions/listen request; the older resources/subscribe method is gone from the new revision (resources spec).

Two new required fields on list and read results matter for anything user-specific. ttlMs is a freshness hint in milliseconds, and cacheScope is either "public", meaning any client or shared intermediary may cache the response across authorization contexts, or "private", meaning the response may be reused only within the same authorization context. A memory resource is user data by definition, so it should always be "private"; a gateway that caches a "public" memory read can serve one user's memories to another. Our MCP 2026-07-28 migration guide covers that failure as "list results served to the wrong tenant".

Transports: stdio for one machine, Streamable HTTP for everyone else

MCP defines two standard transports (transports spec). stdio is newline-delimited JSON-RPC over the standard streams of a subprocess the client launches, so every client that starts the server gets its own process. Streamable HTTP sends each message as an HTTP POST to one endpoint and returns a JSON object or a request-scoped event stream, so one server can answer many clients, machines and people. A Streamable HTTP server MUST validate the Origin header and, when running locally, SHOULD bind to 127.0.0.1 rather than every interface (Streamable HTTP binding). The older HTTP+SSE transport is deprecated.

For memory this is the first real decision. A stdio server can only share memory through whatever it writes to disk; a Streamable HTTP server can share it with anyone who can reach the endpoint. Every server in the official repository serves stdio, and only the Everything demo server also serves Streamable HTTP (servers README), so the reference memory server is a single-machine tool by construction.

Authorization: OAuth 2.1 over HTTP, the environment over stdio

Authorization is optional in MCP (authorization spec). When a server supports it over HTTP, it acts as an OAuth 2.1 resource server: it MUST publish OAuth 2.0 Protected Resource Metadata (RFC 9728), clients send the RFC 8707 resource parameter so tokens are minted for that server, the server MUST validate that a token was issued for it, and it MUST NOT accept or pass through any other token. Dynamic Client Registration is deprecated in favour of Client ID Metadata Documents. A stdio server SHOULD NOT follow any of this and should "instead retrieve credentials from the environment".

Optional means some servers ship with none. The Graphiti MCP server README says it has "no authentication, no authorization, and no prompt-injection protection", that the omissions are intentional, and that any caller can read, change or delete all graph data. And even a server that implements every OAuth rule has only proven who the caller is; which memories that identity may see is still a backend decision.

What MCP 2026-07-28 changed for memory servers

The July revision changed the wire protocol itself, and four of its changes land directly on memory.

Sessions are gone, so scope has to travel somewhere else. The revision removed the initialize handshake and the Mcp-Session-Id header; servers that need cross-call state now use "explicit, server-minted handles passed as ordinary tool arguments" (SEP-2567). Some memory guides published this month still describe Mcp-Session-Id as how Streamable HTTP keeps state. A memory server that keyed short-term memory or user scope off the session needs to take it from the token, from an explicit handle the server returned earlier, or from configuration.

Sampling is deprecated, so extraction needs its own model. A 2025-era server could ask the client's model to do work through sampling/createMessage. 2026-07-28 deprecates Sampling (with Roots and Logging), and its suggested migration is to "integrate directly with LLM provider APIs instead". A memory server that extracts facts from conversation either calls its own model or leaves the extraction to the calling model's tool arguments.

Long writes have a standard place to report progress. Experimental tasks moved into an official extension, io.modelcontextprotocol/tasks, with polling through tasks/get. Memory backends that extract in the background can use it, or expose a plain status tool; either way the client needs some way to know a write has become searchable before it tests recall.

Server-initiated requests became retries. The Multi Round-Trip Requests pattern replaces server-to-client requests: a server returns resultType: "input_required" and the client retries with the answer. A memory server that wants a person to confirm a bulk delete would ask for it this way.

The reference server handles the version split by serving both eras on stdio from one process; the client's first message, server/discover or the old initialize, decides the era of the connection (README). Check that any server you adopt does the same, or at least states which revision it speaks.

What MCP leaves to the memory backend

Extraction: what actually gets written

MCP has no concept of extraction. Every memory server therefore picks one of two designs. In the first, the calling model does the work: it decides a fact is worth keeping and writes it in the shape the tool asks for, as the reference server's create_entities and add_observations expect. In the second, the client sends raw text or a whole exchange and the backend runs its own pipeline to pull out facts, entities and preferences, which is how Mem0's hosted server and Graphiti work.

The first design costs nothing to run and is only as good as the model's judgement on that turn, in that prompt. The second is consistent across clients and costs an LLM call per write on the backend. Neither design decides when the model calls the tool in the first place: a server adds tools, and a model calls them when a system prompt, an instruction file or a hook tells it to. Claude Code, Codex and Cursor memory shows that wiring for three coding agents.

Conflict handling: append, overwrite or supersede

When a user says "I moved to Berlin" after saying "I live in Pune", the protocol carries both calls and has no opinion. The reference server stores observations as strings; nothing reconciles them, so both survive until something deletes one. Mem0's MCP server offers update_memory, which overwrites a memory's text after the model confirms its ID. Graphiti's search tools accept valid_at and invalid_at date filters over a temporally aware graph. Those are three different answers (keep both, replace, keep both with time), and the right one depends on whether you ever need to know what was true before.

Scoping: whose memory a call can see

There is no tenant, user or project field anywhere in the MCP spec, and since July there is no session either. Scope comes from three places: the identity in the access token, arguments on the tool call, or server configuration. Each server picks its own. Mem0's tools address user, agent, app and run entities as arguments; Graphiti separates data by a group_id namespace; Cognee MCP runs either standalone, where each instance keeps its own data, or in API mode, where several instances share one graph.

Scope taken from a tool argument is only as safe as the model that fills it in. A prompt-injected or confused model can pass another user's ID. Derive the user and tenant from the authenticated token on the server, and treat any scope argument as a narrowing filter inside that, never as the grant itself. Multi-agent shared memory goes deeper on scope chains across agents, runs, users and tenants.

Deletion: what "forget" removes

The only thing MCP says about deletion is destructiveHint, and it is a hint. What the call removes is up to the backend. The reference server rewrites its JSONL file without the deleted records, and deleting an entity cascades to its relations. Mem0's MCP server has delete_memory, delete_all_memories and delete_entities. Graphiti's delete_episode cascades to the entities and facts that episode alone created. None of these tells you about derived copies such as embeddings, summaries, caches or backups, and that is the question a privacy request will actually ask.

Staleness: whether a fact knows how old it is

ttlMs tells a client how long it may cache a list or a read; it says nothing about how old the facts inside are. Resources, and resource links embedded in tool results, can carry a lastModified annotation, but nothing requires a memory server to set it, and a plain text result carries none. Whether a memory carries the time it was learned, and whether retrieval prefers the newer of two similar facts, is entirely the backend's. The reference server stores no timestamps in its schema.

The official reference memory server: what it does, and where it stops

The Knowledge Graph Memory Server stores three kinds of object: entities (a unique name, an entity type and a list of observations), directed relations written in active voice, and observations (atomic string facts). It exposes nine tools: create_entities, create_relations, add_observations, delete_entities, delete_observations, delete_relations, read_graph, search_nodes and open_nodes. search_nodes matches the query against entity names, entity types and observation text; there are no embeddings.

Setup is one config block. With npm it runs as npx -y @modelcontextprotocol/server-memory and needs Node.js 24 or later; with Docker it runs as docker run -i -v claude-memory:/app/dist --rm mcp/memory, where the named volume keeps the graph after the container exits. Set MEMORY_FILE_PATH to choose where the JSONL file lives; by default it is memory.jsonl in the server's directory.

{
  "mcpServers": {
    "memory": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-memory"],
      "env": { "MEMORY_FILE_PATH": "/Users/you/.agent-memory/memory.jsonl" }
    }
  }
}

Two clients on one machine can share it. Each starts its own server process, so every write takes an exclusive .lock file next to the memory file; a holder refreshes it every 15 seconds, a lock not refreshed for 30 seconds is treated as abandoned, and a write that cannot get the lock within 60 seconds fails with a tool error rather than overwriting the file. The README warns that a network filesystem that does not honour exclusive file creation cannot be shared safely this way. Two teammates on two laptops get two separate graphs.

The repository is candid about the rest: its servers are "reference implementations" meant "as educational examples for developers building their own MCP servers, not as production-ready solutions" (servers README). In practice that means literal-match recall (search_nodes is a case-insensitive substring match on the whole query, so a search for "PostgreSQL" will not find an observation that says "Postgres", and "the database we picked" finds nothing), no time on any fact, no supersession, read_graph returning everything at once, stdio only and no authentication. It is the right way to learn the tool loop, and a good fit for one person's preferences on one machine.

How to choose an MCP memory server

Since the protocol guarantees the call and not the behaviour, a choice comes down to the backend questions, asked in this order:

  1. Where does the store live, and who can reach it? It may be a file on one laptop, a database you run, or a hosted service, and only the last two serve a team without you building sync.
  2. Where does scope come from? It can come from the token, a tool argument or configuration, and servers that derive identity from authentication are the safer default.
  3. Who extracts? Either the calling model or the backend's own pipeline does, and the second one costs a model call per write.
  4. What happens when a fact changes? A server appends, overwrites, or supersedes the old fact and keeps it as history.
  5. What does delete remove? Find out whether it removes the record only or every derived copy, and whether you get something you can show an auditor.
  6. How big is the tool list, and is it annotated? Count the tools, since each description costs context on every turn, and read the hints.
  7. Which protocol revision does it speak? Prefer a server that speaks 2026-07-28 or serves both eras, since clients are moving at different speeds.

Five servers in wide use answer the first five of those questions like this, according to their own documentation on 29 October 2026:

ServerWhere the store livesScopeWho extractsChanged factsDelete
Reference serverJSONL file per machine, stdio onlyNone; one graph per fileCalling modelBoth kept until deletedRewrites the file; entity delete cascades to relations
Mem0 MCPHosted at mcp.mem0.ai, "nothing runs on your machine"User, agent, app or run entities as tool arguments; browser sign-in or API keyBackendupdate_memory overwrites after confirming the IDSingle memory, all in scope, or an entity with its memories
Graphiti MCP (experimental)FalkorDB (default) or Neo4j you run; HTTP at /mcp/group_id namespace; no authentication by designBackend, with your LLM providerTemporal graph with valid_at and invalid_at filtersEpisode delete cascades to what it alone created; clear_graph
Cognee MCPLocal SQLite, LanceDB and an embedded graph store in standalone mode, or a shared Cognee backend in API modeSeparate data per instance in standalone mode; in API mode each instance uses one token, so its writes belong to one Cognee userBackend builds the graph on ingestion; cognify_status reports background jobsNot described on the MCP tools pageforget removes one item, a dataset, or all memory the user owns; optional clean_history
Basic MemoryMarkdown files on your disk, optional cloud, AGPL-3.0Per project, named on each tool call; shared workspace on its cloud planCalling model writes Markdown notesNotes edited in place with bm_editbm_delete; deleting a whole project needs server opt-in

The pattern in that table is the point. Every row speaks MCP, and no two rows agree on scope, extraction or what happens to a changed fact. Moving from one to another changes your agent's behaviour even though the client configuration barely changes, so the portability MCP gives you is portability of plumbing, not of memory.

How to build an MCP memory server

If you build your own, the protocol hands you the envelope and you write the semantics. A minimum contract that keeps those semantics explicit looks like four or five tools: one to write (text or a structured fact), one to search with a result cap, one to fetch by ID, one to delete by ID, and, if writes are processed in the background, one to report whether a write is searchable yet (or the tasks extension). Annotate every one of them, declare an outputSchema so results are structured, and keep the list ordered.

{
  "name": "forget_memory",
  "description": "Permanently delete one memory by id for the authenticated user, including its search index entry.",
  "inputSchema": {
    "type": "object",
    "properties": { "memory_id": { "type": "string" } },
    "required": ["memory_id"],
    "additionalProperties": false
  },
  "annotations": {
    "readOnlyHint": false,
    "destructiveHint": true,
    "idempotentHint": true,
    "openWorldHint": false
  }
}

The decisions that take real time are the ones the table above lists: deriving the user and tenant from the token on every call, deciding what a contradiction does, recording where each memory came from, and making delete reach every index. Serve Streamable HTTP for anything shared, validate Origin, bind to localhost in development, mark memory resources "private", and plan for both protocol eras until your clients have all moved.

Codebase memory over MCP

Coding agents need a memory server for a specific reason: Claude Code, Codex and Cursor each forget a repository between sessions. Two designs exist. A notes server stores text about the code, such as decisions, conventions and why a library was rejected, and retrieves it by search; it is easy to run and goes stale the moment the code changes, because nothing ties the note to the code. A code-graph server indexes the repository itself, with files and symbols as nodes and imports and calls as edges, so it can answer "what calls this function" deterministically and re-index when the code moves. Most teams want both: the graph for structure, notes for the reasons behind it. Whatever you pick, scope memory per repository so a fact about one project never surfaces in another, and make sure every agent that works on the code reaches the same store, which over stdio means a shared file on one machine and over HTTP means one endpoint.

How to test an MCP memory server before you rely on it

Run five checks with the real clients you will use. Write a distinctive fact in one session and recall it from a new session after restarting the client. Correct the fact and see whether search returns the new one, the old one, or both. Write as one user or project and search as another, and confirm nothing comes back. Delete the fact and confirm it is gone from search and from any resource read. And if writes are processed in the background, measure how long until a write is searchable, so your tests do not fail on timing.

Where Synap fits

Maximem Synap is a memory layer with a hosted MCP endpoint alongside its SDKs, REST API and framework adapters. The endpoint exposes four tools: log an exchange, check whether it finished processing, recall context, and list recent memories. Extraction happens in the backend, so the model forwards everything and Synap decides what matters. The endpoint holds no secrets; the API key arrives per request and is never stored beyond that request, and a self-hosted MCP adapter is supported. Synap is built around the backend half of the table at the top: memory is isolated by default across account, tenant, individual and conversation, every memory carries provenance (where it came from, what it replaced and why), and when something changes the agent stops repeating what is no longer true without losing the history.

Frequently asked questions

What is an MCP memory server?

An MCP memory server is a Model Context Protocol server whose tools store and retrieve information that outlives a conversation, so any MCP client can save a fact in one session and recall it in another. MCP standardises how the client finds and calls the tools; the server's backend decides what is stored, how it is searched, and what happens when facts change or are deleted.

What does MCP standardise for memory?

The 2026-07-28 specification standardises tool discovery and schemas, tool behaviour hints such as readOnlyHint and destructiveHint, resources with change subscriptions and cache hints, the stdio and Streamable HTTP transports, and OAuth 2.1 authorization for HTTP servers. It defines no memory schema, extraction, conflict handling, scoping, deletion semantics or staleness.

Is the official MCP memory server production-ready?

No, by its own repository's description. The servers in modelcontextprotocol/servers are "reference implementations" and "not production-ready solutions". The memory server runs over stdio only, has no authentication, matches search terms literally, and stores no time on facts, which suits one person's preferences on one machine.

Can Claude Code and Cursor share one MCP memory server?

On one machine, yes: point both at the same MEMORY_FILE_PATH and the reference server's lock file serialises their writes. Across machines or people, you need a server reachable over Streamable HTTP with one shared backend, since each stdio client starts its own process.

Does MCP make agent memory portable between vendors?

It makes the connection portable, not the behaviour. Any MCP client can call any MCP memory server, but tool names, scope, extraction and conflict handling differ between servers, so switching backends changes what your agent remembers even when the configuration change is one line.

What changed for MCP memory servers in the 2026-07-28 spec?

Sessions and the Mcp-Session-Id header were removed, so scope must come from the token, tool arguments or configuration. Sampling was deprecated, so servers that extract facts need their own model. Subscriptions moved to subscriptions/listen, and list and read results now carry ttlMs and cacheScope, which should be "private" for user memory.

Sources

From the team at Maximem

Stop rebuilding agent memory from scratch

Maximem Synap is the context management layer we built after hitting every problem in this post ourselves. Persistent recall across sessions, entity resolution and conscious forgetting, in Python, TypeScript and REST.

Related posts

Looking for more to read? See our directory of the best engineering blogs to follow.