{"slug": "a-memory-server-remembers-your-conversation-that-is-not-the-same-as-knowing-your", "title": "A memory server remembers your conversation. That is not the same as knowing your code.", "summary": "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.", "body_md": "Before publishing:set`published: true`\n\n, and check`canonical_url`\n\n— the article must\n\nexist at that URL on the site first. Without it this competes with the original in search\n\ninstead of pointing at it. Tags are from the verified top-1,000 list;`mcp`\n\nwas not in that\n\ncache and is not used here.\n\nA session ends. Your agent had worked out, over forty minutes, that the retry logic lives in\n\none service and the thing that gives up on it lives in another, that the queue name is spelled\n\ntwo different ways, and that the person to ask about any of it left last year. Tomorrow you\n\nopen a new session and it knows none of that. Neither does your colleague's session. Neither\n\ndoes the agent reviewing the pull request that comes out of it.\n\nIt is the same forty minutes a new engineer spends in week one, and the same forty minutes the\n\nREADME would have saved if it were still true. It is why a manager asking \"where is this up to\"\n\nhas to interrupt someone who knows. The knowledge exists; it has nowhere to live but in people\n\nand chat logs.\n\nThe reflex is to reach for memory. That reflex is worth interrogating, because there are two\n\ndifferent problems hiding under one word, and only one of them is what memory servers are for.\n\nIt helps to be exact, because \"MCP memory\" gets said as though it were a feature of the\n\nprotocol. It is not — and the current revision makes that harder to miss rather than easier.\n\nRead the base protocol's own three-line summary in revision `2026-07-28`\n\n: JSON-RPC message\n\nformat, **stateless, self-contained requests**, per-request capability negotiation. Servers\n\noffer three features — Resources, Prompts and Tools. Clients offer one: Elicitation. Sampling\n\nand Roots, which used to make that three, were deprecated in this same revision under SEP-2577,\n\nalong with Logging and Dynamic Client Registration; the migration note against Sampling reads\n\n\"integrate directly with LLM provider APIs\".\n\nThere is no memory primitive and no persistence primitive. There is no memory *extension*\n\neither — the official list is the two authorization extensions, MCP Apps, Skills over MCP, and\n\nTasks. Tasks is the one worth pre-empting, because it advertises \"durable handles\" and that\n\nsounds adjacent: a task ID survives a disconnect so a client can resume polling a long-running\n\ncall, it carries a TTL, and what it holds is the status and eventual result of that one call.\n\nIt is durable in the sense a job ID is durable. It is not somewhere knowledge goes to live.\n\nSo every memory you have seen over MCP is a server implementing memory with ordinary tools.\n\nAnthropic's own Memory MCP server keeps a knowledge graph in a JSONL file; other community\n\nservers do the same job over different storage. Claude Code, separately from MCP altogether,\n\nships Auto Memory — a `MEMORY.md`\n\nper project, on by default since 2.1.59.\n\nThis is a compliment to those projects, not a criticism. They took a gap the protocol\n\ndeliberately left open and filled it with plain tools — exactly what the tool primitive is for.\n\nA memory server stores what was said. Your preferences. The decision you made on Tuesday and\n\nthe reason you gave. The fact that you want British spelling and no bullet lists. Entities,\n\nrelations and observations, accumulated from conversation.\n\nTwo properties of that content matter here.\n\nIt is **personal**. My conversational memory is a bad thing to hand to you. It contains my\n\nhalf-formed conclusions, my shortcuts, and things I said and then revised. Sharing it is not\n\nan unimplemented feature; it is a category error. The value is that it is *mine*.\n\nIt is **stated**. It is true because someone asserted it. Nothing in the repository can\n\ncontradict it, because it was never derived from the repository in the first place.\n\nFor remembering a conversation, both properties are correct. Now hold them against the other\n\nproblem.\n\n\"Where is this symbol used, in every repository, with file and line\" is not personal. There is\n\nexactly one right answer and everybody who has read access to those repositories is entitled\n\nto the same one. Storing it per person means storing the same fact many times and being wrong\n\nin a different way in each copy.\n\nIt is not stated, either. It is **derived** — a function of the current commit, and therefore\n\n**perishable** in a way conversational memory is not. If I told you on Tuesday that I prefer\n\ntabs, that is still true on Friday. If an agent noted on Tuesday that `apply_refund`\n\nhad three\n\ncallers, that is a claim about a commit, and a merge on Wednesday can make it false without\n\nanyone touching the note. A memory store cannot know that happened, because nothing said it.\n\nThat is the failure mode worth naming, and it is the same one that makes stale documentation\n\nworse than none. A remembered fact about code does not decay into silence. It decays into a\n\nconfident wrong answer, indistinguishable in tone from a right one.\n\nSo: conversation is personal, stated and durable. Code knowledge is shared, derived and\n\nperishable. Same word, opposite requirements. The fix for the second is not a better memory —\n\nit is not memory at all. It is an index that is rebuilt from the code, that many callers read,\n\nand that has a stated relationship to a commit.\n\nI build [Celmis](https://celmis-labs.github.io) and it is mine, so treat the description as a\n\nworked example rather than a recommendation. It is a self-hosted platform for most of a\n\ndevelopment cycle — the alert that arrives, the fix that goes out, the dependency and SBOM\n\nevidence underneath — and what this article is about is one layer of it: the index. It is\n\nAGPL-3.0, with a carve-out for `ee/`\n\nthat today holds no product code, and every claim below\n\nnames the file, so you can disagree with me by reading it.\n\nHere is the wider loop, so the layer this article is about has something to be a layer\n\nof. Thirty-four seconds, one real incident, every frame a screenshot of it:\n\nIt builds a tree-sitter symbol graph per repository and serves that same graph over MCP. Eight\n\nlanguages have hand-written extractors — TypeScript, Vue, Python, Go, PHP, Java, C#, C++ — and\n\nsixteen more (Ruby, Rust, Kotlin, Swift, Scala, Elixir, Dart, Lua, R, Solidity, OCaml, F#, Elm,\n\nGleam, Racket, Fortran) come from the grammar authors' own tags queries, registered at the\n\nlowest priority so a real extractor always wins. Dockerfiles, Compose files, Helm charts and CI\n\nworkflows are matched by filename or path rather than suffix, and Kubernetes manifests by\n\nsniffing the first few kilobytes for `apiVersion`\n\nand `kind`\n\n. Terraform is the ordinary case —\n\n`.tf`\n\n.\n\nThe HTTP mount registers 23 tools, eighteen of which read and five of which write. A sample of\n\nwhat the read half returns:\n\n`search_symbols`\n\n— name, kind, file, line, signature and repo slug, for definitions matching\na name across every repository in a project.`find_consumers`\n\n— who calls a symbol, with repo, file and line. The list of what breaks.`get_api_surface`\n\n— functions whose `get_architecture`\n\n— the cached orientation summary for a repository, with the model that\nproduced it and the timestamp, so you can see how old it is.`get_owner`\n\n— top git-blame authors plus matched CODEOWNERS entries for a path. This is the\none that answers \"who do I ask\" without asking.`list_accessible_repos`\n\nand `get_my_access`\n\n— the agent asking what it is allowed to look at,\nand being told which path globs are denied.`start_integration_walk`\n\n— an ordered checklist of the other tool calls, returned as data, for\na client that would otherwise fire ten guesses.Three things about that list are load-bearing.\n\n**It is the same index, not a copy.** The MCP tools open `settings.repo_graph_path(slug)`\n\n. So\n\ndoes the retrieval layer answering a human's question in the web UI. So does the pull-request\n\nreviewer. One graph file per repository, three readers. Celmis does hold its own clone and index\n\nit — one copy, on your infrastructure, not one per agent or per session.\n\n**It is the same access rules, with one exception I will name.** Every tool that returns code,\n\nownership or review content calls `caller_access`\n\n, which calls `resolve_access`\n\nfrom\n\n`src/access`\n\n— the identical function behind the human REST endpoint and behind multi-repository\n\nquestion answering. A repository you may not research is omitted and named in `blocked_repos`\n\n;\n\na denied path is filtered out of the matches, and `search_symbols`\n\nalso reports how many it hid,\n\nin `hidden_symbol_count`\n\n, though not every tool yet returns that count. The exception:\n\n`list_deprecations`\n\nreads its table today without a workspace or access predicate. That is a\n\nbug on my side, not a design, and it is being fixed. While I am being exact: the scope filter on\n\n`tools/list`\n\nis listing hygiene, not authorisation — a scoped read client is not *shown* the\n\nwrite tools, but the HTTP mount carries no per-call scope check, and a token with no scopes sees\n\neverything. Writes are gated on the token resolving to a workspace, not on its scopes. Do not\n\ntreat a read scope as a boundary.\n\n**It has a stated relationship to a commit.** A daily sweep runs `git ls-remote`\n\n— one network\n\nround trip, no clone, no fetch — and compares the branch head with `last_indexed_sha`\n\n. It\n\nreports three outcomes, not two: up to date, behind, and *could not tell*, because a check that\n\ncannot reach the remote and renders as \"no new changes\" is worse than no check. Behind enqueues\n\nan incremental pass that diffs `last_sha..HEAD`\n\n, drops the symbols for every touched file and\n\nre-extracts them, rather than re-parsing the whole repository because one file moved.\n\nThe stdio server carries a raw-Cypher escape hatch too: it tokenises the query and rejects any\n\nof eleven write keywords before running it — a denylist, not a parser, as its own docstring says.\n\nIt is not one of the HTTP mount's 23.\n\nCelmis's MCP server has no memory. Zero hits for memory, persist, recall or remember across\n\n`src/mcp_server/`\n\n. It will not remember that you decided to deprecate the old endpoint, or why.\n\nThat is conversational, it is yours, and a memory server is the right tool for it — run one\n\nalongside, and let it keep the decisions while the index keeps the code.\n\nThe honest claim is narrower than \"your agent finally has long-term memory\", and better. The\n\nnext engineer's agent starts out knowing what yours knew about the code, because that knowledge\n\nwas never in your chat log to begin with. It is in an index, derived from the commit, readable\n\nby every session under the same rules, and rebuilt when the commit moves.\n\n*I build Celmis — self-hosted, AGPL-3.0 ( ee/ carve-out, empty\ntoday), docker compose. Its pull-request reviewer placed 17th of 50 on the Martian Code Review\nBench offline set — seventeenth under all three judges, F1 between 42.7% and 47.5% depending on\nwho is judging. That is a deliberately unflattering number about one surface of the product and\nit stays. The cross-repository capability described above contributed nothing to it: the\nbenchmark set is isolated single-repository pull requests and the graph came back empty on all\n50, so nothing in that table is evidence for or against this path. Check it the way I would want\nit checked — register two services, put them in one project, call find_consumers with a symbol\nyou know one calls in the other, and see whether the repo, file and line are right.*", "url": "https://wpnews.pro/news/a-memory-server-remembers-your-conversation-that-is-not-the-same-as-knowing-your", "canonical_source": "https://dev.to/constantinemakoid/a-memory-server-remembers-your-conversation-that-is-not-the-same-as-knowing-your-code-2mjc", "published_at": "2026-09-01 12:43:48+00:00", "updated_at": "2026-09-01 12:54:22.808995+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-agents", "developer-tools"], "entities": ["Anthropic", "MCP", "Claude Code", "SEP-2577"], "alternates": {"html": "https://wpnews.pro/news/a-memory-server-remembers-your-conversation-that-is-not-the-same-as-knowing-your", "markdown": "https://wpnews.pro/news/a-memory-server-remembers-your-conversation-that-is-not-the-same-as-knowing-your.md", "text": "https://wpnews.pro/news/a-memory-server-remembers-your-conversation-that-is-not-the-same-as-knowing-your.txt", "jsonld": "https://wpnews.pro/news/a-memory-server-remembers-your-conversation-that-is-not-the-same-as-knowing-your.jsonld"}}