Skip to main content
Glama
river-ai-lab

Graph Memory MCP

by river-ai-lab

Agent memory turns into noise: duplicate facts, contradictions served as truth, stale decisions that look current, bloated context, and every session starts from scratch. Teams end up with a pile of unstructured notes nobody trusts.

Graph Memory MCP solves this:

  • Stays clean — near-duplicate writes refused on insert; mark facts outdated; CONTRADICTS edges surfaced in search; TTL for temporary facts

  • Exact agent text — the text in the graph is what the agent wrote; no extraction model splits, rewrites, or drops it

  • Physical isolation — one owner_id = one graph (FalkorDB) or one database (ArcadeDB); no query-time filtering

  • Free, predictable writes — no LLM calls on the server; writes are fast, cost-free, and work offline

  • Compact recall — search(..., compact=true) returns snippets under a token budget with suggested next steps

Quick start: docker compose up -d && uv run graph-memory-mcp — ready at http://127.0.0.1:8000/mcp

Quickstart · Comparison · Agent policies · Features


Quickstart (5 minutes)

  1. Start the databases. FalkorDB is the default backend:

docker compose up -d
  1. Install and start the server:

uv sync
uv run graph-memory-mcp --host 127.0.0.1 --port 8000
  1. Configure your MCP client. For Claude Desktop or Cursor, add this to your MCP servers config (see examples/mcp_servers_config.json):

{
  "mcpServers": {
    "graph-memory-mcp": {
      "transport": "streamable_http",
      "url": "http://127.0.0.1:8000/mcp"
    }
  }
}
  1. Try a smoke test. The server is now running at http://127.0.0.1:8000/mcp:

uv run python examples/http_client_usage.py

See Configuration and Running the databases for environment setup and backend options.

Related MCP server: Graph-Mem MCP

What it provides

  • Fact storage with embeddings (semantic search; hybrid rank: cosine + identifier match + recency)

  • get_brief — project anchor and recent durable facts, separate from search

  • Entity and triplet graph (subject–predicate–object)

  • Context subgraph (get_context) and paths (get_trace)

  • recall_context — one-call search and expand on small graphs

  • Fact versioning and soft-deletion. Facts with ttl_days stay out of default search until include_ttl=true

  • Fact auto-linking — auto_link=true on a Fact adds MENTIONS to similar Entity nodes (default is false)

  • Near-duplicate writes refused before insert (memory_duplicate); a different fact uses check_duplicates=false

  • Multi-tenant isolation via owner_id

  • Background jobs (deduplication, archival)

  • MCP-native API (FastMCP)

Backed by FalkorDB by default. GRAPH_BACKEND=arcadedb uses ArcadeDB with the same tools.

Where it fits

Mem0 remembers facts. Graph Memory keeps them current.

This server is the store. The agent writes the fact, the owner_id, the TTL, and the edge. Search returns what was stored. Embeddings are the only model call inside the server.

  • Real graph you can traverse, in open source. Not a hidden ranking signal. Mem0 OSS has no graph. The Platform graph only changes search order. Here the agent walks the edges.

  • Outdated is marked. Mem0 keeps both facts and ranks the newer one higher. mark_outdated, CONTRADICTS, and version snapshots say what is current.

  • Near-duplicates are refused at write, without an LLM. Mem0 skips exact copies. Near-copies are stored.

Each owner_id is its own graph. Mem0 keeps every user_id in one store.

Graphiti (the library behind Zep) ingests episodes and keeps a bi-temporal graph: a new fact invalidates the old one, and the old one stays queryable by time.

Case

Graph Memory MCP

Mem0

Graphiti

The graph

Edges are readable (get_context, get_trace)

OSS: no graph. Platform: ranking only, relations not returned

Temporal graph you can query

A decision changed

mark_outdated, CONTRADICTS, or a version snapshot

Add-only. Both stay; the newer one ranks higher. No outdated mark.

The old edge is invalidated; history stays

A near-duplicate write

Refused at write (memory_duplicate). Embeddings only

Exact text skipped by hash. Near-copies stored

New edges

The agent already has the sentence

create_node stores that sentence

An extraction model may split, rewrite, or drop it

An episode pipeline turns it into entities and edges

"Remember this chat" and nobody chose the facts

The server does not read a transcript

add extracts memories (default; skip with infer=False)

add extracts a temporal graph

A debug note that should disappear

ttl_days; default search hides it

expiration_date. show_expired or get-by-id still returns it

Validity windows, not a debug TTL

Two agents, one project

Same owner_id, its own graph

user_id, agent_id, run_id, app_id in one store

group_id

No extraction model

Writes do not call an LLM

infer=False skips the LLM; embeddings are still computed

Several LLM calls per episode

docs/comparison.md.

Agent policies

