Skip to main content

Persistent memory for AI assistants via MCP

Project description

Rekall MCP

Give Claude a memory with associative recall. Three steps, five minutes.

Rekall MCP is a persistent memory system with a knowledge graph layer. It stores memories as YAML + vector embeddings, connects them with typed relationships, and retrieves context using graph-enhanced semantic search.


Local-First Agent Nervous System

Rekall gives local agents durable, inspectable, cross-session and cross-project memory for software work. Harness memory stores assistant preferences; Rekall stores what the work has taught the agent: decisions, root causes, procedures, danger zones, and project familiarity with provenance.


Install

Try it — no Docker, one command

claude mcp add rekall -- uvx rekall-mcp

That's the trial tier: stdio transport, embedded vector store at ~/.rekall/qdrant, memories as YAML at ~/.claude/memory. First run downloads the ~90 MB embedding model (progress on stderr). No hooks/auto-capture, single session at a time — upgrade below when it earns a daily slot.

Daily driver — all-in-one Docker

docker run -d -v rekall-data:/data -p 127.0.0.1:8000:8000 ghcr.io/jfr992/rekall-mcp
claude mcp add --transport http rekall http://localhost:8000

One container, embedding model baked in, data on a named volume. Verify with curl http://localhost:8000/health.

Full stack — compose (adds the cockpit UI)

git clone https://github.com/jfr992/rekall-mcp.git
cd rekall-mcp
docker compose up -d    # Qdrant (:6333) + MCP backend (:8000) + cockpit (:3333)
claude mcp add --transport http rekall http://localhost:8000

Data lives on named volumes (rekall-memory, rekall-qdrant). Existing installs with data at ~/.claude/ keep their bind mounts via docker-compose.bind-mounts.example.yaml — see docs/MIGRATION.md. (scripts/start-rekall.sh remains for running the backend/UI on the host during development.)

Need Docker? Get it free at docker.com/get-started

Which tier?

Tier Install Transport Hooks / auto-capture Embedder Storage
Trial uvx rekall-mcp stdio no fastembed embedded ~/.rekall/qdrant + YAML ~/.claude/memory
Daily (pip) uv tool install rekall-mcp && rekall serve HTTP loopback yes fastembed same as trial
Daily (docker) docker run -v rekall-data:/data -p 127.0.0.1:8000:8000 ghcr.io/jfr992/rekall-mcp HTTP loopback yes fastembed (baked into the image) named volume
Full stack docker compose up -d HTTP + cockpit yes per compose external Qdrant container

Trial-tier honesty: no hooks means nothing is captured automatically — you save and recall explicitly. Filtering is linear at embedded scale, and only one process can hold the embedded store (run rekall serve so sessions share one daemon). Shared-env pip install is unsupported; use isolated installs (uvx / uv tool install).

Done. Claude now remembers things between sessions.


How to Use

Just talk normally. Claude automatically remembers:

  • Decisions - "Let's use PostgreSQL"
  • Preferences - "I prefer TypeScript"
  • Lessons - "That bug was caused by..."

To check memories: "What do you remember about this project?"

Python API

from memory import MemoryManager

memory = MemoryManager()

# Save (auto-links to related memories in the knowledge graph)
memory.save("Chose PostgreSQL for JSON support", type="decision", project="my-app")
memory.save("User prefers concise responses", type="preference")

# Recall (graph-enhanced: vector search + relationship traversal)
results = memory.recall("what database did we choose?")
for r in results:
    print(f"[{r['score']:.2f}] {r['content']}")

# Project context (flat or hierarchical)
context = memory.get_project_context("my-app")

CLI

# Save
python -m memory.cli save "Decided to use PostgreSQL" --type decision --project my-app

# Recall
python -m memory.cli recall "database choices"
python -m memory.cli recall "recent work" --limit 3 --days 7

# Stats
python -m memory.cli stats

Operations

Verb What it does
rekall doctor [--project P] [--json] Health check — exit 0 healthy, 1 degraded, 3 unreachable
rekall backup [--out DIR] Tarball memory + Qdrant; streams artifact paths
rekall migrate [--dry-run] [--no-backup] Migrate to hybrid schema; backs up first by default
rekall startup-preview [--project P] Preview what the SessionStart hook would inject (approximates hook output; exit 3 if backend unreachable)
rekall install-claude [--skills-only] [--hooks-only] [--skip-backend] Install Claude Code bundle from a repo checkout

Software evals: uv run --extra dev pytest tests/test_software_evals.py Utility report: uv run python scripts/utility_report.py


