Featured

Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off

Launch OpenClaw on Hostinger in about 60 seconds and keep your agent live 24/7. Our referral link gives you 20% off, no coupon code needed.

Launch on Hostinger
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed

Launch Hermes on Hostinger in one click, fully managed, no VPS knowledge needed. Use code ZACAARON10 for 10% off.

Launch on Hostinger
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off

Firecrawl crawls and scrapes any site into clean markdown for your agent. Get 1,000 free credits, and new users get 10% off their first purchase.

Try Firecrawl free
6,000+ web scrapers for your AI agent, start free logo6,000+ web scrapers for your AI agent, start free

Apify gives your agent live web data: 6,000+ prebuilt scrapers and actors, MCP-ready. Sign up free with $5 in usage credits.

Try Apify free
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.

Context.dev gives your agents a single API to scrape, enrich, and extract live web data — no proxies, no parsers, no maintenance.

Start building free
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams

White-glove OpenClaw for founders and exec teams (4–50+ employees): we install, harden, integrate your tools, and maintain it — secured from day one.

Get it set up for you
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit

DataForSEO gives your agent live access to SERP results, keyword data, backlinks, and on-page SEO data through one API. New accounts get a $1 credit, good for up to 20,000 keyword or backlink lookups.

Try DataForSEO free
Reach 48,000+ AI builders

A flat monthly placement in front of developers actively installing AI tools. No lock-in, cancel anytime.

Advertise here

Works with

Claude CodeClaude DesktopCursorVS CodeClineCodex CLIOpenClaw+ any MCP client

Install to Claude Code

This server doesn't publish a one-line install command. Follow the setup in the source repository.

Summary

Local-first agent memory: versioned JSON categories, BM25 search, per-device ACL, fleet sync.

README.md

mcp-memory-rs

