agentic-memory

agentic-memory

A persistent, bitemporal, injection-safe memory MCP server for coding agents, offering unified retrieval across six memory layers, non-destructive belief revision, and multi-tenant namespace isolation.

Category
访问服务器

README

<p align="center"> <img src="assets/banner.svg" alt="Agentic Memory — A Persistent, Bitemporal, Injection-Safe Memory MCP for AI Agents, by Verace Pvt. Ltd." width="100%"> </p>

<p align="center"><b>A Persistent, Bitemporal, Injection-Safe Memory MCP for AI Agents</b></p>

A memory server for coding agents (Claude Code, Claude Desktop, Cursor, Antigravity, Codex CLI, or any MCP-compliant client) that goes beyond the naive "five separate buckets" model of agent memory: non-destructive belief revision, injection-safe context synthesis, real embeddings with ANN search, multi-tenant namespace isolation, and a choice of a zero-dependency SQLite backend or a Postgres + pgvector + Row-Level-Security backend for real deployments.


🏛️ Architecture

Six memory layers behind one unified retrieval call. Diagram renders natively on GitHub (Mermaid) — open this file on github.com if you're viewing raw markdown:

flowchart TD
    ENV(["Real-Time Environment<br/>user queries / tool output"])

    subgraph L1["1 · SENSORY MEMORY"]
        L1D["Ring buffer, saliency-scored<br/>Retention: ms → minutes"]
    end

    subgraph L2["2 · WORKING MEMORY"]
        L2D["Token-budgeted session context<br/>chronological, auto-compressing<br/>Retention: minutes → hours"]
    end

    subgraph L3["3 · EPISODIC MEMORY"]
        L3D["Causal event trajectories<br/>vector similarity retrieval<br/>Retention: weeks → months"]
    end

    subgraph L4["4 · SEMANTIC MEMORY"]
        L4D["Subject-predicate-object graph<br/>non-destructive belief revision<br/>hybrid vector + text + PPR search"]
    end

    subgraph L5["5 · LONG-TERM MEMORY"]
        L5D["Ebbinghaus-decay retrievability<br/>Truth Maintenance System<br/>Retention: days → years"]
    end

    subgraph L6["6 · PROCEDURAL MEMORY"]
        L6D["Registered skills / action recipes<br/>success-rate tracked"]
    end

    UQ{{"unified_query()<br/>ranks + fuses all 6 layers by one<br/>relevance function (similarity +<br/>recency + importance + graph proximity)"}}
    OUT(["One synthesized,<br/>injection-safe context block"])

    ENV --> L1
    L1 -- "promotion on high saliency" --> L2
    L2 --> L3
    L2 --> L4
    L3 <-.-> L4
    L3 --> L5
    L4 --> L5

    L1 --> UQ
    L2 --> UQ
    L3 --> UQ
    L4 --> UQ
    L5 --> UQ
    L6 --> UQ
    UQ --> OUT

    classDef sensory fill:#d1f5d3,stroke:#2e7d32,color:#1b1b1b
    classDef working fill:#e3d9f7,stroke:#6a3fb5,color:#1b1b1b
    classDef episodic fill:#c9dcf7,stroke:#2451a8,color:#1b1b1b
    classDef semantic fill:#c3ecd9,stroke:#1b7a4d,color:#1b1b1b
    classDef longterm fill:#cfe8ff,stroke:#1565c0,color:#1b1b1b
    classDef procedural fill:#ffe6cc,stroke:#e07b00,color:#1b1b1b
    classDef fusion fill:#111111,stroke:#111111,color:#ffffff

    class L1,L1D sensory
    class L2,L2D working
    class L3,L3D episodic
    class L4,L4D semantic
    class L5,L5D longterm
    class L6,L6D procedural
    class UQ,OUT fusion

A single unified_query call ranks and fuses all six layers by one consistent relevance function (embedding similarity + recency + importance + graph proximity), then returns one synthesized, injection-safe context block — not six separate results the caller has to stitch together itself.