Knowledge Graph

Every memory is a node. Relationships are typed edges created automatically on save:

Relation Meaning Example
related_to Semantically similar Two PostgreSQL facts
led_to Temporal causation Decision led to a learning
depends_on Structural dependency Decision depends on requirement
supersedes Newer replaces older Updated decision overwrites old
contradicts Opposing content Conflicting memories

Graph-Enhanced Recall

Recall uses a 3-phase pipeline instead of flat cosine search:

1. SEED    - Vector search (top K x 2 candidates)
2. EXPAND  - Traverse 1-hop graph neighbors of seed results
3. RANK    - Composite: vector(40%) + importance(20%) + proximity(15%) + tier(15%) + recency(10%)

This finds memories that are structurally related, not just textually similar. Falls back to pure vector search when the graph is empty.

Freshness — conflict detection at read time

When the same memory type appears in the result set, Rekall detects conflicting entries via graph edges and stored-vector cosine (θ ≥ 0.9). The recall_formatted output renders entries newest-first; outdated entries are collapsed to a stub line so the agent acts on current information only. No data is deleted — the detection is ephemeral and happens entirely at read time.

Cockpit UI

Browse the knowledge graph at http://localhost:3333/brain — the Next.js cockpit ships as a container, started by docker compose up -d alongside Qdrant and the backend. (For UI development, cd ui && npm run dev -- -p 3333 still works.) Surfaces:

  • /brain — force-directed graph view, nodes are memories, edges show typed relationships
  • /kb — typed columns (decisions, requirements, preferences, learnings), plus an Export OKF tab that distills memory into a portable Open Knowledge Format bundle
  • /continuity — resume packets and handoff summaries
  • /hygiene — pressure metrics, prune flow, lifecycle backfill

Claude Code bundle (optional)

The three-container stack above gives Claude memory via MCP tools. The claude/ bundle adds the Claude Code integration layer — auto-save hooks, slash commands, and a recommended memory policy. All of it is opt-in; nothing auto-loads.

One-shot install

bash claude/setup/install.sh

Idempotent, backs up your existing ~/.claude/settings.json first. It:

  • copies the two hooks to ~/.claude/hooks/
  • merges UserPromptSubmit + Stop entries into ~/.claude/settings.json (deduped)
  • copies all nine slash commands to ~/.claude/skills/
  • verifies backend health

Restart your Claude Code session afterward so the slash commands load. Re-run anytime from inside Claude Code via /rekall-setup. Full manual steps and flags (--skills-only, --hooks-only, --skip-backend) are in claude/INSTALL.md.

Hooks (the auto-save layer)

  • rekall-restore.sh (UserPromptSubmit) — once-per-session status line (Rekall ready — N memories…). No context injection.
  • rekall-observe.sh (Stop) — a Haiku judge that auto-saves durable observations, gated by cheap signal detection (durability keywords, new git commits, or session length) so it doesn't fire on every turn. Kill switch: REKALL_AUTOSAVE=0.

Slash commands (manual, not auto-triggering)

Slash command What it does
/memory-observe <note> Manual save with auto-classification
/memory-recall <query> Graph-enhanced semantic search
/memory-restore Manual context restore (importance-ranked)
/memory-stats Health check + graph metrics
/memory-rebuild Rebuild the knowledge graph
/memory-consolidate Detect duplicate and contradictory memories
/memory-skills Show extracted skills from memory clusters
/rekall-publish Export memory to an OKF knowledge bundle
/rekall-setup Re-run the bundle installer from inside Claude Code

Recommended CLAUDE.md policy

For the agent to use memory well — recall at session start, save conservatively — copy the policy block from docs/CLAUDE_MEMORY_SETTINGS.md into your ~/.claude/CLAUDE.md (global) or a project CLAUDE.md. It tells Claude when to call get_cached_context(), what's worth an observe(), and how to tune recall.


Your Data

Everything stays on your computer in editable files:

~/.claude/memory/
  <project>/
    2026-02-02.yaml     <- Human-editable memories (nested per project)
  _graph.json           <- Knowledge graph (auto-managed)

Nothing is sent anywhere. Backup = copy the folder.

Credentials are automatically sanitized before storage:

Input:  "Set api_key to sk-abc123def456"
Stored: "Set api_key to [REDACTED]"

Securing a non-localhost deployment

