Cortex Protocol MCP server
Commit Nov 5, 2026Provides user-owned, cross-agent AI memory using a local SQLite database and Gemini embeddings to enable persistent context across different AI clients.
Also known as fernsdavid25/cortex-protocol
- Stars
- 2
- Tools
- —
- Downloads, 30 days
- —
- Latest version
- —
- Last commit
- Nov 5, 2026
- License
- Apache-2.0
What is Cortex Protocol MCP?
Cortex Protocol provides user-owned, cross-agent AI memory using a local SQLite database and Gemini embeddings to enable persistent context across different AI clients.
Summary generated from the project's README
About Cortex Protocol MCP server
Providing persistent, user-owned memory across different AI agents is what cortex-protocol enables through the Model Context Protocol. Developers can connect this local stdio server to clients like Claude Desktop, Cursor, VS Code, or Claude Code to ensure context remains consistent regardless of which tool is being used. The system operates using a local SQLite database and requires a Gemini API key for embeddings, ensuring that your data stays under your control without phoning home.
Users can manage their information using specific tools such as memorize to save durable content, recall to retrieve relevant memories via hybrid dense and BM25 ranking, and forget to delete specific entries. For more advanced organization, the server offers recall_about to generate dossiers on specific entities and recall_timeline to reconstruct dated event sequences. These advanced features are available by opting into memory layers using specific environment variables. Because the system uses your own API keys and a local database, you maintain full ownership of your long-term AI context.
What you can do with it
- 1Maintain context across different AI toolsConnect your memory to multiple agents so they all share the same historical knowledge.
- 2Retrieve specific past informationAsk your AI client to find the most relevant pieces of information from your saved history.
- 3Build entity dossiersRequest a complete summary of everything the AI knows about a specific person or project.
- 4Reconstruct historical timelinesAsk the AI to list events in chronological order based on your saved memories.
Written from the project's README. Every use case is checked against a quote from it.
Configuration
GEMINI_API_KEY
| Name | Description | |
|---|---|---|
| GEMINI_API_KEY | — |
README
View on GitHubCortex Protocol
🧠 One memory. Every agent. — user-owned, cross-agent AI memory over the Model Context Protocol.
Works with Claude Code · Cursor · Claude Desktop · VS Code
You own one portable memory, and any AI agent connects to it over MCP with your consent.
Self-host it as a local stdio server — a single SQLite file, your own Gemini key (BYOK), nothing
phones home — and recall does no server-side LLM generation, so the only runtime cost is your
own embedding tokens.
📊 0.932 LongMemEval_S · 0.813 LoCoMo — the only memory system publishing $/question, and the only one at 0.9+ on LongMemEval_S with a cost-efficient-tier reader: a Gemini Flash reader at ~$0.0396/question on LongMemEval_S and ~$0.0034/question on LoCoMo.† On the published tables that is #3 on LongMemEval_S and #4 on LoCoMo — but those tables mix readers, judges and question sets, so read Results before ranking anything.
† Per-question cost is computed from measured token counts at Google's confirmed list prices (paid tier) for the reader model.
Quickstart — self-host (local memory in your agent)
The local server (cortex-mcp) is a stdio MCP server: your own Gemini key (BYOK), memories in a
local SQLite file (~/.cortex/memory.db), nothing phones home.
- Get a Gemini key (free): https://aistudio.google.com/apikey
- Add Cortex to your MCP client. Every client uses the same
mcpServersshape — only the file differs:
{
"mcpServers": {
"cortex": {
"command": "uvx",
"args": ["--from", "cortex-protocol", "cortex-mcp"],
"env": { "GEMINI_API_KEY": "your-key-here" }
}
}
}
| Client | Config file |
|---|---|
| Claude Code | ~/.claude.json (global), or .mcp.json in a project |
| Cursor | ~/.cursor/mcp.json (global), or .cursor/mcp.json in a project |
| Claude Desktop | claude_desktop_config.json (Settings → Developer → Edit Config) |
| VS Code | .vscode/mcp.json |
Restart the client. That exposes six tools (the last two are gated on opt-in memory layers — see Config (env) below):
| Tool | What it does |
|---|---|
memorize(content, kind?, tags?) |
Save a durable memory (optionally classified into one of six kinds). |
recall(query, limit?) |
Retrieve the most relevant memories (hybrid dense + BM25, RRF; no LLM generation). |
list_memories(limit?) |
List the most recent memories. |
forget(memory_id) |
Delete a memory (a short id prefix works if unambiguous). |
recall_about(entity, limit?) |
Exhaustive dossier for one entity — a person, place, project, org, thing, or yourself — every relationship plus every memory attached to it. A pure keyed read, no LLM/embedding call. Requires CORTEX_GRAPH=1. |
recall_timeline(since?, until?, limit?) |
Dated event timeline — memories ordered by their extracted event_time (for "what happened when" questions), optionally bounded by ISO dates. A pure keyed read, no LLM/embedding call. Requires CORTEX_EPISODIC=1. |
From a checkout (to run your own working copy instead of the published package):
python -m cortex.mcp.server, or in the client config use
"command": "uv", "args": ["run", "--with", "fastmcp", "python", "-m", "cortex.mcp.server"].
Note the --from cortex-protocol in the config above — a bare uvx cortex-mcp resolves to an
unrelated package.
Config (env): GEMINI_API_KEY / GOOGLE_API_KEY (required); optional CORTEX_DB_PATH,
CORTEX_USER_ID, CORTEX_EMBED_MODEL, CORTEX_EMBED_DIM, CORTEX_TOP_K (default recall depth 5).
Opt-in memory layers (off by default). CORTEX_GRAPH=1 builds the entity graph and enables
recall_about; CORTEX_EPISODIC=1 structures event time / actor / location and enables
recall_timeline; CORTEX_EXTRACT_MODEL (default gemini-2.5-flash-lite) is the model that does
that extraction. Enabling either adds one cheap flash-lite call per memorize (write-time only,
on your own key — when both are on they share a single extraction call). recall stays
byte-identical, so the published recall cost is unchanged. See
examples/ and
.env.example.
Claude Desktop one-click: build the .mcpb bundle and drag it onto Desktop — it prompts for your
Gemini key and runs the same six tools. See
packaging/mcpb/.
Why Cortex
- User-owned, not company-owned. You decide which agents see your memory — versus incumbents where the business owns it. One memory, every agent.
- The cost is published. ~$0.0396/question on LongMemEval_S, ~$0.0034 on LoCoMo† — measured token counts at Google's confirmed list prices. No other memory system publishes a $/question at all, so there is nothing to compare it against yet. It targets accuracy per dollar, not raw accuracy at any cost.
- Run anywhere, no operator cost. Self-host is a single SQLite file — no Docker, no DB server. One config snippet wires it into any MCP client.
Results
📊 0.932 LongMemEval_S · 0.813 LoCoMo. Two public long-term-memory benchmarks, with the standing stated plainly: #3 on LongMemEval_S (behind Mastra 0.949 and Mem0 0.944) and #4 on LoCoMo (behind Mem0 0.925, Cognis ~0.925 and EMem 0.84). Those placings are worth less than they look: every row is its own system's number under its own reader, judge and question set. What is distinct here is the cost side — Cortex is the only memory system publishing $/question, and the only one at 0.9+ on LongMemEval_S with a cost-efficient-tier reader. No competitor's $/question has been measured, by us or by them, so no cost comparison is claimed.
| Benchmark | Cortex | Raw rank | Reader (cost†) | Recall@k (session-level‡) |
|---|---|---|---|---|
| LongMemEval_S (500 q) | 0.932 | #3 raw | gemini-3.5-flash, top_k=50, preference-mode, answer-first · ~$0.0396/q |
0.998 |
| LoCoMo (1986 q) | 0.813 | #4 raw | gemini-2.5-flash, top_k=100, answer-first · ~$0.0034/q |
0.998 |
† $/q is computed from measured token counts (25,723.5 in / 113.5 out per question on
LongMemEval_S; 10,468.4 in / 92.9 out on LoCoMo) at Google's confirmed list prices for the
reader model — gemini-3.5-flash at $1.50/$9.00 per 1M input/output tokens, gemini-2.5-flash at
$0.30/$2.50 (see bench/cortex_bench/metrics.py).
‡ Read this recall number the narrow way. It is session-level: it scores a hit when the retrieved set contains the session holding the gold evidence. On LongMemEval that is the dataset's own gold granularity, so 0.998 is measured against exactly what the benchmark defines. On LoCoMo the dataset ships turn-level evidence (
"D1:3"= session 1, turn 3), so session-level recall answers the easier question there. Measured turn-level full-evidence coverage on LoCoMo is 0.915 at k=100 and 0.639 at k=8 — read 0.998 as "we surfaced the right conversation", not "we surfaced the right memory".The stricter metric now ships:
coverage_at_kinmetrics.pyscores retrieval against individual gold turns, joined on LoCoMo's owndia_id. Four evidence fields in the released corpus pack several ids into one string ("D22:1 D22:2 D9:10 D9:11"); matching the raw field keeps only the first and silently shrinks the gold set, so the parser tokenizes first — worth 13 recovered gold turns across the corpus.
The reader frontier — buy accuracy with dollars, not with a different memory system
The same retrieval, the same 500 questions — this is the trade the memory layer exposes, priced. Two things changed between our cheapest arm and our headline, and they are listed separately on purpose, because summing them is the exact mistake this table exists to prevent:
| Config (LongMemEval_S, n=500) | Accuracy | $/question | Cost per correct answer |
|---|---|---|---|
gemini-2.5-flash, 2k output budget |
0.848 | $0.0079 | $0.0093 |
gemini-3.5-flash, 2k output budget |
0.894 | $0.0396 | $0.0443 |
gemini-3.5-flash, 8k + --answer-first |
0.932 | $0.0396 | $0.0425 |
The reader swap is worth +4.6 points and costs ~5×. Retrieval is byte-identical across those two arms — same index, same top-k, same fused ranking, same prompt — so that delta is reader capability. It also makes cost-per-correct-answer 4.8× worse.
The remaining +3.8 points are free, and came from something we did not expect to matter: emitting the answer before its notes and raising the reader's output-token budget from 2,048 to 8,192, which removed a mid-answer truncation on the aggregation-heavy question types. Same reader, same retrieval, same cost — and it improves cost-per-correct-answer.
We do not publish a combined "+8.4 from the reader" number, because less than half of it is the
reader. A leaderboard that reports only accuracy ranks these two changes identically, and reports
neither the decode budget nor the answer ordering — which is the whole argument for publishing the
reader, the judge, the depth and the cost next to every score. Pick your point on this curve with
CORTEX_READER_MODEL.
How Cortex compares (LongMemEval_S)
| System | LongMemEval_S | Reader | ~$/q | Judge |
|---|---|---|---|---|
| Cortex (this repo) | 0.932 | gemini-3.5-flash (cost-efficient tier) |
~$0.0396 | gemini-flash |
| Mastra | 0.949 | gpt-5-mini (premium) |
— | GPT-4o |
| Zep / Graphiti | 0.712 | gpt-4o (premium) |
— | GPT-4o |
| Mem0 | 0.944¹ | gpt-5 (premium) |
— | gpt-5 (self) |
Numbers from the verified leaderboard research.
Not apples-to-apples: competitor scores are self-reported under their own judges; Cortex is
graded by a gemini-3.5-flash judge (likely more lenient than the canonical gpt-4o-2024-08-06), and
~$/q is only published where Cortex measures it — no competitor $/q has been measured. ¹Mem0's 0.944 is
its own published figure (mem0.ai/research), measured with a gpt-5 reader and a gpt-5 judge at
top-200 — a stronger reader than Cortex's and a same-model judge on both sides. Not comparable to
Cortex's 0.932; see the LoCoMo note below. The ~$0.0396 figure is Cortex's own measured token counts priced at Google's confirmed
gemini-3.5-flash list prices.
Judge disclosure (load-bearing). All Cortex numbers above are graded by an LLM judge =
gemini-3.5-flash. The canonical LongMemEval judge isgpt-4o-2024-08-06; a Gemini judge is likely more lenient, so a GPT-4o re-grade (pending an OpenAI key) may lower these. The headline run also used the same model family as both reader and judge, so a self-preference bias cannot be excluded and a cross-family re-grade is planned. As one cross-model sanity check, an independent Claude panel re-graded all 282 LoCoMo multi-hop cases and closely tracked the harness (panel 0.528 vs harness 0.589). The published $/question is measured from token counts at Google's confirmed list prices and does not depend on the judge.
LongMemEval_S 0.932 — per question type: single-session-user 0.957, single-session-assistant 0.982, single-session-preference 0.900, knowledge-update 0.949, temporal-reasoning 0.925, multi-session 0.902, abstention 0.867 (mean ~25.7k input tokens/q). Under our judge, 0.932 sits above ByteRover (0.928, claimed) and Hindsight (0.914) and below only the premium-reader leader Mastra (0.949, gpt-5-mini) — while clearing Emergence (0.860), Supermemory (0.852), and Zep (0.712), all of which use pricier readers. (Competitor rows use their own judges — the leaderboard is not apples-to-apples; canonical judge is GPT-4o.)
Per question type — Cortex vs the field
One overall number hides where a memory system wins or loses. Split by LongMemEval_S question type, Cortex — the only cost-efficient-tier-reader system in the field — stays in the top tier of the premium-reader systems, and leads outright on single-session-assistant and multi-session recall:

| Question type | Cortex flash |
Mastra premium |
EmergenceMem premium |
Supermemory premium |
Zep premium |
|---|---|---|---|---|---|
| Knowledge update | 94.9 | 96.2 | 83.3 | 89.7 | 83.3 |
| Single-session assistant | 98.2 | 94.6 | 100.0 | 98.2 | 80.4 |
| Single-session user | 95.7 | 95.7 | 98.6 | 98.6 | 92.9 |
| Temporal reasoning | 92.5 | 95.5 | 85.7 | 82.0 | 62.4 |
| Multi-session | 90.2 | 87.2 | 81.2 | 76.7 | 57.9 |
| Single-session preference | 90.0 | 100.0 | 60.0 | 70.0 | 56.7 |
| Overall | 93.2 | 94.9 | 86.0 | 85.2 | 71.2 |
Cortex's row is our own run (gemini-3.5-flash reader + judge). Competitor rows are each
system's own published LongMemEval_S results under its own premium reader and judge — the field's
reported standing, not a single apples-to-apples harness (the parody Supermemory "8/12-variant
ensemble" columns are excluded as satire; the real Initial column is used). Cortex's abstention
category (0.867) is omitted — competitors don't report it. Higher is better.
LoCoMo 0.813 — per category: single-hop 0.864, multi-hop 0.695, temporal 0.857, open-domain 0.458, adversarial/abstention 0.836. Doubling retrieval depth (k=50→100) is what recovers multi-hop (+10.6pt) — the LoCoMo frontier is retrieval depth, not reader capability.
Reading LoCoMo numbers across systems (please read before comparing). Mem0 published 0.669 in arXiv 2504.19413 (Apr 2025) and reports 0.925 today on mem0.ai/research. Both are theirs and both are real; between them they shipped a v3 algorithm, temporal reasoning, memory decay and entity linking, and changed the measurement — reader
gpt-4o-mini→gpt-5, judge unnamed →gpt-5self-judged with a partial-credit rubric, retrieval to top-200, and ten runs to one. Their harness also scores LoCoMo categories 1–4, excluding the 446 adversarial questions that Cortex's 0.813 includes (Cortex scores 0.836 on that category). Their own repo puts it well: "Benchmark scores are not absolute numbers. They depend heavily on… LLM capability."So 0.813 and 0.925 are not on the same scale, and no one — us included — can say how much of any gap is memory rather than reader, judge, prompt or depth. That is the whole reason this README publishes its reader, its judge and its cost next to every score. Earlier Zep (0.585–0.62) and EMem (0.78–0.84) figures on this page carry the same caveat: they are each system's own published number under its own harness.
Reproduce
# LongMemEval_S — 0.932 headline (full 500):
python -m cortex_bench.run --system cortex-v0 --variant s --limit 500 \
--reader-model gemini-3.5-flash --top-k 50 --preference-mode --answer-first \
--max-output-tokens 8192 --judge gemini --judge-votes 3
# LongMemEval_S — 0.894: the SAME config as the headline, one variable changed (2k output
# budget, notes-before-answer). The 0.932 - 0.894 gap is that variable, not the reader:
python -m cortex_bench.run --system cortex-v0 --variant s --limit 500 \
--reader-model gemini-3.5-flash --top-k 50 --preference-mode \
--max-output-tokens 2048 --judge gemini --judge-votes 3
# LongMemEval_S — 0.848: the cheap arm. Identical to the 0.894 run except the reader, so
# 0.894 - 0.848 is the reader delta. NOTE the 2k budget: this is the config that was measured.
python -m cortex_bench.run --system cortex-v0 --variant s --limit 500 \
--reader-model gemini-2.5-flash --top-k 50 --preference-mode \
--max-output-tokens 2048 --judge gemini --judge-votes 3
# Never measured, and the number we would most like: gemini-2.5-flash WITH --answer-first and an
# 8k budget. Until someone runs it, no "+8.4 from the reader" claim is available from this repo.
# LoCoMo — 0.813 (put locomo10.json in bench/data/ first):
python -m cortex_bench.run --system cortex-v0 --locomo --reader-model gemini-2.5-flash \
--top-k 100 --answer-first --max-output-tokens 8192 --judge gemini
Full methodology + per-type tables:
bench/results/PHASE3_authoritative.md
(LongMemEval) and
bench/results/LOCOMO_results.md
(LoCoMo); verified competitor leaderboard:
bench/results/leaderboard_research.md.
Features
| Capability | What it does | Status |
|---|---|---|
| Hybrid retrieval | Dense (Gemini embeddings) + Okapi BM25, fused with Reciprocal Rank Fusion (k=60, unweighted); each retriever is asked for a 4 × top_k candidate pool so fusion can promote what both agree on. Deep top-k drives session-level recall@k ≈ 0.998. |
On (all paths) |
| Chain-of-Note reader | The reader takes structured notes over the retrieved memories before answering, with calibrated abstention — it declines when no memory supports an answer instead of hallucinating. | On (benchmark path) |
Episodic memory + recall_timeline |
One cheap gemini-2.5-flash-lite call per memorize structures event_time / actor / location, powering the recall_timeline tool. Write-time cost only — recall is byte-identical, so the published recall cost is unchanged. |
Opt-in (CORTEX_EPISODIC=1) |
Entity graph + recall_about |
At memorize time, entities and relationships are folded into the same cheap extraction call that does episodic. Builds an ego knowledge graph rooted at a synthetic self entity — typed nodes (person / place / org / project / thing) joined by labeled, directed relationships, each memory attached to the entity it's about — powering the recall_about tool. Write-time cost only — recall stays byte-identical. |
Opt-in (CORTEX_GRAPH=1) |
| Anti-saturation | Write-time dedup (embedding-only, no LLM) bounds store growth; contradiction soft-update (one cheap arbiter call) writes a supersessions row so recall returns only the latest value. Implemented and unit-tested; not yet measured at scale — no saturation benchmark is published in this repo. |
Engine-level, opt-in |
See docs/decades-scale.md
for the decades-scale retrieval analysis (self-host SQLite recall is O(n): measured ~95 ms @ 1k
memories → ~7.7 s p50 @ 50k).
Architecture
Two paths, and the second one never calls an LLM.
flowchart TB
subgraph W["① SAVING — you tell an agent something worth keeping"]
direction LR
W1["memorize()"] --> W2["turn it into<br/>a searchable form"] --> W3["write it down"]
end
DB[("YOUR MEMORY<br/><i>one file, and it's yours</i>")]
subgraph R["② RECALLING — a different chat, days later — no AI model runs here"]
direction LR
R1["recall()"] --> R2["search it two ways —<br/>by meaning,<br/>and by exact words"] --> R3["hand back the<br/>memories that matter"]
end
A["YOUR AI reads them<br/>and answers you"]
W3 --> DB --> R2
R3 --> A
classDef step fill:#1b2a3d,stroke:#4b6a8a,color:#e6eefc
class W1,W2,W3,R1,R2,R3 step
style W fill:#0d1b2a,stroke:#3b82f6,color:#93c5fd
style R fill:#0c1f17,stroke:#22c55e,color:#86efac
style DB fill:#241f38,stroke:#a78bfa,color:#ddd6fe
style A fill:#141414,stroke:#9ca3af,color:#f3f4f6
The invariant: every enrichment layer runs at write time. Turning them on changes what is
stored, never what recall does — so the published per-recall cost holds no matter how many
layers you enable. recall is one embedding call plus local search, and returns raw memories.
No LLM ever runs on the read path.
Inside hybrid_retrieve
Dense and lexical retrieval fail in different ways: embeddings miss rare exact tokens (names, IDs, dates), BM25 misses paraphrase. Reciprocal Rank Fusion combines them without score normalization — each list votes by rank, so a memory both retrievers like beats one only a single retriever likes (Cormack et al., 2009).
flowchart LR
classDef q fill:#111,stroke:#666,color:#eee
classDef ret fill:#1a3d2e,stroke:#22c55e,color:#e6f7ee
classDef fuse fill:#2d2a3e,stroke:#a78bfa,color:#f0ecff
classDef out fill:#1e3a5f,stroke:#3b82f6,color:#e8f0fe
Q["query"]:::q
E["embed once"]:::q
D["<b>dense</b><br/>cosine over vectors<br/><i>catches paraphrase</i>"]:::ret
L["<b>lexical</b><br/>Okapi BM25<br/><i>catches exact tokens</i>"]:::ret
F{"<b>RRF</b><br/>k=60<br/>rank-vote fusion"}:::fuse
O["top-k memories"]:::out
Q --> E --> D
Q --> L
D -->|"4 × top_k pool"| F
L -->|"4 × top_k pool"| F
F --> O
Teach your agent to use Cortex well
Connecting the server gives your agent the tools; the Cortex agent skill gives it the craft — which tool answers which kind of question, how to phrase memories so the entity graph and timeline actually build, and when to recall instead of re-asking you. One file, works in any client (Claude Code skill, Cursor rules, or pasted instructions):
mkdir -p ~/.claude/skills/using-cortex-memory
curl -fsSL https://raw.githubusercontent.com/fernsdavid25/cortex-protocol/main/skills/using-cortex-memory/SKILL.md \
-o ~/.claude/skills/using-cortex-memory/SKILL.md
Canonical file: skills/using-cortex-memory/SKILL.md
· rendered: docs → Agent skill.
Security & privacy
- BYOK, no phone-home. Your Gemini key is read from the environment and used only to call Google's API. The local server has no backend and sends nothing anywhere else.
- Your memory text is embedded by Google. Each
memorize/recallsends the content/query to Google's embedding API under your own key — pick a key/project whose data-handling terms you're comfortable with. - Local storage is a plain file. Memories live unencrypted in
~/.cortex/memory.db(CORTEX_DB_PATH). Don't store secrets; protect the file like any local data, and setCORTEX_DB_PATHonly from trusted config (not from untrusted/agent input).
Cortex Protocol MCP questions
What AI clients can I use with Cortex Protocol?
It works with Claude Code, Cursor, Claude Desktop, and VS Code.
Is my data private?
Yes, it is a local stdio server that uses a local SQLite file and nothing phones home.