Any LLM agent that reads or writes Graph Memory — single-agent or multi-agent — should load the memory ritual from client rules / AGENTS.md and keep docs/memory_policies_for_LLM.md (or the shorter docs/memory_policy_cheatsheet.md) in context at the start of each session. That defines what to store, owner_id rules, and how to link facts; without it, memory tends to get noisy or mis-scoped. The same full policy is optionally exposed as MCP resource graph-memory://agent-policies (clients rarely auto-fetch it — prefer rules).

Install

uv sync

uv sync installs runtime deps plus the dev group (pre-commit, pytest, …).

PyTorch is installed from the CPU-only index by default (no NVIDIA/CUDA wheels on Linux). Configured in pyproject.toml via [tool.uv.sources].

TIP

Check theexamples directory for code snippets demonstrating various usage patterns (embedded, HTTP, and MCP configuration).

Run (Development)

HTTP server

graph-memory-mcp --host 127.0.0.1 --port 8000

Streamable HTTP MCP is at http://127.0.0.1:8000/mcp. Tools are MCP calls, not REST paths under /mcp.

Server profiles

Three processes, one handler layer. Tool names match. A client picks one and stays on it.

Start

Writes

Default

graph-memory-mcp

Nested source

Simple

graph-memory-mcp --simple

Flat provenance (ref, provenance_type, …). upsert_node requires ref

Extended

graph-memory-mcp --extended

Same as default, plus description, shared_with_ids, collection_id, and node types Collection, User, Project

graph-memory-mcp --simple --host 127.0.0.1 --port 8000
graph-memory-mcp --extended --host 127.0.0.1 --port 8000

See Server profiles.

Graph Explorer (local GUI)

Read-only web UI to inspect nodes, semantic search, similar facts, and graph context. Proxies read-only MCP tools to a separately running Graph Memory server.

# Terminal 1 — MCP server (FalkorDB must be running; uses .env)
uv run graph-memory-mcp --host 127.0.0.1 --port 8000

# Terminal 2 — Explorer GUI only
uv run graph-memory-explorer --host 127.0.0.1 --port 8088
# optional: --mcp-url http://127.0.0.1:8000/mcp  (or GRAPH_MEMORY_MCP_URL)

Open http://127.0.0.1:8088 — enter owner_id and a node_id, run search, expand neighbors with + on hover or +10 neighbors in the detail panel.

Configuration

Settings are loaded from environment variables and optional .env file.

You can start from env.example (copy it to .env).

Key defaults live in graph_memory_mcp/config.py within the MCPServerConfig class, including:

  • RELATION_POLICY_ENFORCE — off | warn (default) | enforce

  • RELATION_ALLOWED_TYPES — comma-separated allowlist for new edges

  • OWNER_SCOPE — client (default) | header. See Owner isolation.

  • JOBS_ENABLED — off by default. On runs archive and dedup. JOBS_OWNER_IDS limits them to those owners; empty means every owner. See background jobs.

  • Agent link guidance: docs/memory_policies_for_LLM.md

Running the databases

Docker Compose starts both databases. It does not start the MCP server. The code default for FALKORDB_PASSWORD is empty, so copy env.example before connecting.

cp env.example .env   # first time only
docker compose up -d

Port

Credentials in env.example

FalkorDB

6379, UI at http://localhost:3000

password falkordb123

ArcadeDB

2480

user root, password playwithdata

FalkorDB is the default backend and is required for the default test run. ./scripts/falkordb-up.sh starts only FalkorDB. ArcadeDB tests: uv run pytest -m arcade.

With Password Authentication

docker run -p 6379:6379 -p 3000:3000 -it --rm \
  -v ./data:/var/lib/falkordb/data \
  -e REDIS_ARGS="--requirepass falkordb123" \
  falkordb/falkordb

Note: Replace falkordb123 with your desired password and make sure to set the same password in your .env file:

FALKORDB_PASSWORD=falkordb123

Without Password (Development Only)

docker run -p 6379:6379 -p 3000:3000 -it --rm \
  -v ./data:/var/lib/falkordb/data \
  falkordb/falkordb

After starting FalkorDB, you can access the web interface at http://localhost:3000.

Vector Indexes

The server uses two vector indexes (Fact and Entity):

Index

Used by

Fact

search, find_similar

Entity

Fact auto_link → MENTIONS

Creation (pick one):

  • Automatic — indexes are created on first search, find_similar, or Fact auto_link if missing.

  • Startup — AUTO_CREATE_INDEXES=true in .env.

  • Admin — POST /admin/ensure-indexes (or MCP ensure_vector_indexes when MCP_EXPOSE_ADMIN_TOOLS=true).

FalkorDB keeps index data in sync when nodes change; you only need to recreate index definitions after changing embedding model dimension.

WARNING