The server binds 127.0.0.1 by default and is unauthenticated — the trust model is localhost. Docker sets HOST=0.0.0.0 inside the container (required for port-mapping); compose maps ports to localhost only. If you deliberately expose the server on a network (HOST=0.0.0.0 on bare metal), enable bearer auth:

export REKALL_API_TOKEN=$(openssl rand -hex 32)   # on the server

When set, every request except /health requires the token. Point clients at it:

# Claude Code
claude mcp add --transport http rekall http://localhost:8000 \
  --header "Authorization: Bearer $REKALL_API_TOKEN"
# Cockpit: ui/.env.local
echo "NEXT_PUBLIC_REKALL_API_TOKEN=$REKALL_API_TOKEN" >> ui/.env.local

Benchmark

Tested on LongMemEval (500 questions, 6 question types). Reproducible — runner in benchmarks/.

End-to-end effectiveness numbers — accuracy, token cost, and the workloads Rekall loses on — live in BENCHMARKS.md, with committed raw evidence.

These are R@5 retrieval-recall numbers — "was the correct memory in the top 5 retrieved" — with no LLM at any stage. They are not end-to-end QA-accuracy and are not comparable to the QA-accuracy figures other systems (mem0, Zep) publish on LongMemEval. MemPalace's raw retrieval baseline (96.6% R@5) uses the same metric and is the closest comparison point.

Measured 2026-07-02 on v1.7.0 (main, 5-weight recall ranking). All three benchmark modes run from main; the product's default recall path is dense — BM25 in the product search path still lives on feat/hybrid-search-bm25.

Mode R@5 R@10
Dense (semantic only) 91.7% 96.2%
Hybrid (BM25 + dense) 93.6% 97.4%
Hybrid + graph 93.6% 97.4%

Hybrid search catches entity-specific queries (ticket IDs, error codes) that pure semantic search misses. No LLM required, no API calls, runs entirely local. R@5 measures retrieval, not answer quality — a system can retrieve well and still answer poorly.

# Reproduce (runs against the isolated test Qdrant on :6334 — production data untouched)
bash benchmarks/download_data.sh
docker compose --profile test up -d qdrant-test
PYTHONPATH=src:. uv run python -m benchmarks.longmemeval_runner \
    benchmarks/data/longmemeval_s_cleaned.json --mode all

How Search Works

Memories are converted to embeddings (vectors that capture meaning) for semantic search:

"Use PostgreSQL" -> [0.12, 0.45, 0.78, ...]  <- Numbers that represent meaning

When you ask "what database?", Claude searches by meaning, not keywords. The knowledge graph then expands results by following relationship edges to find structurally related memories.

Embedding options (see docs/SETUP.md):

Provider Runs on Cost Quality
sentence-transformers Your computer Free Good (default)
ollama Your computer Free Better
gemini Google Cloud Free tier Best

Troubleshooting

"Connection refused" - Make sure Docker is running: docker compose ps

"Cockpit UI not loading" - Confirm all three containers are up:

docker compose ps            # qdrant, mcp, ui should all be running
docker compose up -d ui      # (re)start just the cockpit

"Claude forgets" - Install the Claude Code bundle (claude/ directory — skills + hooks) or add to ~/.claude/CLAUDE.md:

At session start, call get_cached_context() to restore memory.

Memories not found - Rebuild the knowledge graph:

curl -X POST http://localhost:8000/api/memory/graph/rebuild

Graph shows 0 edges - Run rebuild after first install or upgrade:

curl -X POST http://localhost:8000/api/memory/graph/rebuild

Restart everything: docker compose down && docker compose up -d


How It Works

The Flow

You say something important
        |
Claude saves it -> YAML file + Qdrant vector + Knowledge Graph node
        |
Auto-linker finds related memories -> Creates typed edges
        |
Later: Claude recalls by meaning + follows graph relationships

Example

You: "Let's use PostgreSQL for JSON support"
AI:  saves to memory, creates embedding, auto-links to related memories

[3 days later]

You: "What database did we choose?"
AI:  vector search finds the memory
     graph expansion surfaces the related requirement and learnings
     "We chose PostgreSQL for its JSON support"

Memory Types

Type Example AI Behavior Importance
requirement "Must use Python 3.11+" Must follow 1.0
decision "Chose PostgreSQL" Reference, can revisit 0.85
preference "Prefers Terraform" Suggest, offer alternatives 0.75
learning "JWT bug fix" Apply to similar cases 0.65
fact "Project uses AWS" Background context 0.55
note "General observation" Low-priority context 0.35
session Session summary Continuity context 0.25

