cd /news/artificial-intelligence/a-memory-server-remembers-your-conve… · home topics artificial-intelligence article
[ARTICLE · art-117706] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

A memory server remembers your conversation. That is not the same as knowing your code.

A developer argues that memory servers for AI agents, such as those built on the Model Context Protocol (MCP), are designed to store conversational context, not code knowledge. The post highlights that MCP lacks a memory primitive, and that memory servers like Anthropic's Memory MCP server use ordinary tools to persist personal, stated information, which is distinct from the factual, repository-derived knowledge needed for code understanding.

read10 min views4 publishedSep 1, 2026

Before publishing:setpublished: true , and checkcanonical_url

— the article must

exist at that URL on the site first. Without it this competes with the original in search

instead of pointing at it. Tags are from the verified top-1,000 list;mcp

was not in that

cache and is not used here.

A session ends. Your agent had worked out, over forty minutes, that the retry logic lives in

one service and the thing that gives up on it lives in another, that the queue name is spelled

two different ways, and that the person to ask about any of it left last year. Tomorrow you

open a new session and it knows none of that. Neither does your colleague's session. Neither

does the agent reviewing the pull request that comes out of it.

It is the same forty minutes a new engineer spends in week one, and the same forty minutes the

README would have saved if it were still true. It is why a manager asking "where is this up to"

has to interrupt someone who knows. The knowledge exists; it has nowhere to live but in people

and chat logs.

The reflex is to reach for memory. That reflex is worth interrogating, because there are two

different problems hiding under one word, and only one of them is what memory servers are for.

It helps to be exact, because "MCP memory" gets said as though it were a feature of the

protocol. It is not — and the current revision makes that harder to miss rather than easier.

Read the base protocol's own three-line summary in revision 2026-07-28

: JSON-RPC message format, stateless, self-contained requests, per-request capability negotiation. Servers

offer three features — Resources, Prompts and Tools. Clients offer one: Elicitation. Sampling

and Roots, which used to make that three, were deprecated in this same revision under SEP-2577,

along with Logging and Dynamic Client Registration; the migration note against Sampling reads

"integrate directly with LLM provider APIs".

There is no memory primitive and no persistence primitive. There is no memory extension

either — the official list is the two authorization extensions, MCP Apps, Skills over MCP, and

Tasks. Tasks is the one worth pre-empting, because it advertises "durable handles" and that

sounds adjacent: a task ID survives a disconnect so a client can resume polling a long-running

call, it carries a TTL, and what it holds is the status and eventual result of that one call.

It is durable in the sense a job ID is durable. It is not somewhere knowledge goes to live.

So every memory you have seen over MCP is a server implementing memory with ordinary tools.

Anthropic's own Memory MCP server keeps a knowledge graph in a JSONL file; other community

servers do the same job over different storage. Claude Code, separately from MCP altogether,

ships Auto Memory — a MEMORY.md

per project, on by default since 2.1.59.

This is a compliment to those projects, not a criticism. They took a gap the protocol

deliberately left open and filled it with plain tools — exactly what the tool primitive is for.

A memory server stores what was said. Your preferences. The decision you made on Tuesday and

the reason you gave. The fact that you want British spelling and no bullet lists. Entities,

relations and observations, accumulated from conversation.

Two properties of that content matter here.

It is personal. My conversational memory is a bad thing to hand to you. It contains my

half-formed conclusions, my shortcuts, and things I said and then revised. Sharing it is not

an unimplemented feature; it is a category error. The value is that it is mine.

It is stated. It is true because someone asserted it. Nothing in the repository can

contradict it, because it was never derived from the repository in the first place.

For remembering a conversation, both properties are correct. Now hold them against the other problem.

"Where is this symbol used, in every repository, with file and line" is not personal. There is

exactly one right answer and everybody who has read access to those repositories is entitled

to the same one. Storing it per person means storing the same fact many times and being wrong

in a different way in each copy.

It is not stated, either. It is derived — a function of the current commit, and therefore

perishable in a way conversational memory is not. If I told you on Tuesday that I prefer

tabs, that is still true on Friday. If an agent noted on Tuesday that apply_refund

had three

callers, that is a claim about a commit, and a merge on Wednesday can make it false without

anyone touching the note. A memory store cannot know that happened, because nothing said it.

That is the failure mode worth naming, and it is the same one that makes stale documentation

worse than none. A remembered fact about code does not decay into silence. It decays into a

confident wrong answer, indistinguishable in tone from a right one.

So: conversation is personal, stated and durable. Code knowledge is shared, derived and

perishable. Same word, opposite requirements. The fix for the second is not a better memory —

it is not memory at all. It is an index that is rebuilt from the code, that many callers read,

and that has a stated relationship to a commit.

I build Celmis and it is mine, so treat the description as a worked example rather than a recommendation. It is a self-hosted platform for most of a

development cycle — the alert that arrives, the fix that goes out, the dependency and SBOM