Changing EMBEDDING_MODEL invalidates the stored corpus. Old node embeddings were produced by the old model — new queries will not match them meaningfully. The full procedure is: (1) switch the model, (2) recreate vector index definitions if the dimension changed, (3) re-embed every node (currently manual: iterate nodes and update_node with the same text, or export/import with regenerate_embeddings=true). The same applies to changing prompt/prefix conventions of the same model.

Embedding prefixes

Some models are trained with prompt prefixes. The default intfloat/multilingual-e5-base expects "query: " for search queries and "passage: " for stored texts. The code default for both prefixes is empty; env.example sets them for e5. Enabling prefixes on an existing corpus counts as a model change — re-embed the corpus (see warning above).

Persistence & Backups

docker-compose.yml enables AOF persistence (--appendonly yes --appendfsync everysec) — a container crash loses at most ~1 second of writes. For point-in-time backups:

./scripts/backup.sh            # BGSAVE + copy dump.rdb to ./backups (keeps last 14)
# cron example (hourly): 0 * * * * cd /path/to/repo && ./scripts/backup.sh

Logical per-owner backups (portable across instances/models): GET /admin/export/{owner_id} — supports ?limit=&offset=&section=nodes|relations for large owners; restore with POST /admin/import.

Multi-Agent Usage

Use owner_id to isolate or share knowledge between agents. For example:

  • Shared team memory: Both your code-generation agent and your debugging agent use owner_id="team_platform". One agent stores "Production Redis is at redis.internal"; the other searches and finds it.

  • Isolated per-agent memory: Your agent uses owner_id="agent_codegen" for implementation notes; another uses owner_id="agent_docs" for documentation drafts. Neither sees the other's memory.

Values must be alphanumeric plus -, _, and @ (see docs/memory_policies_for_LLM.md).

Owner Isolation

Isolation is physical on both backends. On FalkorDB, every owner_id lives in its own graph ({FALKORDB_GRAPH}_{owner_id}) with its own vector indexes. On ArcadeDB, every owner_id lives in its own database ({ARCADE_DATABASE}_{owner_id}) with its own vertices, edges, and HNSW indexes. One owner cannot see another's data.

Who picks that owner is OWNER_SCOPE (default client):

OWNER_SCOPE=client

OWNER_SCOPE=header

When

Trusted network; clients pass the owner directly

A reverse proxy or other middleware in front of the server sets the owner per request

Owner

Tool argument owner_id. Empty falls back to DEFAULT_OWNER_ID (usually "default").

X-Owner-Id on the HTTP request. The tool argument is ignored.

Missing owner

Server default

Call is rejected. It does not fall back to DEFAULT_OWNER_ID.

Tool names and arguments stay the same in both modes. Agents should still pass owner_id explicitly: in client that value is the graph; in header the HTTP header wins, so a client cannot name someone else's graph.

See docs/memory_policies_for_LLM.md and docs/memory_faq.md for operational guidance.

ArcadeDB

Optional second graph backend. Leave GRAPH_BACKEND unset (or falkordb) to keep FalkorDB. Set GRAPH_BACKEND=arcadedb and the ARCADE_* variables in .env. Each owner_id gets its own database, {ARCADE_DATABASE}_{owner_id}, with its own vertices, edges, and HNSW indexes. The embedding is a property on the vertex. Search inside that database uses vector.neighbors.

Development

The default test run requires FalkorDB (see Running the databases). ArcadeDB tests are marked arcade and use the Compose server on port 2480:

./scripts/test.sh
# or: docker compose up -d && uv run pytest -q
# ArcadeDB: uv run pytest -m arcade

Pre-commit hooks

Hooks are not global — run them via the project venv (dev group installed by uv sync):

uv run pre-commit run --all-files
uv run pre-commit install   # optional: git hooks

Smoke Test (Quick Verification)

The server uses Streamable HTTP MCP at http://127.0.0.1:8000/mcp. Tools are invoked with MCP call_tool — there is no REST API at /mcp/tools/....

Terminal 1 — start the server (FalkorDB must be running):

graph-memory-mcp --host 127.0.0.1 --port 8000

Terminal 2 — run the HTTP MCP client example:

uv run python examples/http_client_usage.py

That script calls health_check, create_node, and search over Streamable HTTP. See examples/ for embedded usage and MCP client configuration.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    MCP server that gives AI agents and teams persistent, shared memory using a knowledge graph with vector embeddings, automatic consolidation of related facts, and hybrid search.
    3
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    A universal MCP server providing persistent, structured memory through a knowledge graph with graph storage, semantic vector search, and multi-hop traversal for AI agents and IDEs.
    19 PyPI
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Knowledge-graph memory server for MCP-compatible AI tools, providing persistent, connected memory with typed relationships and auto-consolidation.
    54 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A local-first compiled knowledge graph MCP server that provides structured memory for AI agents with full-text search, vector embeddings, and timeline tracking.
    55 npm
    8
    MIT