![CI](https://github.com/DioNanos/mcp-memory-rs/actions/workflows/ci.yml) ![Tests](https://github.com/DioNanos/mcp-memory-rs/actions/workflows/ci.yml) ![License: Apache-2.0](LICENSE) ![Rust](https://www.rust-lang.org) ![Local First](#why)

Local-first MCP memory server in pure Rust. Persistent, versioned, queryable memory for AI agents — owned by the user, not by a platform.

State lives on your disk as plain JSON categories backed by SQLite (FTS5). Every write is versioned and backed up. A fleet of devices syncs through an optional HTTP endpoint with merkle manifests and optimistic concurrency. No cloud account, no embedding service, no network dependency in the default mode.

Why

Agent memory tied to a vendor dies with the vendor session. This server keeps the agent's long-lived state — identity, projects, infrastructure notes, per-device workflows — in files you can read, grep, diff, and back up yourself. Any MCP client (Claude Code, Codex, or anything speaking MCP stdio) gets the same memory; swapping the model does not lose the state.

Design choices that follow from that:

  • Local-first: the stdio server works fully offline against local storage.

Sync is a separate, explicit step — never a hidden dependency.

  • Plain storage: one JSON file per category plus a SQLite index. The

database can be rebuilt from the files; the files are the truth.

  • Versioning by default: every write keeps history; deletes create a

backup first. memory_history and memory_compact manage the tail.

  • Concurrency-safe writes: expected_hash turns clobbering races between

concurrent agents into explicit conflicts.

  • Zero ML in the core: full-text search is SQLite FTS5 with BM25;

memory_search_semantic adds an optional TF-IDF hybrid. No model downloads.

The pair: for corpus recall (chunked documents, BM25 retrieval, original-text injection) see the companion server mcp-vl-msa-rs. This server holds the curated agent state; that one holds the queryable corpus.

flowchart LR
    A["AI agent<br/>(any MCP client)"]
    A -->|"curated state<br/>read / write / sync"| M["mcp-memory-rs<br/><i>the notebook</i>"]
    A -->|"corpus recall<br/>index / search / fetch"| V["mcp-vl-msa-rs<br/><i>the library</i>"]
    M --- D1[("JSON categories<br/>SQLite FTS5")]
    V --- D2[("tantivy BM25<br/>collections")]

Install

Prebuilt binary (recommended) — download the archive for your platform from the latest release, extract, and point your MCP client at the binary:

tar xzf mcp-memory-rs-x86_64-unknown-linux-gnu.tar.gz
install -m755 mcp-memory-rs-*/mcp-memory-rs ~/.local/bin/

Prebuilt targets (Linux + Android): x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl, aarch64-unknown-linux-gnu, aarch64-unknown-linux-musl (edge / ARM / Termux), aarch64-linux-android.

macOS: no prebuilt binary is shipped (it would need Apple code-signing). Install from source instead — cargo install compiles it on your Mac in one command, no signing needed:

cargo install --git https://github.com/DioNanos/mcp-memory-rs --locked

--locked uses the committed Cargo.lock (reproducible build).

Quick start

cargo build --release

# stdio MCP server, offline mode (default)
./target/release/mcp-memory-rs

Claude Code (~/.claude.json) or any MCP client:

{
  "mcpServers": {
    "memory": {
      "command": "/path/to/mcp-memory-rs",
      "env": {
        "MCP_MEMORY_CONFIG": "/home/me/.config/mcp-memory-rs/config.toml",
        "MCP_MEMORY_REQUIRE_CONFIG": "1",
        "MCP_MEMORY_MODE": "offline",
        "MCP_DEVICE": "my-laptop"
      }
    }
  }
}

Codex (~/.codex/config.toml):

[mcp_servers.memory]
command = "/path/to/mcp-memory-rs"
env = { MCP_MEMORY_CONFIG = "/home/me/.config/mcp-memory-rs/config.toml", MCP_MEMORY_REQUIRE_CONFIG = "1", MCP_MEMORY_MODE = "offline", MCP_DEVICE = "my-laptop" }
# auto-approve read-only tools (memory_read/list/search/…); writes still gated
default_tools_approval_mode = "approve"

Configuration is TOML — copy config/example.toml to ~/.config/mcp-memory-rs/config.toml and adjust it. The server auto-discovers that XDG-style path. Environment variables override file values (MCP_DEVICE, MCP_MEMORY_MODE, MCP_MEMORY_DIR, …); managed deployments should set MCP_MEMORY_REQUIRE_CONFIG=1 so a missing config fails closed.

Memory model

Memory is organized in categories: named JSON documents (base, projects, my-laptop, workflow_my-laptop, …). Reads return the document plus metadata (content hash, size, last writer, timestamp). Writes replace the category or, with merge=true, patch it per top-level key.

Access control

Multi-device fleets get a small, explicit ACL ([acl] in the config):

| Rule | Effect | |---|---| | admin_devices | Listed devices write everything. | | device_categories | Device name writes category name and workflow_name — its own namespace only. | | agent scope | Device foo-agent writes foo_* categories. | | everyone | All devices read everything. |

Unknown categories are denied for non-admin writers — fail closed.

Fleet sync

Each node runs local-first; one node (or any number) exposes the HTTP API as a sync remote. sync_manifest builds a merkle-rooted fingerprint of all categories; sync_diff compares manifests; memory_sync pushes dirty categories or pulls remote changes. Conflicts between nodes are resolved by the configured conflict_strategy (last-write-wins by default); expected_hash preconditions protect direct writes (MCP and HTTP), not the sync envelope.

The HTTP API is an admin/sync plane: the bearer token grants full access to every category. Per-category ACL applies on the MCP stdio surface, where the device identity is known locally; HTTP callers are identified only by the shared token, so no per-device ACL is enforced there.

The HTTP server requires MCP_MEMORY_TOKEN and refuses to start without it. Bind it to loopback (the default) and tunnel between nodes; do not expose it to the public internet.

MCP_MEMORY_TOKEN=<secret> ./target/release/mcp-memory-rs --http

Tool surface

| Tool | Description | |---|---| | memory_read | Read a category (optional field filtering). | | memory_write | Replace or merge-patch a category; versioned; expected_hash precondition. | | memory_append | Append a timestamped entry to a bounded append-only log category; auto-prunes by max_entries/max_age_days. For event streams / session journals, so they don't bloat memory categories. | | memory_delete | Delete a category (backup created first). | | memory_list | All categories with hash/size/last-update metadata. | | memory_search | FTS5 full-text search, BM25 ranking, category/date/actor filters, snippets. | | memory_search_semantic | Hybrid TF-IDF + FTS5 search. | | memory_history | Version history of a category. | | memory_delta | Changes since a known hash (cheap polling). | | memory_context | Multi-category warmup read, token-budget oriented. | | memory_compact | Prune old versions and backups. | | memory_status | Local-first status: dirty queue, manifest hash, last sync. | | memory_doctor | Diagnostics: paths, database, categories, sync config. | | sync_manifest | Merkle-rooted manifest of all categories. | | sync_diff | Compare local vs remote manifest: push/pull/conflict sets. | | sync_push / sync_pull | Export/import sync envelopes. | | memory_sync | One sync step against the configured remote (push_dirty / pull_remote). |

The same surface is available over HTTP (/api/v1/*) for non-MCP consumers; /health is unauthenticated, everything else requires the bearer token.

AI client compatibility

The server is built to be self-explanatory to a weak client model:

  • At initialize it returns an instructions string describing the memory

model and the entry-point tools. Some lightweight clients ignore this field; if your client never surfaces it, read the tool descriptions instead — they carry the same guidance (e.g. memory_read takes category, not key).

  • Read-only tools are annotated readOnlyHint, so a client such as Codex can

auto-approve them. On Codex, an unsupported call / user cancelled result usually means the tool-approval gate fired, not a server fault — set default_tools_approval_mode = "approve" (see the Codex snippet above).

  • The server speaks the standard MCP handshake. A client must complete

initialize and send notifications/initialized like any MCP client.

Storage layout

With no config and strict mode disabled, standalone base_dir remains ~/.memory for compatibility. The auto-discovered example config uses ~/.local/state/mcp-memory-rs (XDG-style). Config resolution is: explicit MCP_MEMORY_CONFIG, $XDG_CONFIG_HOME, $HOME/.config, legacy cwd-local memory-config.toml, then standalone defaults. Either way the layout is:

<base_dir>/
├── categories/   # one .json file per category — the source of truth
├── backups/      # automatic pre-delete/pre-overwrite backups
└── memory.db     # SQLite: FTS5 index, versions, sync state (rebuildable)

Building and testing

cargo build --release   # single static-friendly binary
cargo test              # unit + integration tests
cargo clippy --all-targets -- -D warnings

No build-time network access, no C dependencies beyond bundled SQLite.

License

Apache-2.0. See LICENSE.

See related servers & alternatives →

Related MCP servers

Browse all →

Related guides

Hand-picked reading to help you choose and use Vector & Memory servers.