What makes this different from a naive per-layer memory store

  • Non-destructive belief revision. Updating a fact never silently overwrites it. The old belief is marked superseded (with a timestamp and a pointer to what replaced it) rather than deleted — full audit history via get_belief_history() / get_semantic_belief_history().
  • Injection-safe context synthesis. Every retrieved memory item is wrapped in <memory trust="..." source="..."> tags with an explicit preamble telling the LLM that memory content is untrusted historical data, not instructions. All angle brackets in stored content are escaped (not just the <memory> tag itself) — so a stored item can't forge any tag, including ones like <system>, to break out of its fence.
  • Write-time trust isn't blind. Every stored item carries a trust level. Self-reported, unverified claims (an agent's own confidence/success/reward score) are ranking-discounted relative to system- or user-provided facts — an agent can't inflate its own memory's influence just by claiming high importance. A verify_memory() call lets a separate, more-trusted reviewer corroborate an item after the fact and restore full ranking weight; the original writer can never call it on its own write.
  • Contradiction flagging, not silent overwrite. A cheap antonym-predicate heuristic flags directly conflicting facts about the same subject (e.g. "Dan LIKES pizza" vs "Dan HATES pizza") for review instead of guessing which one is right — this is not general semantic contradiction detection (an open NLP problem), just a fast, honest, zero-model check for the specific opposite-predicate case.
  • Real embeddings, with a safety net. Defaults to sentence-transformers (all-MiniLM-L6-v2) when installed; falls back to a deterministic hash embedder otherwise. The vector index dimension is auto-detected from whichever embedder is actually active — mixing a database built with one embedder and a process running another raises a clear, actionable error at startup instead of silently corrupting or crashing mid-session.
  • Real ANN search, with a safety net. Uses hnswlib HNSW when installed; falls back to brute-force NumPy cosine search otherwise — and near-exhaustive queries route to brute-force even when HNSW is available, since HNSW is optimized for k ≪ n and is measurably slower than a vectorized brute-force pass once k approaches the corpus size.
  • Multi-tenant namespace isolation. Every memory item carries a namespace. On the Postgres backend this is enforced by Postgres Row-Level Security — not just an app-layer filter that a bug could skip. Consolidation, reflection, and graph export are all namespace-scoped too — none of them mix or leak data across tenants.
  • Two backends, one API. SQLite by default (zero external dependencies, single-process). Postgres + pgvector + RLS for real multi-writer, multi-tenant deployments — same MemoryEngine API either way. Optional Qdrant and Milvus vector-store connectors are also included for teams that want a dedicated vector database instead.

📦 Installation

One package, every feature included by default (real sentence-transformers embeddings, hnswlib ANN search, and Postgres/pgvector support are all installed out of the box — no extras to pick). Not on PyPI yet — install straight from GitHub for now:

pip install "agentic-memory @ git+https://github.com/Verace-Pvt-Ltd/agentic-memory.git"

Or clone and install locally:

git clone https://github.com/Verace-Pvt-Ltd/agentic-memory.git
cd agentic-memory
pip install -e .

Connect it to your AI coding tool

Claude Code (recommended — plugin marketplace, gets autonomous hooks too):

/plugin marketplace add Verace-Pvt-Ltd/agentic-memory
/plugin install agentic-memory@agentic-memory

Same two steps non-interactively (CI, setup scripts) via the CLI:

claude plugin marketplace add Verace-Pvt-Ltd/agentic-memory
claude plugin install agentic-memory@agentic-memory

This registers the MCP server through Claude Code's plugin marketplace system and auto-registers 9 autonomous hooks (hooks/hooks.json) that read and write memory on every turn without the agent needing to call an MCP tool explicitly — see Autonomous operation via hooks below. Verify with claude plugin details agentic-memory@agentic-memory, which should list Status: enabled and Hooks (9). The Python package still needs to be installed separately first (see Installation above) — the plugin distributes the MCP registration, not a bundled Python runtime.

Any other tool (Cursor, Antigravity, Codex CLI, Claude Desktop, or any other MCP-capable agent): see SETUP.md — copy one prompt into your agent's chat and it detects your tool and configures itself, including autonomous hooks where that tool supports them.