summary is also a valid type — generated by memory compaction (POST /api/memory/compact), not saved by hand.

MCP Tools

Tool Purpose
observe(summary) Auto-classify and save (accepts caller cwd for project scope)
recall_memories(query, task_hint?) Graph-enhanced semantic search; task_hint (2+ words) surfaces memories matching your current task first
recall_across_projects(query, current_project) Cross-project transfer recall across current, related, and global memory
close_loop(memory_id, note?) Close an open loop: appends a RESOLVED stamp, drops it from the Open Loops capsule bucket
save_memory(content, type) Manual save with explicit type
memory_detail(memory_id) Single memory + neighbors + scope
memory_kb(project) Typed slices (decisions / requirements / preferences / learnings)
memory_pressure(project) Pressure metrics + flagged candidates
memory_pressure_snapshot() Detailed pressure snapshot
prune_plan(project, limit) Build prune plan (apply via REST only)
backfill_lifecycle(project, dry_run) Tier metadata backfill on existing memories
resume_packet(project) Continuity resume
handoff_summary(project) Continuity summary
agent_startup(project) Unified startup payload
project_capsule(project) Thin project familiarity capsule
publish_team_memory(project) Team-safe bundle of distilled project capsule and playbooks
reflex_recall(text, project) Cue-triggered recall before risky commands or edits
memory_lifecycle() Behavioral classifier output
memory_doctor(project) Trust report for YAML/Qdrant/vector/graph/provenance health
get_cached_context(project) Flat context (prompt-cache optimized)
get_hierarchical_context(project) Topic-grouped context tree
skill_context() Extracted skills from memory clusters
memory_stats() Health + graph metrics
consolidate_memories() Detect duplicates and conflicts
proactive_context_summary() Top signals ranked by importance x recency
rebuild_knowledge_graph() Rebuild graph from all existing memories
publish_memory(project, format) Export memory to an OKF knowledge bundle
list_available_tools() List registered tool providers and status
get_telemetry_summary() Tool-call telemetry summary

Team Memory Publishing

Team memory publishing emits distilled project capsules and playbook summaries. It strips known raw event-log, session transcript, private prompt, and hook payload fields from the generated bundle, but it is not a content redaction pass: review capsule/playbook text before sharing. Keep local memory as the default.

REST API

Endpoint Method Purpose
/health GET Health check
/api/memory/save POST Save a memory
/api/memory/recall POST Graph-enhanced search (optional task_hint: context-matched results first)
/api/memory/recall/cross-project POST Cross-project transfer recall
/api/memory/reflex POST Cue-triggered recall packet for risky commands or edits
/api/memory/observe POST Auto-classify and save (accepts cwd for scope)
/api/memory/stats GET Statistics + graph metrics
/api/memory/doctor GET Trust report for YAML/Qdrant/vector/graph/provenance health
/api/memory/projects GET List of projects + memory counts
/api/memory/context GET Flat project context
/api/memory/context/hierarchy GET Topic-grouped (?days=N for date filter)
/api/memory/context/smart GET Token-capped smart context (?limit=&max_tokens=)
/api/memory/context/proactive GET Top signals + conflict detection
/api/memory/context/skills GET Inferred skill context from memory clusters
/api/memory/context/startup GET Unified agent startup payload
/api/memory/capsule GET Thin project familiarity capsule
/api/memory/detail/{id} GET Full memory + v2 blocks: relationships (both in/out directions), provenance, lifecycle, storage, warnings; neighbors alias for backward compat
/api/memory/kb GET Typed slices
/api/memory/pressure GET Pressure metrics + flagged candidates
/api/memory/resume GET Resume packet for continuity
/api/memory/prune/plan POST Build prune plan (plan-id, 15-min TTL, 200-deletion cap)
/api/memory/prune/apply POST Apply plan with typed-id confirmation (REST-only)
/api/memory/prune/superseded POST Gated auto-prune of superseded memories (confirm-date token, ≤10/fire, ≤20/day, backup-first; REST-only)
/api/memory/lifecycle/backfill POST Backfill tier metadata (dry-run + execute)
/api/memory/{id} DELETE Delete a single memory
/api/memory/cleanup POST Batch cleanup (prune superseded, age-based)
/api/memory/graph GET Graph visualization data
/api/memory/graph/rebuild POST Rebuild knowledge graph
/api/memory/consolidate GET Detect superseded/conflicting pairs
/api/memory/recall/quick GET Fast high-threshold recall for per-prompt injection
/api/memory/compact POST LLM-summarize old memories (dry-run by default)
/api/memory/publish GET, POST Export memory to an OKF v0.1 bundle (mode=preview|tar|dir)
/api/memory/publish/synthesize POST Start (or report) a background LLM synthesis job for a project scope
/api/memory/publish/status GET Poll a synthesis job's progress
/api/memory/events POST Append a client-side session-summary event to the event log

