The Problem

AI agents that need up‑to‑date contextual memory must continuously ingest new facts while preserving historic state. Traditional RAG pipelines rebuild an index on every change, which is costly and loses temporal nuance. Developers need a library that can incrementally mutate a knowledge graph, expose time‑aware queries, and stay runnable inside containerised services.

What This Does

graphiti_core/ implements the graph model, drivers for Neo4j/FalkorDB/Neptune, and LLM client adapters. The driver entry point lives in graphiti_core/driver/driver.py, exposing run, __aenter__, and execute_write. High‑level orchestration is in graphiti_core/graphiti.py (initialisation, telemetry, provider selection). Example scripts such as examples/azure-openai/azure_openai_neo4j.py and examples/quickstart/quickstart_falkordb.py demonstrate end‑to‑end ingestion and query flows. A separate MCP server (mcp_server/main.py) wraps the core as a HTTP service, while server/graph_service/main.py provides a minimal GraphQL API.

How It Is Wired

Execution can start from three places:

  • MCP server – mcp_server/main.py creates a Graphiti instance, calls initialize_graphiti, then runs lifespan (see server/graph_service/main.py line 12) which reaches 39 functions.
  • Standalone example – examples/azure-openai/azure_openai_neo4j.py runs main (line 68) and traverses 371 functions, ultimately invoking execute_query → database driver.
  • Direct library use – importing graphiti_core/graphiti.py and calling Graphiti() executes build_indices_and_constraints → execute_query.

All routes converge on the query executor (graphiti_core/driver/query_executor.py) and the core node/edge models (graphiti_core/nodes.py, graphiti_core/edges.py). The call graph shows:

  • execute_query is invoked 48 × from delete, 47 × from save, and 45 × from various getter methods.
  • EntityNode is referenced from 67 distinct callers, making it the widest‑impact symbol.
  • Graphiti itself is called from 33 places, including the MCP server and example scripts.

Database interaction occurs in graphiti_core/driver/driver.py → driver‑specific execute_write → the underlying client (self.client.execute). LLM calls are routed through graphiti_core/llm_client/*_client.py, e.g., anthropic_client.py's _resolve_max_tokens. File I/O appears only in the cache (graphiti_core/llm_client/cache.py) and a few example helpers.

Circular imports involve graphiti_core/nodes.py, graphiti_core/driver/driver.py, and graphiti_core/edges.py (21 high‑risk cycles). The hub module graphiti_core/nodes.py is imported by 70 other modules, so any change there has a large blast radius.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/graphiti
cd graphiti

# Build the container (Dockerfile present)
docker build -t graphiti:latest .

# Run the MCP server (environment variables defined in .env.example)
docker run -p 8000:8000 --env-file .env.example graphiti:latest \
    python -m mcp_server.main

For a quick local test without Docker, install the core with UV (pinning required by pyproject.toml):

uv pip install -e .
python examples/quickstart/quickstart_falkordb.py

The examples expect a running Neo4j/FalkorDB instance; connection strings are read from the .env.example files in each example folder.

Real‑World Use

A customer building a conversational sales assistant can run the MCP server alongside their product catalog DB. Each new chat turn is sent to /ingest (router in server/graph_service/routers/ingest.py), which creates EntityNode and EntityEdge objects, stores them via the Neo4j driver, and immediately makes them searchable through /search. Temporal queries (e.g., “what did the user say last week?”) are answered without re‑indexing the whole graph.

Code Health & Issues

  • Critical – Privileged PR checkout – .github/workflows/release-server-container.yml checks out PR code with repository secrets.
  • Critical – Secrets in PR‑triggered workflow – same file exposes DOCKERHUB_USERNAME/TOKEN.
  • High – Pin third‑party actions – actions referenced by tag (e.g., astral-sh/setup-uv@v3).
  • Medium – Base image not pinned – Dockerfile uses python:3.12-slim without digest.
  • Medium – No dependency‑vulnerability scan – CI lacks a dependency-review-action.
  • Medium – Large binary in repo – tests/evals/data/longmemeval_oracle.json (14.7 MiB).
  • Low – Missing job timeouts – .github/workflows/codeql.yml lacks timeout-minutes.

Measured static analysis also uncovered:

  • Import cycle (high) – graphiti_core/nodes.py, driver/driver.py, edges.py.
  • Deep nesting (high) – up to 7‑level indentation in nodes.py.
  • Oversized file (high) – nodes.py > 900 lines.
  • Hub module (high) – nodes.py imported by 70 modules.
  • Broad exception handling (medium) – generic except: in graphiti.py.
  • Duplicated code blocks (high) – identical 6‑line snippets across multiple examples.

The Bottom Line

Graphiti supplies a concrete Python stack for real‑time, temporally aware knowledge graphs, with ready‑made drivers and an MCP server. The code base is functional but suffers from high coupling (import cycles, hub modules) and several security‑related CI misconfigurations that must be fixed before production use. Teams comfortable with Python, Docker, and Neo4j‑style graphs will find the library usable after addressing the highlighted health concerns.