memory-arbiter-mcp
This server provides a fully local, SQLite-backed shared memory store with built-in conflict arbitration for AI coding tools (e.g., ZCode, Codex, Cursor, Claude Code), enabling multi-agent collaboration through a unified MCP protocol.
Core capabilities:
Write structured memories: Store memories with rich metadata — content, subject, tags, agent ID, workspace, source type (
agent_generated,user_confirmed,document_extracted), confidence score, event time, and protection level.user_confirmedmemories are automatically locked against overwriting.Search memories: Query by keyword, tags, and workspace using a graceful fallback chain (FTS5 → LIKE).
Compare two memories: Analyze whether two memories conflict and receive a human-readable explanation — without recording any conflict.
Arbitrate conflicts: Resolve disputes using structured rules (user confirmation → event time → source trust → ingest time), with options to record the conflict and/or mark the loser as superseded.
Confirm and lock a memory: Promote a memory to
user_confirmedstatus with locked protection, preventing agents from overwriting it.List unresolved conflicts: View open conflict records across all agents and tools.
Check server status: Inspect the database path, degradation mode, client identifier, and policy configuration.
Key properties: Operates entirely locally (no cloud, no external LLM calls), degrades gracefully across sqlite-vec → FTS5 → LIKE → JSONL backup, and supports per-client enable/disable settings and agent allow/deny lists for governance.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@memory-arbiter-mcpsave that the user prefers dark mode"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Memory Arbiter MCP
English | 中文
Memory Arbiter is a trustworthy local fact layer for AI agents — not just shared memory, but shared facts that are current, trusted, traceable, and safe to use. It is a local SQLite service exposed over MCP: four product tools, evidence-based recall, advisory conflict notices, and user-authorized governance. Every fact is stored once in local SQLite and every model it can call runs locally.
Current release:
0.15.4(write-time duplicate hints recall via subject+tags vectors;scan_duplicatessweeps the whole library in one bounded call).
Why trust it
One complete source of truth. Every memory keeps its full original text. Evidence vectors, full-text search, and rankings are all derived indexes — rebuildable, never the only copy.
Provenance on every write. Each memory carries
source_type,source_ref,event_time, andingest_time. Theuser_confirmedlabel is reserved by convention for facts the user explicitly verified; technically enforced protection is what happens after labeling — auser_confirmedmemory is locked against silent edits.Trust levels.
normal/protected/lockedprotection levels prevent an agent from silently overwriting what is locked;memory_govern(confirm)promotes a memory touser_confirmedonly with per-action user authorization.Full version history. Every edit appends to
memory_historywith a version bump, and supersede chains keep old facts traceable instead of silently replaced.One conflict record per event. A single
conflictstable holds the immutable detection snapshot, value groups, decision, and application results for each one-to-many conflict event. Qwen proposes no winner and never edits memory.Authorized governance. Every state-changing
memory_governaction requires per-actionauthorized=trueafter the user confirms that specific action.Local-only. Embeddings run on a local GGUF model; the optional Qwen filter is a local GGUF too. The single outbound call is an optional PyPI update check, disabled with
update_check.enabled=false.
Related MCP server: memory-mcp
Install & quickstart
Install with your AI Agent
Paste this into Codex, Claude Code, Cursor, or another coding agent with terminal access:
Read the latest README at https://github.com/billy12151/memory-arbiter-mcp.
Install and configure the latest mema release for my operating system and current AI client.
Preserve any existing config and database; do not overwrite or delete existing data.
Ask me before choosing between materially different install modes, changing existing config,
or performing any destructive or privileged action. When finished, run mema doctor and report
the install method, config path, database path, client integration, and verification result.The agent should treat this README as the source of truth, inspect the local environment before choosing uvx, core, vec, or semantic-local, and stop for user input when a safe choice cannot be inferred. A successful install is not complete until mema doctor has run and any warning has been reported.
Install manually
pip install memory-arbiter-mcp
pip install "memory-arbiter-mcp[vec]" # sqlite-vec evidence recall
pip install "memory-arbiter-mcp[semantic-local]" # local GGUF runtime (embeddings + Qwen)Run mema setup to write ~/.config/memory-arbiter/config.json and self-check the embedding environment (it never installs or downloads anything). Since 0.15.0 configuration is file-only and the whole user surface is 18 keys (see Configuration): paths, identity, workspace/isolation, update_check.enabled, the embedding model, the optional semantic-conflict Qwen model, and MCP transport/host/port. The reference examples/memory-arbiter.config.example.json shows the same slim surface with per-key notes. Then wire your MCP client from examples/*.mcp.json and start the server with mema.
The server requires an explicitly configured identity: set client and agent_id in config.json or the MEMORY_ARBITER_CLIENT/MEMORY_ARBITER_AGENT_ID launch-context environment variables (the stdio examples/*.mcp.json entries do this via env). There are no built-in defaults — the server refuses to start when either is blank. Under stdio this configured identity is the process-level caller identity used for attribution and policy decisions; memory(action="remember") does not accept agent_id/client in data. streamable-http takes caller identity from the per-request headers described below.
stdio remains the default. For one local server shared by several clients, set mcp.transport to streamable-http (or MEMORY_ARBITER_MCP_TRANSPORT=streamable-http, one of the six retained launch-context variables) and connect to http://127.0.0.1:8000/mcp. Each client's MCP server entry must set fixed X-Mema-Client and X-Mema-Agent-Id headers; see examples/streamable-http.mcp.json. The client sends them automatically on every HTTP MCP request—agents should not add identity to individual tool calls. Missing, empty, invalid, duplicated, or conflicting identity is rejected instead of falling back to defaults. Community HTTP mode binds only to localhost, and these headers are advisory provenance and policy input, not authentication or multi-tenant isolation.
The daily loop is four calls — remember a reusable fact, find to recall, read for exact lookup, update when a newer source replaces an existing current memory (never create a second active copy of one source of truth). Point any agent at the packaged rule:
{"action":"help","data":{"topic":"agent_onboarding"}}The four tools
memory:remember,find,read,update,judge,status,helpmemory_review: read-only health, conflict groups/details, history, expired memory, audit, and entitiesmemory_govern: explicitly authorized retirement, conflict-plan application/resolution, confirmation, and workspace governancememory_repair: evidence rebuild, broad conflict scanning/recording, history cleanup, entity assignment, pending activation, backup replay, semantic runtime control, and notice lifecycle
Every product call returns the envelope {ok, mode, warnings, degraded, data}. Operation-specific action_required, next_action, replan, and records live under data; successful calls may additionally carry a top-level notices array. Each notice has its own action_required and machine-readable call under the notice object. Do not look for a generic top-level action_required.
find is an index page: by default each result carries metadata plus content_chars (the full-text length — what a read would cost) and a bounded outline of up to 8 {head, offset} segments whose offsets share read's span coordinate system, so span=[offset, offset+N] slices that exact segment. Full content is not returned by default; pass include_content=true to get it back (content_chars/outline stay either way). Scores compare only within the page, and if the top page misses you should reword the query or add tags_filter rather than deep-page — unfiltered query-recall reports total_estimate=null/has_more=false, while filtered recall keeps the exact count. The size block meters the page as actually returned: returned_chars/returned_count and a tokens_estimate from a deterministic bucket-table estimator (heuristic_v1) calibrated against a Qwen2.5 tokenizer on real records; it runs ~30% high on pure Chinese prose and ~17% high on pure English — the estimate and the estimated share one yardstick, so savings comparisons stay valid. unresolved_conflict_count appears only when page items directly hit an open/applying conflict group, and counts those page items.
How recall works
Lexical and evidence channels recall independently and merge per memory with reciprocal-rank fusion, then trust, recency, filter, and workspace adjustments.
Lexical: FTS5 over content plus subject/tags LIKE and a bounded content-LIKE anchor channel.
Evidence: a background worker derives local-text evidence units from the
subject, Markdown headings, sentence/paragraph groups, and overlapping windows for long text. The indexer never extracts facts, infers entities, or calls a model — it only slices the stored source. Evidence hits carry source offsets.memory(action="read", data={"memory_id": 42, "span":{"start":120,"end":640}})returns only that clipped source window plusdata.span.{start,end,total_chars}; omitspanto read the complete source. Span bounds are strict integers with0 <= start < end, andendclips at content length.
Conflict groups and notices
Evidence KNN recalls sentence-level neighbours; it does not decide conflict truth. For each short pair, optional local Qwen runs in both directions (A→B and B→A) and may return exactly four fields:
{"attribute_a":"database","value_a":"MySQL","attribute_b":"database","value_b":"SQLite"}Code then validates the JSON, side mapping, mechanical attribute/value normalization, quote grounding, duplicate/compatibility rules, and entity/scope provenance. Qwen never chooses a winner, suppresses the scheduled scan, or edits memory.
There are deliberately two gates:
Scheduled scan is broad.
memory_repair(task="scan_candidates")retains deterministic KNN/rule candidates and — when the local Qwen runtime is up (scan enhancement is always on, a frozen constant) — runs a bounded per-page Qwen enhancement: rule candidates gain extracted attribute/value fields andvalue_groups, similarity-only pairs (normally opt-in viainclude_check) that extract a valid same-attribute/different-value in either direction are unioned in, and verified candidates with matching entity/scope are aggregated intoslot_groups. Fixed bounds cap the cost (8 Qwen pair evaluations per page, 60 s page deadline). Single-direction, weak-grounding, and incomplete entity/scope cases remainreview_candidate; a model failure never shrinks the baseline candidate set.include_duplicates=truestays a single-page spot check (full record_conflict-compatible members for that page); for a full duplicate sweep use the separatememory_repair(task="scan_duplicates")task, which aggregates every page server-side under one global 200-pair cap. The external reviewer records every triaged candidate withrecord_conflict(status="open"|"not_a_conflict")to obtain snapshot dedupe.Write-time notice is strict. A user-visible notice requires two valid, mutually consistent four-field extractions, grounded differing values, a complete canonical
workspace + entity + attribute + scope, and no deterministic coexistence veto. Anything less fails closed into later scan review. The fixed 5 s synchronous-delivery wait only gates when a notice is attached; it does not change detection.
Set up the two scheduled tasks. mema does not ship an internal timer by design: the scan's value loop ends in agent-side triage, so the external scheduler is what wakes the agent. Create two tasks on any scheduler you like — an hourly memory_repair(task="scan_candidates") paging loop (feed each page's next_anchor_memory_id into the next call until null) and a daily memory_review(view="doctor"). Each completed full-scan boundary (a page returning next_anchor_memory_id=null with anchors scanned) appends one lightweight audit line to scan_log.jsonl; until then agents receive a scan_never_run/scan_stale guidance notice, and doctor flags a still-owed rebuild (conflicts.scan_required) or a scan idle beyond 14 days (conflicts.scan_stale) — once the tasks run, both fall silent on their own. The full platform-agnostic spec is memory(action="help", data={"topic": "scheduled_tasks"}).
The single conflicts table stores one one-to-many event and its immutable member/value snapshot. Its public lifecycle is open → applying → resolved, with not_a_conflict as a terminal triage result. memory(action="judge") CAS-pins the conflict revision, records the chosen value and plan, and moves it to applying; execute each returned memory_govern(action="apply_conflict_action") sequentially with explicit authorization and the latest revision, then call authorized resolve_conflict only after every planned member action completes. Partial failures remain applying: when data.action_required="replan_conflict", re-read the group/members and call authorized memory_govern(action="replan_conflict") with the current revision and replacement plan. Replanning preserves prior plan history; never retry stale precomputed steps.
Workspaces
Workspace canonical normalization runs in every isolation mode and is separate from access control. none applies no workspace ACL: an omitted workspace spans the library, while an explicitly supplied workspace is canonicalized and scopes that read. weak adds a soft ranking/hint signal (a fixed binary nudge — the continuous vector-distance weighting is no longer a knob). Under strict, Qwen never silently merges a near-match: a new workspace stays pending until authorized memory_govern(confirm_pending_workspace) activates it. Strict visibility uses guarded vector admission (always on since 0.15.0, a frozen constant): workspace-sensitive recall/read/repair operations, conflict/notice workflows, and console content/count views share one admitted set: the caller canonical plus every canonical at or below a 0.25 cosine cutoff after default-pool, short-name, and generic-substring guards. Process-global maintenance (for example semantic runtime control, backup replay, doctor, and settings) is not a workspace-scoped content view. Missing vectors or sqlite-vec degradation fall back to the exact caller canonical. The reserved default pool is insulated and is not visible from a strict project scope. Automatic vector/Qwen normalization affects only the memory's workspace_canonical; supported workspace governance uses rename, migrate, move-by-id (move_memories_workspace), pending confirmation, and full-registry confirmation. Internal redirect/negative-decision state prevents old names from re-splitting and suppressed candidates from reappearing, but is not a user-facing workflow.
The first successful write that registers a canonical workspace returns a non-blocking top-level workspace_review notice in none/weak, plus data.write_hints.new_workspace_detected. Review possible duplicates before running authorized confirm_workspaces. strict instead returns the existing blocking action_required=confirm_new_workspace flow and does not emit the duplicate non-blocking notice.
Operating mema
mema doctor [--json|--deep]— read-only health checks;--deeploads the GGUF model and probes the live embedding dimension.workspace.reviewwarns (CLI exit 1) for canonicals missing from the reviewed snapshot. Rename/merge duplicates first, then call authorizedmemory_govern(confirm_workspaces)without an explicit list to snapshot the current registry and return this check to pass. The overall CLI exits 0 only when no other warning remains.mema console— read-only local console on 127.0.0.1.memory(action="status")— surfaceslocal_text_evidencecoverage,vec_index_state, the process-local index queue, andsemantic_conflictruntime including queue drops/restarts andcheck_degradation.last_reason.Maintenance tasks on
memory_repair:rebuild_evidence(dry-run then batched execute; after an embedding-model change the index reportsstate=mismatchand rebuild flips it back toreadyautomatically),semantic_control(status/pause/resume/enable/unload/disable),replay_backup(dry-run then authorized execute),cleanup_history,set_entity,activate_pending, andscan_duplicates(a one-call full-library near-duplicate sweep bounded at 200 lightweight pairs;include_quotes=trueadds the triggering evidence quotes).
Evidence/semantic queues are process-local, so a crash or forced shutdown can lose queued work. Do not infer durable coverage from queue depth. After a restart or an evidence-side busy/discard signal, inspect local_text_evidence coverage and run rebuild_evidence until its dry-run is empty and the vector state is ready; semantic-worker queue drops are recovered by the scheduled scan_candidates pass, not by rebuild_evidence. Rebuilding evidence is idempotent derived-index repair; scanning is what recovers conflict candidates/notices that were never processed.
Upgrading from an older database
Upgrade warning for 0.14.8: current runtime startup accepts only schema generation workspace_state_v1. Both conflict_groups_v2 and local_text_evidence_v1, plus older claim/memory-vector/section-vector databases, are refused without modification. Run the public side-by-side mema upgrade. Every schema migration declares vector_effect=preserve|rebuild; the migrations from the two previous evidence generations preserve vector payloads regardless of current model availability. Compatibility is evaluated separately: a different configured embedding space records state=mismatch, disables vector reads, and is repaired later with memory_repair(rebuild_evidence). Both paths compact current workspace redirect/negative-decision state and discard the obsolete workspace decision event ledger.
The side-by-side copy retains memory content/history, backup replay receipts, workspace canonicals and current redirect/negative-decision state, and audit. The obsolete workspace decision event ledger is not copied. Preserve migrations clone FTS/evidence/vector payloads unchanged and transactionally rebuild only the conflict domain; vector health or space mismatch never changes the structural migration result. Rebuild migrations regenerate evidence and vectors. Both paths intentionally start with empty new conflicts/notice state and do not copy old conflicts, append-only conflict_judgments, or semantic_notices history. Current contradictions must be rediscovered by a scheduled full-library scan.
After rebuild, status/doctor reports conflict_scan_required=true with a persistent scan epoch. Only a successful full scan covering the upgrade-time active-memory set with the matching detector version may CAS-clear that flag; partial pages, failed scans, and older-detector scans do not. The target is published only after row/fingerprint checks, a successful PRAGMA wal_checkpoint(TRUNCATE), and removal of target WAL/SHM sidecars — the full-rebuild path additionally requires complete eligible evidence coverage; the source database is never deleted.
# Preview only.
mema upgrade --dry-run
# Stop every mema MCP client/worker. Make a WAL-safe rollback backup:
sqlite3 /absolute/path/to/memory.sqlite3 "PRAGMA wal_checkpoint(TRUNCATE);"
cp /absolute/path/to/memory.sqlite3 /absolute/path/to/memory.pre-0.14.sqlite3
# Migrate and switch the standard JSON config.
mema upgrade
# Restart the MCP client and verify.
mema doctor --jsonThe full evidence-rebuild path requires sqlite-vec, a configured/readable local GGUF embedding model, llama-cpp-python (install the semantic-local extra because it also runs GGUF embeddings), a writable target directory, and enough free disk. A preserve migration does not load either model and does not require vector completeness; it reports vector compatibility independently and marks incompatible preserved data mismatch. The optional semantic-conflict Qwen model itself is never a migration prerequisite. The command reports its selected mode, vector effect/compatibility, memory count, estimated vector work, free disk space, source, and target before asking for confirmation.
The explicit checkpoint above matters because copying only the main .sqlite3 file while live WAL frames exist is not a complete backup; alternatively use SQLite's online .backup command before stopping. Abort if wal_checkpoint(TRUNCATE) reports a non-zero busy count. mema upgrade also checkpoints/verifies the new target before switching, but it does not create the operator's rollback copy of the source.
The old database is never deleted. Standard JSON configuration is backed up and switched only after full verification; environment-variable db_path overrides are reported as a manual action. Use --no-switch to build and verify without editing configuration. --yes skips both the interactive confirmation and its acknowledgement that all writers/workers are stopped and old conflict/judgment/notice history will be permanently omitted; it does not stop processes, checkpoint the source, or create a backup. The lower-level mema migrate-vnext command remains available for diagnostics. Keep the old database until the new one has run successfully in normal use; if the new database has accepted writes, do not switch back without first accounting for those newer records.
Configuration
Configuration is file-only since 0.15.0. Everything tunable lives in ~/.config/memory-arbiter/config.json (or the file the MEMORY_ARBITER_CONFIG launch-context variable points at; mema setup writes the starter template). Engine parameters, timeouts, thresholds, and caps are frozen constants (memory_arbiter/constants.py).
The complete user surface is 18 keys:
{
"db_path": "~/.local/share/memory-arbiter/memory.sqlite3",
"backup_jsonl": "~/.local/share/memory-arbiter/memory.backup.jsonl",
"client": "your-client",
"agent_id": "your-agent-id",
"workspace": "default",
"isolation": "none",
"policy_path": null,
"update_check": { "enabled": true },
"embedding": {
"model_path": "~/.local/share/memory-arbiter/models/embedding.gguf",
"auto_query": true,
"auto_write": true
},
"semantic_conflict": {
"enabled": true,
"model_path": "~/.local/share/memory-arbiter/models/qwen2.5-0.5b-instruct-q4_k_m.gguf",
"on_write": "async",
"max_notice_pairs": 2
},
"mcp": {
"transport": "stdio",
"http": { "host": "127.0.0.1", "port": 8000 }
}
}Setting | Purpose |
| Current SQLite database |
| Append-only fallback when SQLite cannot write |
| Required caller identity; no built-in defaults — the server refuses to start when either is blank |
| Default workspace and |
| Optional client/agent tool-routing policy file |
| Optional one-shot background PyPI discovery (default |
| Local GGUF embedding model — pointing at it is the sole intent to enable sqlite-vec evidence recall |
| Auto-embed at query/write time (default |
| Optional local Qwen2.5-0.5B GGUF for bidirectional four-field extraction; configured → auto-enabled, loaded at startup, and kept resident |
| Explicit off-switch; unset + |
| Write-time detection: |
| Per-write notice cap (1–3, default |
|
|
| Local HTTP endpoint; host is restricted to loopback, defaults to |
See examples/memory-arbiter.config.example.json.
Semantics worth knowing: the embedding dimension comes from the model itself — the database records the active dimension, and switching to a model with a different dimension automatically drops and rebuilds the vector tables at the new dimension at startup (a one-time full evidence rebuild). Ranking is fixed hybrid (lexical + evidence fusion); there is no ranking-mode knob. HTTP request handling is stateless with a 4 MB request-body cap.
Six environment variables remain as launch context: MEMORY_ARBITER_CONFIG, MEMORY_ARBITER_DB_PATH, MEMORY_ARBITER_BACKUP_JSONL, MEMORY_ARBITER_MCP_TRANSPORT, MEMORY_ARBITER_CLIENT, MEMORY_ARBITER_AGENT_ID. They select process context (which config file, which DB, which transport, which identity), and a config-file value wins over the matching variable. Every other MEMORY_ARBITER_* variable is no longer read — a stale export surfaces a "no longer read" warning in mema doctor, the console settings page, and memory(action="status"). Removed file keys similarly warn "no longer configurable" and are ignored; docs/INTEGRATION.md carries the 0.14 → 0.15 key-migration table.
HTTP mode: sharing one local server
stdio (the default) needs no background process: each MCP client launches mema as its own short-lived child process. Switch to streamable-http only when you want one long-lived local server that several clients connect to.
stdio (default) | streamable-http | |
Who starts mema | each client spawns a child process | you run one persistent process; clients connect to it |
Background process needed | no | yes — otherwise it dies when the terminal closes |
Client config | command + args | url + two fixed request headers |
Good for | one person, one client | several clients on one machine sharing one memory store |
Setting it up:
Config: set
mcp.transportto"streamable-http"in~/.config/memory-arbiter/config.json(orMEMORY_ARBITER_MCP_TRANSPORT=streamable-http).Keep it running: mema has no built-in daemon — use a process manager. On macOS, the launchd template at
examples/com.memory-arbiter.mema.plistruns it at load, restarts on crash, and logs to/tmp/mema.{out,err}.log(replace__MEMA_BIN__with the absolute pathwhich memaprints; put it in~/Library/LaunchAgents/thenlaunchctl load). For a quick try,tmux new -d -s mema 'mema'works.Client: copy
examples/streamable-http.mcp.json, filling inX-Mema-ClientandX-Mema-Agent-Id.
Notes: HTTP request handling is stateless (a frozen constant since 0.15.0) because mema keeps memory and semantic-notice state in SQLite, not in an MCP session. A service restart therefore does not leave clients holding an expired server session. Semantic notices created asynchronously are claimed from SQLite and attached to a later successful tool response as before; only a worker job that has not yet persisted its notice can be interrupted by a process restart.
The client sends the fixed headers automatically on every HTTP MCP request — agents must not add identity to individual tool data, or it is rejected. Missing/empty/duplicate/conflicting identity fails closed (400), never falling back to defaults. The service binds to loopback only; these headers are provenance, not authentication. Because launchd does not inherit your shell PATH or expand ~, put absolute paths in ProgramArguments and for any GGUF model_path in config.json.
Claude Desktop / Claude Code through localhost HTTP
Claude's local MCP configuration launches stdio commands. To reuse one running mema HTTP service instead of spawning another mema process, put this single entry under mcpServers in ~/.claude.json (current Claude Desktop/Cowork and Claude Code installations may share this user-level file):
{
"mcpServers": {
"memory-arbiter": {
"command": "/opt/homebrew/bin/npx",
"args": [
"-y",
"mcp-remote@0.1.43",
"http://127.0.0.1:8000/mcp",
"--allow-http",
"--transport", "http-only",
"--header", "X-Mema-Client:claude",
"--header", "X-Mema-Agent-Id:claude",
"--silent"
],
"env": {
"PATH": "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",
"NO_PROXY": "127.0.0.1,localhost"
}
}
}
}Use the absolute npx path from which npx on your machine. Remove any older memory-arbiter entry that directly launches mema/memory-arbiter-mcp, otherwise Claude may start a second server process. Fully quit and reopen Claude Desktop, and restart Claude Code sessions after changing the file. mcp-remote is a third-party bridge; the pinned version above is the configuration tested with mema. If your Claude installation uses a separate Desktop MCP file, place the same single entry there instead, but do not register both copies.
Degradation
Without sqlite-vec or an embedding model, lexical recall and memory governance continue; evidence indexing is unavailable.
Without Qwen, strict write-time model-dependent notices fail closed; scheduled scan continues returning its deterministic KNN/rule baseline candidates.
If SQLite is unavailable or unwritable, writes use the append-only JSONL envelope only when that write succeeds. JSONL contains memory records and their selected canonical, not internal redirects or negative decisions; preserve or upgrade the SQLite database to retain workspace decision state.
Development
uv run pytest -q
python scripts/sync_version.py --checkDuring development, package/docs may describe an unreleased dev version while server.json intentionally remains at the last published registry release (0.13.1). The registry manifest is advanced only as part of release preparation; do not treat that deliberate lag as the runtime/database upgrade matrix.
中文摘要
Memory Arbiter(迷码)是面向 AI Agent 的本地可信事实层:每条事实只存一份完整原文,向量与检索均为可重建的派生索引。冲突 scan 走宽门召回,write-time notice 走双向四字段 Qwen 抽槽与严格 grounding;单一 conflicts 表保存一对多事件,生命周期为 open → applying → resolved 或 not_a_conflict。裁决后按 judge → apply_conflict_action → resolve_conflict 顺序治理。none/weak/strict 都做 workspace 归一;strict 使用 guarded vector admission,default 池不进入项目 scope。workspace_state_v1 升级会清除旧 conflict/judgment/notice 历史和旧 workspace decision event ledger,并要求完成带 epoch 的全库 scan。完整中文文档见 README.zh-CN.md;另见 INTRO.md 与 docs/INTEGRATION.zh-CN.md。
Available Tools
4 toolsmemoryA
Daily memory operations: remember, find, read, update, judge, status, help.
Call memory(action="help") to discover accepted fields, judge requirements, value enums, update modes, and action_required paths before relying on a result that requests attention.
find is an index page: results carry metadata + content_chars + a bounded outline (offsets usable directly as read span starts), not full content — pass include_content=true for full text. Score compares only within the page; if the top page misses, reword the query or add tags_filter instead of deep paging. The size block meters the returned page (tokens_estimate + display_hint).
| Name | Required | Description | Default |
|---|---|---|---|
| data | No | ||
| action | No | help |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden, and it adds real behavioral detail for find: index-page semantics, include_content=true for full text, page-scoped scoring, and a size block. However, it does not disclose side effects, permissions, or outcome implications for remember, update, judge, or status, so behavioral coverage is incomplete across the tool's surface.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the action list and uses three compact paragraphs, each with a distinct job: overview, help-first advice, and find semantics. There is no filler or repetition; every sentence adds information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description fully details only the find action and points to help for the rest; remember, read, update, judge, and status semantics are left undisclosed. Sibling tool boundaries are not addressed, so an agent still needs extra discovery before confidently using all operations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It lists the accepted action values, mentions action='help', and names concrete data fields such as include_content and tags_filter. The full data object shape is left to the help action, but this partial enumeration is meaningful.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Daily memory operations' and enumerates the supported verbs (remember, find, read, update, judge, status, help), making the dispatch role clear. It does not fully explain what each operation does, and 'memory operations' is somewhat generic, but it is enough to distinguish this tool from the memory_review/govern/repair siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit guidance to call action='help' before relying on results, and advises rewording the query or adding tags_filter instead of deep paging. It does not name sibling tools or state when memory_review/govern/repair should be chosen instead, so exclusions/alternatives are missing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_governB
Authorized governance: retire, merge near-duplicates, apply/replan/resolve conflicts, confirm, and manage workspaces.
Every state-changing action requires explicit user authorization for that action, then authorized=true. Call memory_govern(action="help") for exact actions, accepted fields, impact notes, and confirmation semantics.
| Name | Required | Description | Default |
|---|---|---|---|
| data | No | ||
| action | No | help |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It does disclose that actions are state-changing and gated on explicit user authorization, which is important safety-relevant context. But it doesn't detail what gets retired, merged, or changed, and it defers impact notes and confirmation semantics to the help action rather than providing them up front.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded with the tool's governing purpose, then moves to the authorization guardrail and the help-first instruction. It contains no filler and each sentence contributes useful guidance. It could be slightly more structured, but it is appropriately sized.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description gives enough to know this is a governance tool and warns that authorization is required, but it deliberately defers exact actions, fields, impact notes, and confirmation semantics to a runtime help call. That is a reasonable pattern for a dispatcher-style tool, but it leaves an agent without full context until that help call is made.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It only mentions action="help" and does not explain the data parameter or enumerate the accepted action values. The agent would have to call the tool with action="help" before it can meaningfully understand the parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names concrete governance operations: retire, merge near-duplicates, apply/replan/resolve conflicts, confirm, and manage workspaces. This is clear enough to identify the tool as the management/curation surface among siblings like memory_review and memory_repair. It lacks a single precise verb+resource phrasing, but it is not vague or tautological.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states a key precondition: every state-changing action requires explicit user authorization for that action, with authorized=true. It also directs the agent to call memory_govern(action="help") to learn exact actions and confirmation semantics. However, it does not discuss when to prefer this tool over memory_review or memory_repair, so sibling routing guidance is incomplete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_repairC
Maintenance: evidence rebuild, conflict scans (scheduled-task spec under help topic scheduled_tasks), full-library duplicate sweeps (scan_duplicates), history cleanup, entity assignment, pending activation, backup replay, notices, and semantic runtime control.
Use memory_repair(task="help") for notice handling and semantic_control actions. Semantic notices are advisory; read both memories before dismiss or resolve, and never pass a notice directly to judge or resolve_conflict.
| Name | Required | Description | Default |
|---|---|---|---|
| data | No | ||
| task | No | help |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It does disclose that semantic notices are advisory and imposes read-both-memories and do-not-forward constraints, which is useful. But it never states whether operations like history cleanup or backup replay are destructive, reversible, or permission-gated, leaving the tool's overall side effects opaque.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence packs an exhaustive comma-separated list of operations into a dense, ambiguous clause, while the second sentence contains essential usage and safety details. It is not overly long, but the structure buries actionability in a pile of items; a clearer mapping of task values to operations would be more effective.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With two generic parameters, no annotations, and zero schema descriptions, the description alone is insufficient for a multi-purpose maintenance tool. It points to a help topic but omits concrete argument semantics, side effects, and sibling differentiation needed to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the schema only shows generic task and data fields. The description demonstrates task="help" for notice handling but never enumerates valid task values or explains the data object at all, so an agent cannot reliably construct arguments for the listed operations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description frames the tool as a broad maintenance umbrella, listing many operations (evidence rebuild, conflict scans, duplicate sweeps, history cleanup, backup replay, notices, semantic runtime control) rather than a single specific verb+resource. It does not differentiate from sibling tools memory_review, memory_govern, or memory, so an agent would struggle to know exactly when this is the right tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is explicit guidance to use memory_repair(task="help") for notice handling and semantic_control actions, plus a caution to read both memories before dismissing or resolving and never pass a notice to judge or resolve_conflict. However, no guidance is given for the other listed maintenance tasks, and there is no 'when not to use' or comparison with sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_reviewA
Read-only inspection: overview, doctor, conflicts, conflict_detail, history, expired, audit, entities, help.
Use memory_review(view="help") for accepted fields. Inspect conflict_detail before judging a conflict so its members, value groups, revision, and apply state are visible.
| Name | Required | Description | Default |
|---|---|---|---|
| data | No | ||
| view | No | help |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It explicitly states the operation is read-only and adds a useful behavioral caveat about inspecting conflict_detail before judging a conflict. While it does not address rate limits or auth, those are less critical for a read-only inspection tool, and the description provides the key behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise, front-loading the core purpose in the first sentence and immediately providing actionable usage guidance. Every sentence earns its place, and there is no redundant filler. The structure makes it easy for an agent to quickly extract the essential information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is reasonably complete for a simple review tool: it lists the available views, points to help for accepted fields, and warns about conflict_detail. However, the `data` parameter remains completely unexplained, and there is no explicit guidance about when not to use this tool relative to siblings. The output schema mitigates some return-value ambiguity, but the parameter gap keeps this from being fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, but it only partially explains the `view` parameter by pointing to view="help" for accepted fields. The `data` parameter is never mentioned, leaving a significant gap in understanding. This makes the description insufficient for fully correct parameter use.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly labels the tool as 'Read-only inspection' and enumerates the specific views it exposes (overview, doctor, conflicts, conflict_detail, etc.), making the tool's intent evident. It differentiates from siblings like memory_govern and memory_repair by emphasizing inspection rather than governance or repair. The 'doctor' view is slightly ambiguous without further explanation, but the overall purpose is clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage directives: 'Use memory_review(view="help") for accepted fields' and 'Inspect conflict_detail before judging a conflict.' These are concrete, actionable instructions for when and how to use the tool. It does not explicitly contrast with alternatives like memory_govern or memory_repair, but the 'Read-only' framing implies when this tool is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
The four tools are largely distinct: memory_review is read-only inspection, memory_govern is authorized state-changing governance, memory is daily operations, and memory_repair is maintenance. Some overlap exists around conflicts/duplicates across govern and repair, and memory vs memory_review could be mildly confused at first glance, but descriptions make the boundaries clear.
Three tools follow a consistent memory_<verb> pattern and all names use lowercase snake_case. The bare memory tool is a minor deviation from the verb_noun pattern, but it reads naturally as the core daily operations tool, so the naming is mostly consistent and predictable.
Four tools is well-scoped for a memory management server. Each tool represents a coherent functional area and earns its place; the count is neither too thin nor overloaded.
The tool surface covers the memory lifecycle well: create/read/update/find/judge via memory, inspection and auditing via memory_review, governance and retirement via memory_govern, and repair/maintenance via memory_repair. No obvious dead ends or critical missing operations are apparent for the stated domain.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
One memory, every AI. A shared, user-owned markdown memory your AI clients read and write over MCP.
Persistent AI memory shared across Claude, ChatGPT, coding agents, and compatible MCP clients.
An MCP memory server. One memory your agents share — across models, devices and apps.
Real-time chat for AI agents. Claude Code, Cursor, Cline and Codex join channels over MCP.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA self-hosted MCP server that provides AI assistants with a shared, persistent SQLite-backed memory for storing and retrieving project context, decisions, and discoveries. It enables cross-session continuity and team-wide knowledge sharing to keep AI coding tools aligned and informed.3MIT
- FlicenseNot gradedqualityDmaintenanceA persistent, conflict-aware memory MCP server for AI coding assistants (Cursor, Claude Code).

threadctx-mcpofficial
AlicenseAqualityBmaintenanceShared memory MCP server for AI coding agents, enabling context sharing across sessions with local SQLite or cloud-based semantic search, compatible with Claude Code and Cursor.2681MIT- AlicenseAqualityCmaintenanceA local-first MCP server that provides a shared Markdown-based memory for AI coding agents, enabling cross-agent context persistence via tools like memory_search and memory_capture.101MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/billy12151/memory-arbiter-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server