Cost Savings

Token Savings

  • ~80% reduction in repetitive context

Prompt Cache Savings

get_cached_context() returns identical content per turn -> 90% discount after turn 1

At high usage: ~$54/month savings per 10k cached tokens


For Developers

Local Development

pip install -e ".[dev]"
docker compose up -d qdrant
cd src && MCP_TRANSPORT=streamable-http python -m server

Tests

Tests run in an isolated environment and never affect your production data.

# Run all tests (fast, local)
uv run --extra dev pytest -v

# Run all tests (isolated Docker)
docker compose --profile test run --rm test

# Run specific test file
docker compose --profile test run --rm test pytest tests/test_memory.py -v

# Cleanup
docker compose --profile test down

What happens:

  • qdrant-test starts on port 6334 with ephemeral tmpfs storage
  • Tests use /tmp/test_memory for YAML files (inside container)
  • Production data at ~/.claude/memory/ and ~/.claude/qdrant/ stays untouched
  • Everything auto-deletes when tests finish

Project Structure

src/
├── server.py               # MCP server + REST API endpoints
├── core/                   # Embedder, VectorStore, Telemetry, utils
│   └── utils.py            # stable_hash_id() for string->int64 hashing
├── memory/
│   ├── manager.py          # MemoryManager (save, recall, get_stats)
│   ├── knowledge_graph.py  # KnowledgeGraph (networkx DiGraph, persistence)
│   ├── linker.py           # Auto-linking: classify relations on save
│   ├── graph.py            # Visualization graph builder
│   ├── cache_context.py    # Stable cacheable context + hierarchical variant
│   ├── topics.py           # Topic auto-classification (agglomerative clustering)
│   └── skills.py           # Skill extraction from memory clusters
├── crawler/                # Documentation crawler (Scrapy)
├── indexer/                # Document chunker + Qdrant indexer
└── tools/                  # MCP tool definitions

Documentation

Doc Purpose
docs/ARCHITECTURE.md Technical design, knowledge graph internals
docs/SETUP.md Setup, embedding providers, migration
docs/TUNING.md Customize what Claude remembers
claude/INSTALL.md Claude Code bundle: skills and hooks install
docs/CLAUDE_MEMORY_SETTINGS.md Claude-specific policy and tuning knobs
docs/MIGRATION.md Version upgrade notes

Requirements

  • Docker (or Python 3.11+)
  • uv (for the uv run commands used throughout)
  • ~500MB disk (embedding model downloads on first use)
  • macOS, Linux, or Windows (WSL)

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rekall_mcp-1.11.0.tar.gz (682.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rekall_mcp-1.11.0-py3-none-any.whl (169.8 kB view details)

Uploaded Python 3

File details

Details for the file rekall_mcp-1.11.0.tar.gz.

File metadata

  • Download URL: rekall_mcp-1.11.0.tar.gz
  • Upload date:
  • Size: 682.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rekall_mcp-1.11.0.tar.gz
Algorithm Hash digest
SHA256 b2535d7d1cdbf68467adaa5b4c0d6dee69d9911401d9a53bd0eb7dba4153a101
MD5 88ad77b360f1ca2d80671d9cb8a0be35
BLAKE2b-256 1e1e408585048774f78baee5a2c877380c7781121ea9788af473491515bfe181

See more details on using hashes here.

Provenance

The following attestation bundles were made for rekall_mcp-1.11.0.tar.gz:

Publisher: publish.yml on jfr992/rekall-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rekall_mcp-1.11.0-py3-none-any.whl.

File metadata

  • Download URL: rekall_mcp-1.11.0-py3-none-any.whl
  • Upload date:
  • Size: 169.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rekall_mcp-1.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0494bac4bd172d3888fd222e54621bcb984993892599091aa08237127810d917
MD5 452c648523bcd166430e6fc157492217
BLAKE2b-256 40e6b08bc595be10a7b1169736e3e730625a002006498db4bbbb51d7db949029

See more details on using hashes here.

Provenance

The following attestation bundles were made for rekall_mcp-1.11.0-py3-none-any.whl:

Publisher: publish.yml on jfr992/rekall-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page