Local-first agent memory: versioned JSON categories, BM25 search, per-device ACL, fleet sync.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
π‘ Paste into ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
Inspect callable tools, capabilities, and parameters exposed to AI agents by Mcp Memory Rs.
memory_readRead a category (optional field filtering).
memory_writeReplace or merge-patch a category; versioned; `expected_hash` precondition.
memory_appendAppend 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_deleteDelete a category (backup created first).
memory_listAll categories with hash/size/last-update metadata.
memory_searchFTS5 full-text search, BM25 ranking, category/date/actor filters, snippets.
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.
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:
memory_history and memory_compact manage the tail.expected_hash turns clobbering races between
concurrent agents into explicit conflicts.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.
Prebuilt binary (recommended) β download the archive for your platform from the latest release, extract, and point your MCP client at the binary:
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:
--locked uses the committed Cargo.lock (reproducible build).
Claude Code (~/.claude.json) or any MCP client:
Codex (~/.codex/config.toml):
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 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.
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.
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.
| 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.
The server is built to be self-explanatory to a weak client model:
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).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).initialize and send notifications/initialized like any MCP client.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:
No build-time network access, no C dependencies beyond bundled SQLite.
Apache-2.0. See LICENSE.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/mcp-memory-rs)<a href="https://allmcps.com/mcp/mcp-memory-rs"><img src="https://allmcps.com/api/badge/mcp-memory-rs?style=directory" alt="Mcp Memory Rs on AllMCPs" /></a>