Skip to main content

Long-term memory MCP server for LLMs — hybrid search in a single SQLite file

Project description

rekal

Long-term memory for LLMs, as an MCP server.

Every conversation starts from scratch — your LLM forgets what you told it yesterday. rekal is a small MCP server that stores memories in a single SQLite file and retrieves them with hybrid search. Install it, point your MCP client at it, and your LLM starts remembering things between sessions.

pip install rekal

Why I built this

I got tired of repeating myself. "I prefer Ruff." "We deploy with tags." "The auth service lives in services/auth." Every new conversation, same explanations.

Existing memory tools either do keyword search (which misses anything phrased differently) or vector search (which misses exact terms). I wanted both, plus a bias toward recent memories so stale stuff sinks naturally. And I wanted it in a single file I could back up by copying.

How search works

rekal runs three searches and blends the results:

score = 0.4 · BM25(keyword match)
      + 0.4 · cosine(semantic similarity)
      + 0.2 · exp(-t/half_life)

So a memory about "deploying the auth service to staging" shows up whether you search for "deploy auth" or ask about "shipping the login system to pre-prod". Recent memories rank higher, but old ones still surface if they're relevant.

Embeddings run locally with fastembed — no API keys, no network calls.

Quick start

Add to your MCP client config (Claude Desktop, Cursor, Claude Code, etc.):

{
  "mcpServers": {
    "rekal": {
      "command": "rekal"
    }
  }
}

rekal creates ~/.rekal/memory.db on first run. That file is your entire memory — portable, backupable, yours.

Requires Python 3.14+.

What it looks like in practice

Your LLM picks up on things worth remembering and stores them:

User: "I prefer Ruff over Black for formatting"
LLM:  → memory_store("User prefers Ruff over Black", type="preference")

Weeks later, in a completely different conversation:

User: "Set up linting for my new project"
LLM:  → memory_search("formatting linting preferences")
      ← "User prefers Ruff over Black" (score: 0.92)

When knowledge changes, it doesn't just pile up — old versions stay linked:

LLM: → memory_supersede(old_id="mem_abc", new_content="API moved from v2 to v3")

And when things contradict each other, you can ask:

LLM: → memory_conflicts(project="backend")
     ← "use PostgreSQL for everything" contradicts "migrate analytics to ClickHouse"

Tools

rekal exposes 16 tools over MCP.

Core

Tool Description
memory_store Store a memory with type, project, tags, and conversation scope
memory_search Hybrid search — BM25 + vector + recency in one query
memory_update Update content, tags, or type (re-embeds automatically)
memory_delete Delete a memory by ID

Smart write

Tool Description
memory_supersede Replace a memory while preserving the old one as history
memory_link Link memories: supersedes, contradicts, related_to
memory_build_context Relevant memories + conflicts + timeline for a query, in one call

Introspection

Tool Description
memory_similar Find memories similar to a given one
memory_topics Topic summary grouped by type
memory_timeline Chronological view with optional date range filters
memory_related All links to and from a memory
memory_health Database stats — counts by type, project, date range
memory_conflicts Find memories that contradict each other

Conversations

Tool Description
conversation_start Start a conversation, optionally linked to a previous one
conversation_tree Get the full conversation DAG
conversation_threads List recent conversations with memory counts
conversation_stale Find inactive conversations

Memory types

Memories are tagged with a type so search can be scoped:

Type For Example
fact Things that are true "The API rate limit is 1000 req/min"
preference How the user likes things "Prefers dataclasses over hand-written __init__"
procedure Steps to do something "Deploy: git tag vX.Y.Z && git push --tags"
context What's going on right now "Currently rewriting the payment service"
episode Things that happened "Debugged the OOM — root cause was unbounded cache"

Architecture

Everything lives in one SQLite file:

rekal
  │
  SQLite ──┬── FTS5 index ──── keyword relevance (BM25)
           ├── sqlite-vec ──── semantic similarity (384d vectors)
           ├── recency ─────── exponential decay (30-day half-life)
           └── memory links ── supersedes / contradicts / related_to

Conversations form a DAG — follow-ups, branches, merges — so you can navigate interaction history the way you'd navigate a Git log.

CLI

rekal serve    # Run as MCP server (default)
rekal health   # Database health report
rekal export   # Export all memories as JSON

License

MIT

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

rekal-1.0.0.tar.gz (76.9 kB view details)

Uploaded Source

Built Distribution

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

rekal-1.0.0-py3-none-any.whl (18.8 kB view details)

Uploaded Python 3

File details

Details for the file rekal-1.0.0.tar.gz.

File metadata

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

File hashes

Hashes for rekal-1.0.0.tar.gz
Algorithm Hash digest
SHA256 522b5d6049312477627b26bc89f0b20aca0f5b3afa8f7b9c156a15dd0391c225
MD5 9cf496ceb60aec7a6e6c9f9c7aef43ee
BLAKE2b-256 86868f435a9a80884c7f00a2d31f6a78152be2eb62ebc77dd3c5c3bb4f2a845b

See more details on using hashes here.

Provenance

The following attestation bundles were made for rekal-1.0.0.tar.gz:

Publisher: release.yml on janbjorge/rekal

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

File details

Details for the file rekal-1.0.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for rekal-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5f4a4076e5a3ea999ff2a53770cddd5623a757fde35d37b680e56520b21c881d
MD5 a0218771f20716dff3eae6dff58b506c
BLAKE2b-256 5cab9457ebf420a4d7ddab6a6d48d947a4ef76f837a4354c48e9ae8dd4f8b184

See more details on using hashes here.

Provenance

The following attestation bundles were made for rekal-1.0.0-py3-none-any.whl:

Publisher: release.yml on janbjorge/rekal

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