<details> <summary>Manual installation per tool (if you'd rather not use the plugin marketplace or SETUP.md prompt)</summary>

Claude Code (manual, no plugin system — MCP tools only, no autonomous hooks):

claude mcp add agentic-memory -- agentic-memory --transport stdio

Any other MCP client (Claude Desktop, Cursor, Antigravity, Codex CLI — MCP tools only, no autonomous hooks unless configured per SETUP.md):

# Auto-install into Claude Desktop's config
agentic-memory --setup-claude

# Print copy-paste config snippets for Claude Desktop, Cursor, Antigravity, and Codex CLI
agentic-memory --print-config

</details>

MCP (Model Context Protocol) is a shared standard across all of these — the same server works with any of them via:

{
  "mcpServers": {
    "agentic-memory": {
      "command": "agentic-memory",
      "args": ["--transport", "stdio"]
    }
  }
}

🪝 Autonomous operation via hooks

MCP tools require the agent to decide to call them. Hooks make memory read/write happen automatically, tied to the host tool's own lifecycle events (a new session starting, a prompt being submitted, a tool call succeeding or failing, the session stopping) — no explicit tool call needed. Four tools have a real hook/lifecycle system this project integrates with, each adapter living in its own module (memory/hooks.py, memory/hooks_antigravity.py, memory/hooks_cursor.py, memory/hooks_codex.py) with a matching config template under hooks/. Confidence differs per platform — verified against real installed binaries where one was available in this environment, doc-derived only where it wasn't:

Tool Events wired Confidence
Claude Code (plugin marketplace) SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PostToolUseFailure, Stop, TaskCompleted, PreCompact, SessionEnd Confirmed working end-to-end — verified via claude plugin details, which reports Status: enabled and Hooks (9) against a real installed instance.
Antigravity (agy) PreToolUse, PostToolUse, PreInvocation, Stop Confirmed to execute — a real tool-triggering prompt through a live agy install produced the hook's own stderr output (model load) in agy's logs, with no error. The resulting database write location wasn't independently confirmable from outside agy's process (possible subprocess sandboxing), so treat as working-but-not-fully-proven rather than broken.
Cursor (cursor-agent / Cursor IDE) sessionStart, beforeSubmitPrompt, beforeShellExecution, afterShellExecution, beforeMCPExecution, afterMCPExecution, afterFileEdit, afterAgentResponse, stop, sessionEnd Schema confirmed valid against Cursor's own docs; not confirmed to firecursor-agent requires an interactive login this environment didn't have. A community report also states several of these (sessionStart, beforeSubmitPrompt, stop, afterAgentResponse) are documented but don't currently execute in Cursor CLI specifically, only in the Cursor IDE — CLI users may see partial coverage until this is independently confirmed.
Codex CLI SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, PreCompact, SessionEnd Doc-derived only — no codex binary was available in this environment to verify against, so neither the schema nor the firing behavior has been live-tested.

Claude Desktop and any other generic MCP client have no hook/lifecycle system to integrate with — they get the 16 MCP tools only, called explicitly by the agent.

See SETUP.md for the exact install steps per platform, including where each hooks/*.json template needs to be copied.


🐘 Optional: Postgres / Supabase backend

For a real deployment with concurrent multi-process writers and enforced multi-tenant isolation, run Agentic Memory against Postgres + pgvector instead of SQLite. Self-hosted via Docker, no cloud account required:

docker compose up -d          # starts Postgres + pgvector (bare, unconfigured)
python -m memory.backends.postgres --migrate --dsn postgresql://postgres:postgrespassword@localhost:5433/memory

The migration step auto-detects the correct vector column dimension from whichever embedder is active in your Python environment (via get_embedding_dim()) and generates a secure app-role password if you don't supply one — nothing about the schema is hand-edited or hardcoded.

from memory.backends.postgres import PostgresBackend
from memory.engine import MemoryEngine

backend = PostgresBackend(dsn="postgresql://postgres:postgrespassword@localhost:5433/memory")
engine = MemoryEngine(backend=backend)

Row-Level Security policies enforce namespace isolation at the database engine level — a query for namespace="tenant_a" genuinely cannot see tenant_b's rows, even if application code has a bug.

Known limitations of the self-hosted Docker setup: no automated backups/point-in-time recovery, no high-availability/failover (single-container Postgres), and no encryption-at-rest beyond whatever the underlying disk provides — all buildable, none included out of the box today.


🔌 MCP Tools

Tool Purpose
sensory_ingest Ingest a real-time event into sensory memory
working_memory_update Add a turn to the active session's working memory
episodic_record Log a task trajectory; pass episode_id from an earlier call to update it instead of creating a duplicate
semantic_upsert Add/revise a subject-predicate-object fact (flags antonym contradictions)
long_term_store Store a durable preference or fact (Truth Maintenance on update)
procedural_register Register a reusable skill/action recipe (upserts by name — won't duplicate)
unified_query Fused, ranked, injection-safe context across all layers; optional top_k cap
query_as_of Point-in-time retrieval using bitemporal fields
get_belief_history Full revision history for a long-term memory key
get_semantic_belief_history Full revision history for a semantic fact
verify_memory Mark a fact/episode/skill as corroborated by a trusted reviewer — never by its own writer
forget GDPR-style hard delete (distinct from non-destructive supersede)
evict Namespace-scoped capacity/decay-based pruning
reflect Heuristic pattern synthesis over recent episodes/facts, namespace-scoped, deduplicated
graph_export_dot Export the semantic knowledge graph as Graphviz DOT, namespace-scoped
trigger_consolidation Run the sensory→working→episodic→semantic→long-term promotion cycle, namespace-scoped
inspect_memory_health Per-layer counts and operational metrics

Resources: memory://sensory/stream, memory://working/active, memory://semantic/graph.dot, memory://longterm/user. Prompt: synthesize_context.


🐍 Python SDK Quickstart

from memory import MemoryEngine

engine = MemoryEngine(db_path="memory.db")  # SQLite by default

engine.sensory_ingest("User clicked urgent alert", source="ui_event")
engine.working_update("user", "Can you deploy the payments service to prod?")
engine.working_update("assistant", "Running the blue-green deploy pipeline now.")

engine.episodic_record(
    title="Payments deploy",
    goal="Deploy payments service to prod",
    context="prod cluster",
    steps=[{"action": "run_pipeline", "input": {}, "output": {"status": "ok"}, "success": True}],
    outcome="success",
)

engine.semantic_add("User", "PREFERS", "blue-green deploys", confidence=0.9)
engine.long_term_store(
    "user_preference", "deploy_strategy", "blue-green",
    summary="User always wants blue-green deploys for prod",
    importance=0.9, is_pinned=True,
)

result = engine.query("deploy payments service to production")
print(result.synthesized_prompt_context)   # one injection-safe, ranked context block

stats = engine.consolidate()   # promote sensory -> working -> episodic -> semantic -> long-term

Every write accepts namespace= (default "default") and trust= (default TrustLevel.USER) for multi-tenant scoping and provenance tracking.


🧪 Testing

python3 -m pytest tests/ -v

98 tests covering persistence across restart, non-destructive belief revision, prompt-injection fencing (including non-<memory> tag names), namespace isolation across every subsystem (query, consolidation, reflection, DOT export, belief history), trust-weighted ranking and the verification mechanism, contradiction flagging, ANN index correctness (with and without hnswlib installed), embedding-dimension mismatch fail-fast behavior, eviction, Postgres dialect translation logic, and the Claude Code / Antigravity / Cursor / Codex CLI hook adapters. The Postgres backend has been verified against a real running instance (writes, reads, RLS enforcement, forget, evict) — not just reviewed statically.


⚠️ Known limitations

  • No published benchmark comparison (LoCoMo, LongMemEval, or similar) against Mem0, Zep/Graphiti, or MemGPT/Letta exists yet — retrieval quality claims should be treated as unvalidated against other systems until that exists. Internal, judge-free retrieval measurements against the MemFail benchmark (arXiv:2605.26667) are available in benchmarks/.
  • reflect() and episodic→semantic extraction (trigger_consolidation) use real LLM synthesis when called live through an MCP client that supports MCP sampling — the server asks the connected client's own model to synthesize insights / extract triples (ctx.sample(...) in mcp_server.py), so no separate API key or subscription is needed. This only works for live tool calls, since sampling requires an active client connection: headless paths (autonomous hooks, the background consolidation loop) have no live client to sample from and fall back to HeuristicReflector/HeuristicExtractor (template sentences / regex patterns) — real coverage, but not LLM-quality synthesis. If a sampling call fails or the connected client doesn't support it, the same heuristic fallback applies automatically, so reflect()/trigger_consolidation() never produce nothing. LLMReflector/LLMExtractor/StructuredPromptExtractor (in consolidator.py and utils.py) remain available as a separate, explicitly-opt-in path for anyone who wants headless LLM-backed extraction/reflection backed by their own Callable[[str], str] (e.g. a direct API call) — not wired in by default.
  • Contradiction detection only catches the specific antonym-predicate-on-same-subject case (Tier 1). It does not detect general semantic contradictions between differently-worded facts — that remains an open problem no memory system solves generically without an expensive, unreliable LLM pass at write time.
  • Postgres ANN search currently loads embeddings into an in-process index rather than querying pgvector's native index directly — works well at moderate scale, doesn't yet solve the "dataset too large for one process's memory" case that's part of the reason to use Postgres at all.
  • Qdrant/Milvus connectors are real (genuine client calls, no fallback stub) but have only been exercised in local/embedded mode (:memory: Qdrant, milvus-lite) — not against a remote/distributed cluster.

🤝 Contributing

Issues and pull requests are welcome. See CONTRIBUTING.md for guidelines.

📜 License

MIT License — see LICENSE. © Verace Pvt. Ltd.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选