Claude Code Persistent Memory Across Sessions: A Local-First MCP Setup
Claude Code is a capable coding agent, but every new terminal session starts with amnesia. It forgets the refactor plan you discussed yesterday, the API quirks you already explained twice, and the reason a certain module is off limits. Developers keep re-pasting the same context, and several long Reddit threads show people hunting for a fix. The common workaround is a CLAUDE.md file, which works, but it is a flat file you curate by hand. It does not search itself, it does not rank relevance, and it grows until nobody maintains it.
This post walks through a different approach: giving Claude Code a persistent semantic memory that survives across sessions, running entirely on your machine, with no API key for the memory layer itself. We will use Uteke, our open source memory engine, in its MCP server mode.
The problem with session-scoped context
Every serious user of coding agents hits the same wall. The agent is smart inside a session and clueless between sessions. The standard answers each have a cost:
- CLAUDE.md / AGENTS.md: manual, always loaded, no relevance ranking. You pay tokens for the whole file every session whether it matters or not.
- Copy-paste context: you become the memory system. It is your job to remember what the agent needs to know.
- Cloud memory services: they solve recall, but your project decisions and code notes leave your machine, and most want an API key and a subscription.
What most people want is narrower: a memory the agent can query when it needs to, stored locally, searchable by meaning rather than exact keywords.
How it works: Uteke as an MCP memory server
Uteke is a memory engine written in Rust, Apache-2.0 licensed, currently at v0.16.0 with over 230 stars on GitHub. Two things matter for this setup:
- Offline core: a single binary with SQLite storage, an embedded HNSW vector index, and an ONNX embedding model bundled in. No embedding API calls, no network dependency for storage or recall.
- MCP server mode: Uteke exposes its store, recall, and search operations over the Model Context Protocol, so any MCP-capable client, including Claude Code and Claude Desktop, can use it as a memory tool.
The result: Claude Code gets a recall tool it can call mid-session. When it needs to know what was decided about the auth module last week, it queries local memory instead of asking you again.
Setup
First install Uteke. On a machine with Rust:
cargo install uteke-cli
uteke initThe init command creates the local database and loads the bundled embedding model. There is no key to configure for the engine itself. Then register the MCP server with Claude Code:
claude mcp add uteke -- uteke-mcpRestart Claude Code and check that the tools are visible:
/mcpYou should see the Uteke server listed with its memory operations.
A real workflow
At the end of a session where you settled an architectural decision, store it:
uteke remember "Decided to keep the billing module on Postgres, not migrate to the new ledger service, because the ledger lacks partial refunds (agreed with Dana, sprint 41)" --source "sprint-41-design-review"Weeks later, in a fresh Claude Code session, the agent can query this itself through MCP, or you can ask it to:
uteke recall "why is billing still on postgres"Recall is hybrid: SQLite FTS5 for keyword matches plus HNSW vector search for semantic matches, merged and ranked. In our measurements, recall on a CPU-only box lands around 45ms, which is fast enough that the agent can query it multiple times per session without anyone noticing.
Decisions and trade-offs
We made choices worth being honest about.
Bundled ONNX embeddings over an embedding API. Quality per token is lower than a large hosted embedding model. We accepted that trade because the goal is memory that works on a train, in a restricted network, or on a box with no cloud spend. For codebase decisions and design notes, local embedding quality is good enough. If you need maximum retrieval quality and are fine with network calls, a hosted service may fit better.
SQLite over a server database. One file, trivially backed up, zero ops. You lose multi-writer concurrency across machines. For a single developer memory, that is the right trade.
Explicit memory over automatic capture. Uteke does not silently record your conversations. You (or the agent, when you ask) store what matters. This costs some discipline up front. In exchange, memory stays small, relevant, and auditable. Every memory can carry a --source provenance tag, so when the agent recalls a fact, you can trace where it came from.
Honest maturity note. Uteke is at v0.16.0 with a growing but still small community. It is production-minded, tested, and actively released (40+ releases so far), but it is a young project. Read the code, it is open.
What we are working on next
The consolidation command shipped: uteke dream deduplicates, flags contradictions, and cleans orphans, with a dry-run mode for preview. Current focus areas: richer room support so multiple agents can share scoped memory without cross-contamination, and smoother MCP ergonomics. If you want memory across sessions for multiple agents on the same machine, rooms are already usable today.
Getting started
The repo is at github.com/codecoradev/uteke (Apache-2.0). Install, run uteke init, register it with claude mcp add uteke -- uteke-mcp, and store your first memory. If you build something with it, issues and discussions are open.
Session amnesia in coding agents is a solvable problem, and it does not require sending your project memory to someone else's cloud. A single binary on your own machine is enough.