evidence underneath — and what this article is about is one layer of it: the index. It is

AGPL-3.0, with a carve-out for ee/ that today holds no product code, and every claim below

names the file, so you can disagree with me by reading it.

Here is the wider loop, so the layer this article is about has something to be a layer

of. Thirty-four seconds, one real incident, every frame a screenshot of it:

It builds a tree-sitter symbol graph per repository and serves that same graph over MCP. Eight

languages have hand-written extractors — TypeScript, Vue, Python, Go, PHP, Java, C#, C++ — and

sixteen more (Ruby, Rust, Kotlin, Swift, Scala, Elixir, Dart, Lua, R, Solidity, OCaml, F#, Elm,

Gleam, Racket, Fortran) come from the grammar authors' own tags queries, registered at the

lowest priority so a real extractor always wins. Dockerfiles, Compose files, Helm charts and CI

workflows are matched by filename or path rather than suffix, and Kubernetes manifests by

sniffing the first few kilobytes for apiVersion

and kind

. Terraform is the ordinary case —

.tf

.

The HTTP mount registers 23 tools, eighteen of which read and five of which write. A sample of

what the read half returns:

search_symbols

— name, kind, file, line, signature and repo slug, for definitions matching a name across every repository in a project.find_consumers

— who calls a symbol, with repo, file and line. The list of what breaks.get_api_surface

— functions whose get_architecture

— the cached orientation summary for a repository, with the model that produced it and the timestamp, so you can see how old it is.get_owner

— top git-blame authors plus matched CODEOWNERS entries for a path. This is the one that answers "who do I ask" without asking.list_accessible_repos

and get_my_access

— the agent asking what it is allowed to look at, and being told which path globs are denied.start_integration_walk

— an ordered checklist of the other tool calls, returned as data, for a client that would otherwise fire ten guesses.Three things about that list are load-bearing.

It is the same index, not a copy. The MCP tools open settings.repo_graph_path(slug)

. So

does the retrieval layer answering a human's question in the web UI. So does the pull-request

reviewer. One graph file per repository, three readers. Celmis does hold its own clone and index

it — one copy, on your infrastructure, not one per agent or per session.

It is the same access rules, with one exception I will name. Every tool that returns code,

ownership or review content calls caller_access

, which calls resolve_access

from

src/access

— the identical function behind the human REST endpoint and behind multi-repository

question answering. A repository you may not research is omitted and named in blocked_repos

;

a denied path is filtered out of the matches, and search_symbols

also reports how many it hid,

in hidden_symbol_count

, though not every tool yet returns that count. The exception:

list_deprecations

reads its table today without a workspace or access predicate. That is a

bug on my side, not a design, and it is being fixed. While I am being exact: the scope filter on

tools/list

is listing hygiene, not authorisation — a scoped read client is not shown the

write tools, but the HTTP mount carries no per-call scope check, and a token with no scopes sees

everything. Writes are gated on the token resolving to a workspace, not on its scopes. Do not

treat a read scope as a boundary.

It has a stated relationship to a commit. A daily sweep runs git ls-remote

— one network

round trip, no clone, no fetch — and compares the branch head with last_indexed_sha

. It

reports three outcomes, not two: up to date, behind, and could not tell, because a check that

cannot reach the remote and renders as "no new changes" is worse than no check. Behind enqueues

an incremental pass that diffs last_sha..HEAD

, drops the symbols for every touched file and

re-extracts them, rather than re-parsing the whole repository because one file moved.

The stdio server carries a raw-Cypher escape hatch too: it tokenises the query and rejects any

of eleven write keywords before running it — a denylist, not a parser, as its own docstring says.

It is not one of the HTTP mount's 23.

Celmis's MCP server has no memory. Zero hits for memory, persist, recall or remember across

src/mcp_server/

. It will not remember that you decided to deprecate the old endpoint, or why.

That is conversational, it is yours, and a memory server is the right tool for it — run one

alongside, and let it keep the decisions while the index keeps the code.

The honest claim is narrower than "your agent finally has long-term memory", and better. The

next engineer's agent starts out knowing what yours knew about the code, because that knowledge

was never in your chat log to begin with. It is in an index, derived from the commit, readable

by every session under the same rules, and rebuilt when the commit moves.

I build Celmis — self-hosted, AGPL-3.0 ( ee/ carve-out, empty today), docker compose. Its pull-request reviewer placed 17th of 50 on the Martian Code Review Bench offline set — seventeenth under all three judges, F1 between 42.7% and 47.5% depending on who is judging. That is a deliberately unflattering number about one surface of the product and it stays. The cross-repository capability described above contributed nothing to it: the benchmark set is isolated single-repository pull requests and the graph came back empty on all 50, so nothing in that table is evidence for or against this path. Check it the way I would want it checked — register two services, put them in one project, call find_consumers with a symbol you know one calls in the other, and see whether the repo, file and line are right.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @anthropic 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/a-memory-server-reme…] indexed:0 read:10min 2026-09-01 ·