graphiti Documentation

Build Real-Time Knowledge Graphs for AI Agents

32,143 stars Python Python 15 files ยท ~26,042 tokens #agents#graph#llms#rag
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy graphiti on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name graphiti -p 6379:6379 --restart always zepai/knowledge-graph-mcp:latest
Configured Services & Ports
โš™๏ธ graphiti-falkordb
image: zepai/knowledge-graph-mcp:latest
๐Ÿ”Œ Ports: 127.0.0.1:6379:6379, 127.0.0.1:3000:3000, 127.0.0.1:8000:8000
docker-compose.yml
yaml (docker-compose.yml)
services:
  graphiti-falkordb:
    image: zepai/knowledge-graph-mcp:latest
    build:
      context: ..
      dockerfile: docker/Dockerfile
      args:
        GRAPHITI_CORE_VERSION: ${GRAPHITI_CORE_VERSION:-0.29.1}
        MCP_SERVER_VERSION: ${MCP_SERVER_VERSION:-1.1.3}
        BUILD_DATE: ${BUILD_DATE:-}
        VCS_REF: ${VCS_REF:-}
    env_file:
      - path: ../.env
        required: false
    environment:
      # FalkorDB configuration
      - FALKORDB_PASSWORD=${FALKORDB_PASSWORD:-}
      - BROWSER=${BROWSER:-1}  # Enable FalkorDB Browser UI (set to 0 to disable)
      # MCP Server configuration
      - FALKORDB_URI=redis://localhost:6379
      - FALKORDB_DATABASE=${FALKORDB_DATABASE:-default_db}
      - GRAPHITI_GROUP_ID=${GRAPHITI_GROUP_ID:-main}
      - SEMAPHORE_LIMIT=${SEMAPHORE_LIMIT:-10}
      - CONFIG_PATH=/app/mcp/config/config.yaml
    volumes:
      - falkordb_data:/var/lib/falkordb/data
      - mcp_logs:/var/log/graphiti
    ports:
      - "127.0.0.1:6379:6379"  # FalkorDB/Redis
      - "127.0.0.1:3000:3000"  # FalkorDB web UI
      - "127.0.0.1:8000:8000"  # MCP server HTTP
    healthcheck:
      test: ["CMD", "redis-cli", "-p", "6379", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 15s

volumes:
  falkordb_data:
    driver: local
  mcp_logs:
    driver: local

Technical Documentation: getzep/graphiti

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`README.md`)

Graphiti

A Framework for Building Temporal Knowledge Graphs

[!NOTE]
We're Hiring! Build context graphs that power reliable, personalized, fast production AI agents.
Come build with us โ€” we're hiring Engineers and Developer Relations folks. View open roles.

โญ Help us reach more developers and grow the Graphiti community. Star this repo!

 

Graphiti is a framework for building and querying temporal context graphs for AI agents. Unlike static knowledge graphs,
Graphiti's context graphs track how facts change over time, maintain provenance to source data, and support both
prescribed and learned ontology โ€” making them purpose-built for agents operating on evolving, real-world data.

Unlike traditional retrieval-augmented generation (RAG) methods, Graphiti continuously integrates user interactions,
structured and unstructured enterprise data, and external information into a coherent, queryable graph. The framework
supports incremental data updates, efficient retrieval, and precise historical queries without requiring complete graph
recomputation, making it suitable for developing interactive, context-aware AI applications.

Use Graphiti to:

  • Build temporal knowledge graphs that evolve with every interaction โ€” tracking what's true now and what was true before.
  • Represent rich, structured context instead of flat document chunks or raw event streams.
  • Query across time, meaning, and relationships with hybrid retrieval (semantic + keyword + graph traversal).

 

 

What is a Context Graph?

A context graph is a temporal graph of entities, relationships, and facts โ€” like "Kendra loves Adidas shoes (as of
March 2026)."
Unlike traditional knowledge graphs, each fact in a context graph has a validity window: when it became
true, and when (if ever) it was superseded. Entities evolve over time with updated summaries. Everything traces back to
episodes โ€” the raw data that produced it.

What makes Graphiti unique is its ability to autonomously build context graphs from unstructured and structured data,
handling changing relationships while preserving full temporal history.

A context graph contains:

Component What it stores
Entities (nodes) People, products, policies, concepts โ€” with summaries that evolve over time
Facts / Relationships (edges) Triplets (Entity โ†’ Relationship โ†’ Entity) with temporal validity windows
Episodes (provenance) Raw data as ingested โ€” the ground truth stream. Every derived fact traces back here
Custom Types (ontology) Developer-defined entity and edge types via Pydantic models

Graphiti and Zep

Graphiti is an open-source Python framework for building and querying temporal context graphs. You supply the graph
database, LLM, and embedder, and you build the service around it: ingestion, tenancy, access control, and operations.

Zep is the unified context layer for enterprises. Zep brings data from across a business into
governed context graphs and serves that context to agents in production. Graphiti is the graph construction framework
inside Zep. Konig, Zep's graph database service, stores and
serves millions of context graphs with low-latency retrieval.

Teams use both to give agents memory. Neither is an agent memory product: Graphiti is a framework for building graphs,
and Zep unifies, governs, and serves an enterprise's context.

Read our paper: Zep: A Temporal Knowledge Graph Architecture.

Zep vs Graphiti

Aspect Zep Graphiti
What it is The unified context layer for enterprises An open-source framework for building temporal context graphs
Scope Unifies data from across an enterprise into governed context and serves it to agents Builds and queries graphs inside your own application
Context graphs Manages millions of context graphs with governance Builds and queries the graphs you define
Graph database Konig, Zep's graph database service, built for millions of context graphs with low-latency retrieval; no third-party graph database required Bring your own: Neo4j, FalkorDB, or Amazon Neptune
Users, threads, and ingestion Built-in users, threads, and ingestion for messages and business data Build your own
Retrieval & performance Pre-configured, production-ready retrieval with sub-200ms performance at scale Custom implementation required; performance depends on your setup
Developer tools Dashboard with graph visualization, debug logs, API logs; CLI; SDKs for Python, TypeScript, and Go Build your own tools
Enterprise features SLAs, support, security guarantees Self-managed
Deployment Fully managed or in your cloud (BYOC) Self-hosted only

When to choose which

Choose Zep if you want an enterprise's context unified, governed, and served to agents in production, without
building and operating that system yourself.

Choose Graphiti if you are building temporal context graphs into your own system and will operate the graph
database, retrieval, and surrounding service yourself.

Why Graphiti?

Traditional RAG approaches often rely on batch processing and static data summarization, making them inefficient for
frequently changing data. Graphiti addresses these challenges by providing:

  • Temporal Fact Management: Facts have validity windows. When information changes, old facts are
    invalidated โ€” not deleted. Query what's true now, or what was true at any point in time.
  • Episodes & Provenance: Every entity and relationship traces back to the episodes (raw data) that produced it.
    Full lineage from derived fact to source.
  • Prescribed & Learned Ontology: Define entity and edge types upfront via Pydantic models (prescribed), or let
    structure emerge from your data (learned). Start simple, evolve as patterns appear.
  • Incremental Graph Construction: New data integrates immediately without batch recomputation. The graph evolves
    in real-time as episodes are ingested.
  • Hybrid Retrieval: Combines semantic embeddings, keyword (BM25), and graph traversal for low-latency,
    high-precision queries without reliance on LLM summarization.
  • Scalability: Efficiently manages large datasets with parallel processing, pluggable graph backends, suitable
    for enterprise workloads.

Graphiti vs. GraphRAG

Aspect GraphRAG Graphiti
Primary Use Static document summarization Dynamic, evolving temporal knowledge graphs
Data Handling Batch-oriented processing Continuous, incremental updates
Knowledge Structure Entity clusters & community summaries Temporal context graph โ€” entities, facts with validity windows, episodes, communities
Retrieval Method Sequential LLM summarization Hybrid semantic, keyword, and graph-based search
Adaptability Low High
Temporal Handling Basic timestamp tracking Explicit bi-temporal tracking with automatic fact invalidation
Contradiction Handling LLM-driven summarization judgments Automatic fact invalidation with temporal history preserved
Query Latency Seconds to tens of seconds Typically sub-second latency
Custom Entity Types No Yes, customizable via Pydantic models
Scalability Moderate High, optimized for large datasets

Graphiti is specifically designed to address the challenges of dynamic and frequently updated datasets, making it
particularly suitable for applications requiring real-time interaction and precise historical queries.

Installation

Requirements:

  • Python 3.10 or higher
  • Neo4j 5.26 / FalkorDB 1.1.2 / Amazon Neptune Database Cluster or Neptune Analytics Graph + Amazon OpenSearch
    Serverless collection (serves as the full text search backend) / Kuzu 0.11.2 (deprecated, see below)
  • OpenAI API key (Graphiti defaults to OpenAI for LLM inference and embedding)

[!IMPORTANT]
Graphiti works best with LLM services that support Structured Output (such as OpenAI, Anthropic, and Gemini).
Using other services may result in incorrect output schemas and ingestion failures. This is particularly
problematic when using smaller models.

Optional:

  • Google Gemini, Anthropic, or Groq API key (for alternative LLM providers)

[!TIP]
The simplest way to install Neo4j is via Neo4j Desktop. It provides a user-friendly
interface to manage Neo4j instances and databases.
Alternatively, you can use FalkorDB on-premises via Docker and instantly start with the quickstart example:

text
docker run -p 6379:6379 -p 3000:3000 -it --rm falkordb/falkordb:latest
bash
pip install graphiti-core

or

bash
uv add graphiti-core

Installing with FalkorDB Support

If you plan to use FalkorDB as your graph database backend, install with the FalkorDB extra:

bash
pip install graphiti-core[falkordb]

# or with uv
uv add graphiti-core[falkordb]

# or embedded version (requires Python 3.12+)
pip install graphiti-core[falkordblite]
# or with uv
uv add graphiti-core[falkordblite]

Installing with Kuzu Support

[!WARNING]
Kuzu is deprecated and will be removed in a future release โ€” the upstream Kuzu project is no longer
maintained. New projects should use Neo4j or FalkorDB. The driver still ships for now but emits a
DeprecationWarning.

If you plan to use Kuzu as your graph database backend, install with the Kuzu extra:

bash
pip install graphiti-core[kuzu]

# or with uv
uv add graphiti-core[kuzu]

Installing with Amazon Neptune Support

If you plan to use Amazon Neptune as your graph database backend, install with the Amazon Neptune extra:

bash
pip install graphiti-core[neptune]

# or with uv
uv add graphiti-core[neptune]

You can also install optional LLM providers as extras:

bash
# Install with Anthropic support
pip install graphiti-core[anthropic]

# Install with Groq support
pip install graphiti-core[groq]

# Install with Google Gemini support
pip install graphiti-core[google-genai]

# Install with multiple providers
pip install graphiti-core[anthropic,groq,google-genai]

# Install with FalkorDB and LLM providers
pip install graphiti-core[falkordb,anthropic,google-genai]

# Install with Amazon Neptune
pip install graphiti-core[neptune]

Default to Low Concurrency; LLM Provider 429 Rate Limit Errors

Graphiti's ingestion pipelines are designed for high concurrency. By default, concurrency is set low to avoid LLM
Provider 429 Rate Limit Errors. If you find Graphiti slow, please increase concurrency as described below.

Concurrency controlled by the SEMAPHORE_LIMIT environment variable. By default, SEMAPHORE_LIMIT is set to 10
concurrent operations to help prevent 429 rate limit errors from your LLM provider. If you encounter such errors, try
lowering this value.

If your LLM provider allows higher throughput, you can increase SEMAPHORE_LIMIT to boost episode ingestion
performance.

Quick Start

[!IMPORTANT]
Graphiti defaults to using OpenAI for LLM inference and embedding. Ensure that an OPENAI_API_KEY is set in your
environment.
Support for Anthropic, Gemini, and Groq is available, too. Other LLM providers โ€” both hosted OpenAI-compatible APIs
(DeepSeek, Together, OpenRouter, โ€ฆ) and local servers (Ollama, vLLM, llama.cpp, LM Studio) โ€” may be used via their
OpenAI-compatible endpoints; see
Using Graphiti with OpenAI-compatible providers and local LLMs.

For a complete working example, see the Quickstart Example in the examples directory.
The quickstart demonstrates:

  1. Connecting to a Neo4j, Amazon Neptune, FalkorDB, or Kuzu database
  2. Initializing Graphiti indices and constraints
  3. Adding episodes to the graph (both text and structured JSON)
  4. Searching for relationships (edges) using hybrid search
  5. Reranking search results using graph distance
  6. Searching for nodes using predefined search recipes

The example is fully documented with clear explanations of each functionality and includes a comprehensive README with
setup instructions and next steps.

Running with Docker Compose

You can use Docker Compose to quickly start the required services:

  • Neo4j Docker:

    bash
    docker compose up

    This will start the Neo4j Docker service and related components.

  • FalkorDB Docker:

    bash
    docker compose --profile falkordb up

    This will start the FalkorDB Docker service and related components.

Reference MCP and REST servers

The mcp_server and server directories contain reference implementations of an MCP server and a REST server. These
servers show how to put Graphiti behind a protocol. These servers are not production deployments.

[!WARNING]
The reference servers have no authentication, no authorization, and no prompt-injection protection. These omissions
are intentional. Do not expose the reference servers to an untrusted network.

The reference servers have these limits:

  • The servers do not authenticate callers. Any caller can read, change, or delete data in any group_id.
  • The servers do not detect or block prompt injection. The servers send episode content and tool input to the
    configured LLM without a filter.
  • The example Docker Compose files use default database credentials.

Security reports about these limits are out of scope. Pull requests that add authentication, authorization, or
prompt-injection filters to the reference servers are also out of scope. For more information, see the
security policy scope.

For a production deployment, use one of these options:

  • Use the graphiti-core library in your own service. Your service must supply authentication, authorization, tenant
    isolation, and input controls.
  • Use Zep, the unified context layer for enterprises, which is built on Graphiti. Zep is
    available as a managed service or in your own cloud (BYOC). For a comparison, see Zep vs Graphiti.

MCP Server

The mcp_server directory contains a reference Model Context Protocol (MCP) server for Graphiti. This server
allows AI assistants to interact with Graphiti's context graph capabilities through the MCP protocol.

Key features of the MCP server include:

  • Episode management (add, retrieve, delete)
  • Entity management and relationship handling
  • Semantic and hybrid search capabilities
  • Group management for organizing related data
  • Graph maintenance operations

The MCP server can be deployed using Docker with Neo4j, making it easy to integrate Graphiti into your AI assistant
workflows.

For detailed setup instructions and usage examples, see the MCP server README.

REST Service

The server directory contains a reference REST service for the Graphiti API. The service uses FastAPI.

Please see the server README for more information.

Optional Environment Variables

In addition to the Neo4j and OpenAi-compatible credentials, Graphiti also has a few optional environment variables.
If you are using one of our supported models, such as Anthropic or Voyage models, the necessary environment variables
must be set.

Database Configuration

Database names are configured directly in the driver constructors:

  • Neo4j: Database name defaults to neo4j (hardcoded in Neo4jDriver)
  • FalkorDB: Database name defaults to default_db (hardcoded in FalkorDriver)

As of v0.17.0, if you need to customize your database configuration, you can instantiate a database driver and pass it
to the Graphiti constructor using the graph_driver parameter.

Neo4j with Custom Database Name

python
from graphiti_core import Graphiti
from graphiti_core.driver.neo4j_driver import Neo4jDriver

# Create a Neo4j driver with custom database name
driver = Neo4jDriver(
    uri="bolt://localhost:7687",
    user="neo4j",
    password="password",
    database="my_custom_database"  # Custom database name
)

# Pass the driver to Graphiti
graphiti = Graphiti(graph_driver=driver)

FalkorDB with Custom Database Name

python
from graphiti_core import Graphiti
from graphiti_core.driver.falkordb_driver import FalkorDriver

# Create a FalkorDB driver with custom database name
driver = FalkorDriver(
    host="localhost",
    port=6379,
    username="falkor_user",  # Optional
    password="falkor_password",  # Optional
    database="my_custom_graph"  # Custom database name
)

# Or use embedded FalkorDB Lite (requires Python 3.12+)
# from redislite.async_falkordb_client import AsyncFalkorDB
# falkordb_client = AsyncFalkorDB(dbfilename='/path/to/database.db')
# driver = FalkorDriver(falkor_db=falkordb_client)

# Pass the driver to Graphiti
graphiti = Graphiti(graph_driver=driver)

Kuzu

[!WARNING]
Kuzu is deprecated (upstream project unmaintained) and will be removed in a future release. Prefer Neo4j or
FalkorDB.

python
from graphiti_core import Graphiti
from graphiti_core.driver.kuzu_driver import KuzuDriver

# Create a Kuzu driver
driver = KuzuDriver(db="/tmp/graphiti.kuzu")

# Pass the driver to Graphiti
graphiti = Graphiti(graph_driver=driver)

Amazon Neptune

python
from graphiti_core import Graphiti
from graphiti_core.driver.neptune_driver import NeptuneDriver

# Create a Neptune driver
driver = NeptuneDriver(
    host='<NEPTUNE_ENDPOINT>',
    aoss_host='<AMAZON_OPENSEARCH_SERVERLESS_HOST>',
    port=8182,      # Optional, defaults to 8182
    aoss_port=443,  # Optional, defaults to 443
)

# Pass the driver to Graphiti
graphiti = Graphiti(graph_driver=driver)

Contributing a new graph backend? See Adding a graph driver.

Using Graphiti with Azure OpenAI

Graphiti supports Azure OpenAI for both LLM inference and embeddings using Azure's OpenAI v1 API compatibility layer.

Quick Start

python
from openai import AsyncOpenAI
from graphiti_core import Graphiti
from graphiti_core.llm_client.azure_openai_client import AzureOpenAILLMClient
from graphiti_core.llm_client.config import LLMConfig
from graphiti_core.embedder.azure_openai import AzureOpenAIEmbedderClient

# Initialize Azure OpenAI client using the standard OpenAI client
# with Azure's v1 API endpoint
azure_client = AsyncOpenAI(
    base_url="https://your-resource-name.openai.azure.com/openai/v1/",
    api_key="your-api-key",
)

# Create LLM and Embedder clients
llm_client = AzureOpenAILLMClient(
    azure_client=azure_client,
    config=LLMConfig(model="gpt-5-mini", small_model="gpt-5-mini")  # Your Azure deployment name
)
embedder_client = AzureOpenAIEmbedderClient(
    azure_client=azure_client,
    model="text-embedding-3-small"  # Your Azure embedding deployment name
)

# Initialize Graphiti with Azure OpenAI clients
graphiti = Graphiti(
    "bolt://localhost:7687",
    "neo4j",
    "password",
    llm_client=llm_client,
    embedder=embedder_client,
)

# Now you can use Graphiti with Azure OpenAI

Key Points:

  • Use the standard AsyncOpenAI client with Azure's v1 API endpoint format:
    https://your-resource-name.openai.azure.com/openai/v1/
  • The deployment names (e.g., gpt-5-mini, text-embedding-3-small) should match your Azure OpenAI deployment names
  • See examples/azure-openai/ for a complete working example

Make sure to replace the placeholder values with your actual Azure OpenAI credentials and deployment names.

Using Graphiti with Google Gemini

Graphiti supports Google's Gemini models for LLM inference, embeddings, and cross-encoding/reranking. To use Gemini,
you'll need to configure the LLM client, embedder, and the cross-encoder with your Google API key.

Install Graphiti:

bash
uv add "graphiti-core[google-genai]"

# or

pip install "graphiti-core[google-genai]"
python
from graphiti_core import Graphiti
from graphiti_core.llm_client.gemini_client import GeminiClient, LLMConfig
from graphiti_core.embedder.gemini import GeminiEmbedder, GeminiEmbedderConfig
from graphiti_core.cross_encoder.gemini_reranker_client import GeminiRerankerClient

# Google API key configuration
api_key = "<your-google-api-key>"

# Initialize Graphiti with Gemini clients
graphiti = Graphiti(
    "bolt://localhost:7687",
    "neo4j",
    "password",
    llm_client=GeminiClient(
        config=LLMConfig(
            api_key=api_key,
            model="gemini-2.0-flash"
        )
    ),
    embedder=GeminiEmbedder(
        config=GeminiEmbedderConfig(
            api_key=api_key,
            embedding_model="embedding-001"
        )
    ),
    cross_encoder=GeminiRerankerClient(
        config=LLMConfig(
            api_key=api_key,
            model="gemini-2.5-flash-lite"
        )
    )
)

# Now you can use Graphiti with Google Gemini for all components

The Gemini reranker uses the gemini-2.5-flash-lite model by default, which is optimized for
cost-effective and low-latency classification tasks. It uses the same boolean classification approach as the OpenAI
reranker, leveraging Gemini's log probabilities feature to rank passage relevance.

Using Graphiti with OpenAI-compatible providers and local LLMs

Graphiti can use any OpenAI-compatible /v1 endpoint for LLM inference via OpenAIGenericClient โ€” both hosted
providers
(DeepSeek, Together, OpenRouter, Fireworks, etc.) and local servers (Ollama, vLLM, llama.cpp, LM
Studio). Local servers are ideal for privacy-focused applications or avoiding API costs. The example below uses Ollama;
for any other provider, point base_url at its endpoint and set the appropriate api_key and model.

Note: Use OpenAIGenericClient (not OpenAIClient) for these endpoints. It is optimized for local models with a
higher default max token limit (16K vs 8K) and handles structured outputs across compatible providers.

Install the models:

bash
ollama pull deepseek-r1:7b # LLM
ollama pull nomic-embed-text # embeddings
python
from graphiti_core import Graphiti
from graphiti_core.llm_client.config import LLMConfig
from graphiti_core.llm_client.openai_generic_client import OpenAIGenericClient
from graphiti_core.embedder.openai import OpenAIEmbedder, OpenAIEmbedderConfig
from graphiti_core.cross_encoder.openai_reranker_client import OpenAIRerankerClient

# Configure Ollama LLM client
llm_config = LLMConfig(
    api_key="ollama",  # Ollama doesn't require a real API key, but some placeholder is needed
    model="deepseek-r1:7b",
    small_model="deepseek-r1:7b",
    base_url="http://localhost:11434/v1",  # Ollama's OpenAI-compatible endpoint
)

llm_client = OpenAIGenericClient(config=llm_config)

# Initialize Graphiti with Ollama clients
graphiti = Graphiti(
    "bolt://localhost:7687",
    "neo4j",
    "password",
    llm_client=llm_client,
    embedder=OpenAIEmbedder(
        config=OpenAIEmbedderConfig(
            api_key="ollama",  # Placeholder API key
            embedding_model="nomic-embed-text",
            embedding_dim=768,
            base_url="http://localhost:11434/v1",
        )
    ),
    cross_encoder=OpenAIRerankerClient(client=llm_client, config=llm_config),
)

# Now you can use Graphiti with local Ollama models

Ensure Ollama is running (ollama serve) and that you have pulled the models you want to use.

Structured output and small models

Graphiti depends on structured (JSON) output for entity/edge extraction and deduplication, and works best with models
and providers that reliably honor it (OpenAI, Anthropic, Gemini). Reliability varies across OpenAI-compatible providers and
especially on smaller or local models, so OpenAIGenericClient exposes a structured_output_mode:

  • "json_schema" (default): requests native structured output via response_format. Best on capable models and
    providers that enforce the schema via constrained decoding.
  • "json_object": requests plain-JSON mode and injects the schema into the prompt instead. Use this for
    providers/models that don't reliably honor json_schema โ€” including some local servers that accept the json_schema
    request but don't actually constrain output to it, where json_object can be more reliable.

When using smaller or local models:

  • Prefer the most capable model you can run. Very small models frequently emit JSON that doesn't match the requested
    schema, which surfaces as extraction failures.
  • Responses wrapped in Markdown ```json code fences are stripped automatically.
  • Keep SEMAPHORE_LIMIT low (see above) โ€” local
    servers and some providers have limited concurrency.

Configurable Prompts

Graphiti lets you override LLM prompt builders per client instance. Override callables must return
ChatPrompt (system + user). Response schemas are fixed and not overridable:

python
from graphiti_core import Graphiti
from graphiti_core.prompts import ChatPrompt, SystemMessage, UserMessage, create_prompt_library

def custom_extract_message(context: dict) -> ChatPrompt:
    return ChatPrompt(
        system=SystemMessage(content='Extract entities for my domain.'),
        user=UserMessage(content=str(context.get('episode_content', ''))),
    )

prompt_library = create_prompt_library({
    'extract_nodes': {
        'extract_message': custom_extract_message,
    },
})

graphiti = Graphiti(..., prompt_library=prompt_library)

Unspecified prompts keep the built-in defaults. Returning list[Message] from an override raises
TypeError โ€” migrate with return ChatPrompt(system=..., user=...). Unicode handling is applied
via ChatPrompt.as_messages().

The package-level prompt_library keeps the existing list[Message] API.
The opt-in prompt customization API uses ChatPromptLibrary and
DefaultChatPromptLibrary.

For per-prompt routing across providers, pass an opt-in llm_runtime. Create
one LLMTransport for each provider client. Each LLMModel binds a provider
model ID to one transport. An unrouted prompt uses the default model.
llm_runtime cannot be combined with llm_client or prompt_library.
Response schemas stay fixed. You can configure prompt text and model routes:

python
from typing import Literal

from graphiti_core import Graphiti
from graphiti_core.llm_client.anthropic_client import AnthropicClient
from graphiti_core.llm_client import (
    LLMRuntime,
    LLMTransport,
    OpenAIClient,
    PromptRoutes,
)

OpenAIModels = Literal['gpt-5.1', 'gpt-5-nano']
openai = LLMTransport[OpenAIModels](
    OpenAIClient(),
    models=['gpt-5.1', 'gpt-5-nano'],
)

AnthropicModels = Literal['claude-sonnet-4-5', 'claude-haiku-4-5']
anthropic = LLMTransport[AnthropicModels](
    AnthropicClient(),
    models=['claude-sonnet-4-5', 'claude-haiku-4-5'],
)

main = openai.model('gpt-5.1')
nano = openai.model('gpt-5-nano')
haiku = anthropic.model('claude-haiku-4-5')
runtime = LLMRuntime(
    model=main,
    routes=PromptRoutes(
        extract_nodes=PromptRoutes.ExtractNodes(extract_attributes=nano),
        dedupe_edges=PromptRoutes.DedupeEdges(
            resolve_edge=haiku,
        ),
    ),
)

graphiti = Graphiti(..., llm_runtime=runtime)

LLMModel does not have a small_id field. The runtime passes
model_size for legacy compatibility, but this value does not select a
smaller model. The selected model ID controls provider calls. A routed prompt
uses that model ID. An unrouted prompt uses the default model ID. Route prompts
that need a smaller model to that model explicitly. Legacy calls without
llm_runtime retain LLMConfig.small_model behavior.

GLiNER2 binds model objects at initialization. It does not support per-prompt
model routing. See spec/llm-runtime.md for the runtime API.

Jev dedupe

JevClient routes node dedupe and edge resolution to TypeSafe Jev. Set
JEV_API_KEY before you create the client. The duplicate threshold defaults
to 0.7. The contradiction threshold defaults to 0.8.

Jev is a decision model. It answers typed questions with probabilities. It
does not generate text. Use a general LLM as the default model. Route only
dedupe_nodes.nodes and dedupe_edges.resolve_edge to Jev. Do not use Jev
for extraction, summaries, or other generation tasks.

TypeSafe hosts the Jev API. Graphiti sends dedupe prompt content to TypeSafe.
See the FalkorDB Jev dedupe example for a runnable example.

python
from graphiti_core import Graphiti
from graphiti_core.llm_client import (
    JevClient,
    LLMRuntime,
    LLMTransport,
    OpenAIClient,
    PromptRoutes,
    jev_prompt_overrides,
)

openai = LLMTransport(OpenAIClient(), models=['gpt-6-luna'])
jev = LLMTransport(JevClient(), models=['jev-latest'])
jev_dedupe = jev.model('jev-latest', prompt_overrides=jev_prompt_overrides())

runtime = LLMRuntime(
    model=openai.model('gpt-6-luna'),
    routes=PromptRoutes(
        dedupe_nodes=PromptRoutes.DedupeNodes(nodes=jev_dedupe),
        dedupe_edges=PromptRoutes.DedupeEdges(resolve_edge=jev_dedupe),
    ),
)
graphiti = Graphiti(..., llm_runtime=runtime)

/* Detailed source-code truncated for AI context efficiency. */

bash
export GRAPHITI_TELEMETRY_ENABLED=false

Option 2: Set in your shell profile

bash
# For bash users (~/.bashrc or ~/.bash_profile)
echo 'export GRAPHITI_TELEMETRY_ENABLED=false' >> ~/.bashrc

# For zsh users (~/.zshrc)
echo 'export GRAPHITI_TELEMETRY_ENABLED=false' >> ~/.zshrc

Option 3: Set for a specific Python session

python
import os

os.environ['GRAPHITI_TELEMETRY_ENABLED'] = 'false'

# Then initialize Graphiti as usual
from graphiti_core import Graphiti

graphiti = Graphiti(...)

Telemetry is automatically disabled during test runs (when pytest is detected).

Technical Details

  • Telemetry uses PostHog for anonymous analytics collection
  • All telemetry operations are designed to fail silently - they will never interrupt your application or affect Graphiti
    functionality
  • The anonymous ID is stored locally and is not tied to any personal information

Contributing

We encourage and appreciate all forms of contributions, whether it's code, documentation, addressing GitHub Issues, or
helping others on GitHub. For detailed guidelines on code contributions, please refer
to CONTRIBUTING.

Support

Open a GitHub issue to ask questions, report bugs, or discuss Graphiti.


Overview (`mcp_server/README.md`)

Graphiti MCP Server

Graphiti is a framework for building and querying temporally-aware knowledge graphs, specifically tailored for AI agents
operating in dynamic environments. Unlike traditional retrieval-augmented generation (RAG) methods, Graphiti
continuously integrates user interactions, structured and unstructured enterprise data, and external information into a
coherent, queryable graph. The framework supports incremental data updates, efficient retrieval, and precise historical
queries without requiring complete graph recomputation, making it suitable for developing interactive, context-aware AI
applications.

Security: This server is a reference implementation. Do not use the server as a production deployment. The server has no authentication, no authorization, and no prompt-injection protection. These omissions are intentional. Any caller can read, change, or delete all graph data. Do not expose the server to an untrusted network. For production options, see Reference MCP and REST servers. For the security scope, see the security policy scope.

This is an experimental Model Context Protocol (MCP) server implementation for Graphiti. The MCP server exposes
Graphiti's key functionality through the MCP protocol, allowing AI assistants to interact with Graphiti's knowledge
graph capabilities.

To expose the server on all interfaces, pass --host 0.0.0.0 or set server.host, or change the host-side port
mapping in Docker Compose; the server has no authentication.

Features

The Graphiti MCP server provides comprehensive knowledge graph capabilities:

  • Episode Management: Add, retrieve, and delete episodes (text, messages, or JSON data)
  • Entity Management: Search and manage entity nodes and relationships in the knowledge graph
  • Search Capabilities: Search for facts (edges) and node summaries using semantic and hybrid search
  • Group Management: Organize and manage groups of related data with group_id filtering
  • Graph Maintenance: Clear the graph and rebuild indices
  • Graph Database Support: Multiple backend options including FalkorDB (default) and Neo4j
  • Multiple LLM Providers: Support for OpenAI, Anthropic, Gemini, Groq, and Azure OpenAI
  • Multiple Embedding Providers: Support for OpenAI, Voyage, Sentence Transformers, and Gemini embeddings
  • Rich Entity Types: Built-in entity types including Preferences, Requirements, Procedures, Locations, Events, Organizations, Documents, and more for structured knowledge extraction
  • HTTP Transport: Default HTTP transport with MCP endpoint at /mcp/ for broad client compatibility
  • Queue-based Processing: Asynchronous episode processing with configurable concurrency limits

Quick Start

Clone the Graphiti GitHub repo

bash
git clone https://github.com/getzep/graphiti.git

or

bash
gh repo clone getzep/graphiti

For Claude Desktop and other `stdio` only clients

  1. Note the full path to this directory.
text
cd graphiti && pwd
  1. Install the Graphiti prerequisites.

  2. Configure Claude, Cursor, or other MCP client to use Graphiti with a stdio transport. See the client documentation on where to find their MCP configuration files.

For Cursor and other HTTP-enabled clients

  1. Change directory to the mcp_server directory

cd graphiti/mcp_server

  1. Start the combined FalkorDB + MCP server using Docker Compose (recommended)
bash
docker compose up

This starts both FalkorDB and the MCP server in a single container.

Alternative: Run with separate containers using Neo4j:

bash
docker compose -f docker/docker-compose-neo4j.yml up
  1. Point your MCP client to http://localhost:8000/mcp/

Installation

Prerequisites

  1. Docker and Docker Compose (for the default FalkorDB setup)
  2. OpenAI API key for LLM operations (or API keys for other supported LLM providers)
  3. (Optional) Python 3.10+ if running the MCP server standalone with an external FalkorDB instance

Setup

  1. Clone the repository and navigate to the mcp_server directory
  2. Use uv to create a virtual environment and install dependencies:
bash
# Install uv if you don't have it already
curl -LsSf https://astral.sh/uv/install.sh | sh

# Create a virtual environment and install dependencies in one step
uv sync

# Optional: Install additional LLM providers (anthropic, gemini, groq, voyage, sentence-transformers)
uv sync --extra providers

Configuration

The server can be configured using a config.yaml file, environment variables, or command-line arguments (in order of precedence).

Default Configuration

The MCP server comes with sensible defaults:

  • Transport: HTTP (accessible at http://localhost:8000/mcp/)
  • Database: FalkorDB (combined in single container with MCP server)
  • LLM: OpenAI with model gpt-6-luna
  • Embedder: OpenAI text-embedding-3-small

Database Configuration

FalkorDB (Default)

FalkorDB is a Redis-based graph database that comes bundled with the MCP server in a single Docker container. This is the default and recommended setup.

yaml
database:
  provider: "falkordb"  # Default
  providers:
    falkordb:
      uri: "redis://localhost:6379"
      password: ""  # Optional
      database: "default_db"  # Optional

Neo4j

When you need a full-featured graph database, Neo4j is recommended:

yaml
database:
  provider: "neo4j"
  providers:
    neo4j:
      uri: "bolt://localhost:7687"
      username: "neo4j"
      password: "your_password"
      database: "neo4j"  # Optional, defaults to "neo4j"

FalkorDB

FalkorDB is another graph database option based on Redis:

yaml
database:
  provider: "falkordb"
  providers:
    falkordb:
      uri: "redis://localhost:6379"
      password: ""  # Optional
      database: "default_db"  # Optional

Configuration File (config.yaml)

The server supports multiple LLM providers (OpenAI, Anthropic, Gemini, Groq) and embedders. Edit config.yaml to configure:

yaml
server:
  transport: "http"  # Default. Options: stdio, http

llm:
  provider: "openai"  # or "anthropic", "gemini", "groq", "azure_openai"
  model: "gpt-6-luna"  # Default model
  # Optional for OpenAI-compatible providers: "json_schema" (default) or "json_object"
  structured_output_mode: "json_schema"

database:
  provider: "falkordb"  # Default. Options: "falkordb", "neo4j"

Using Ollama for Local LLM

To use Ollama with the MCP server, configure it as an OpenAI-compatible endpoint:

yaml
llm:
  provider: "openai"
  model: "gpt-oss:120b"  # or your preferred Ollama model
  api_base: "http://localhost:11434/v1"
  api_key: "ollama"  # dummy key required
  structured_output_mode: "json_object"  # use when json_schema is accepted but not enforced

embedder:
  provider: "sentence_transformers"  # recommended for local setup
  model: "all-MiniLM-L6-v2"

Make sure Ollama is running locally with: ollama serve

[!IMPORTANT]
Graphiti relies on structured (JSON) output for entity/edge extraction and deduplication, and reliability varies on
small or local models. Prefer the most capable model your hardware can run โ€” very small models frequently emit JSON
that doesn't match the expected schema, which surfaces as ingestion failures. For background and the
structured_output_mode (json_schema vs json_object) trade-off, see the core README's
Structured output and small models section.
If an OpenAI-compatible endpoint accepts json_schema but returns objects that miss fields such as
extracted_entities, set structured_output_mode: "json_object" so Graphiti injects the schema into the prompt
instead of relying on provider-side schema enforcement.

Entity Types

Graphiti MCP Server includes built-in entity types for structured knowledge extraction. These entity types are always enabled and configured via the entity_types section in your config.yaml:

Available Entity Types:

  • Preference: User preferences, choices, opinions, or selections (prioritized for user-specific information)
  • Requirement: Specific needs, features, or functionality that must be fulfilled
  • Procedure: Standard operating procedures and sequential instructions
  • Location: Physical or virtual places where activities occur
  • Event: Time-bound activities, occurrences, or experiences
  • Person: An individual human referenced in the content
  • Organization: Companies, institutions, groups, or formal entities
  • Document: Information content in various forms (books, articles, reports, videos, etc.)
  • Topic: Subject of conversation, interest, or knowledge domain (used as a fallback)
  • Object: Physical items, tools, devices, or possessions (used as a fallback)

These entity types are defined in config.yaml and can be customized by modifying the descriptions:

yaml
graphiti:
  entity_types:
    - name: "Preference"
    - name: "Requirement"
    # ... additional entity types

The MCP server automatically uses these entity types during episode ingestion to extract and structure information from conversations and documents.

Upgrade note: These built-in types are now registered as rich models with typed attributes (e.g. a description), so extraction stores those attributes on entities. The shipped default config.yaml enables them, so an existing deployment on the default config switches from attribute-free to rich-attribute extraction. To keep the previous behavior, set graphiti.entity_types to an empty list (or remove the entries).

Environment Variables

The config.yaml file supports environment variable expansion using ${VAR_NAME} or ${VAR_NAME:default} syntax. Key variables:

  • NEO4J_URI: URI for the Neo4j database (default: bolt://localhost:7687)
  • NEO4J_USER: Neo4j username (default: neo4j)
  • NEO4J_PASSWORD: Neo4j password (default: demodemo)
  • NEO4J_DATABASE: Neo4j database name (default: neo4j)
  • OPENAI_API_KEY: OpenAI API key (required for OpenAI LLM/embedder)
  • ANTHROPIC_API_KEY: Anthropic API key (for Claude models)
  • GOOGLE_API_KEY: Google API key (for Gemini models)
  • GROQ_API_KEY: Groq API key (for Groq models)
  • AZURE_OPENAI_API_KEY: Azure OpenAI API key
  • AZURE_OPENAI_ENDPOINT: Azure OpenAI endpoint URL
  • AZURE_OPENAI_DEPLOYMENT: Azure OpenAI deployment name
  • AZURE_OPENAI_EMBEDDINGS_ENDPOINT: Optional Azure OpenAI embeddings endpoint URL
  • AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT: Optional Azure OpenAI embeddings deployment name
  • AZURE_OPENAI_API_VERSION: Optional Azure OpenAI API version
  • USE_AZURE_AD: Optional use Azure Managed Identities for authentication
  • SEMAPHORE_LIMIT: Episode processing concurrency. See Concurrency and LLM Provider 429 Rate Limit Errors

You can set these variables in a .env file in the project directory.

Running the Server

Default Setup (FalkorDB Combined Container)

To run the Graphiti MCP server with the default FalkorDB setup:

bash
docker compose up

This starts a single container with:

  • HTTP transport on http://localhost:8000/mcp/
  • FalkorDB graph database on localhost:6379
  • FalkorDB web UI on http://localhost:3000
  • OpenAI LLM with gpt-6-luna model

Running with Neo4j

Option 1: Using Docker Compose

The easiest way to run with Neo4j is using the provided Docker Compose configuration:

bash
# This starts both Neo4j and the MCP server
docker compose -f docker/docker-compose.neo4j.yaml up

Option 2: Direct Execution with Existing Neo4j

If you have Neo4j already running:

bash
# Set environment variables
export NEO4J_URI="bolt://localhost:7687"
export NEO4J_USER="neo4j"
export NEO4J_PASSWORD="your_password"

# Run with Neo4j
uv run main.py --database-provider neo4j

Or use the Neo4j configuration file:

bash
uv run main.py --config config/config-docker-neo4j.yaml

Running with FalkorDB

Option 1: Using Docker Compose

bash
# This starts both FalkorDB (Redis-based) and the MCP server
docker compose -f docker/docker-compose.falkordb.yaml up

Option 2: Direct Execution with Existing FalkorDB

bash
# Set environment variables
export FALKORDB_URI="redis://localhost:6379"
export FALKORDB_PASSWORD=""  # If password protected

# Run with FalkorDB
uv run main.py --database-provider falkordb

Or use the FalkorDB configuration file:

bash
uv run main.py --config config/config-docker-falkordb.yaml

Available Command-Line Arguments

  • --config: Path to YAML configuration file (default: config.yaml)
  • --llm-provider: LLM provider to use (openai, anthropic, gemini, groq, azure_openai)
  • --embedder-provider: Embedder provider to use (openai, azure_openai, gemini, voyage)
  • --database-provider: Database provider to use (falkordb, neo4j) - default: falkordb
  • --model: Model name to use with the LLM client
  • --temperature: Temperature setting for the LLM (0.0-2.0)
  • --transport: Choose the transport method (http or stdio, default: http)
  • --group-id: Set a namespace for the graph (optional). If not provided, defaults to "main"
  • --destroy-graph: If set, destroys all Graphiti graphs on startup

Concurrency and LLM Provider 429 Rate Limit Errors

Graphiti's ingestion pipelines are designed for high concurrency, controlled by the SEMAPHORE_LIMIT environment variable. This setting determines how many episodes can be processed simultaneously. Since each episode involves multiple LLM calls (entity extraction, deduplication, summarization), the actual number of concurrent LLM requests will be several times higher.

Default: SEMAPHORE_LIMIT=10 (suitable for OpenAI Tier 3, mid-tier Anthropic)

Tuning Guidelines by LLM Provider

OpenAI:

  • Tier 1 (free): 3 RPM โ†’ SEMAPHORE_LIMIT=1-2
  • Tier 2: 60 RPM โ†’ SEMAPHORE_LIMIT=5-8
  • Tier 3: 500 RPM โ†’ SEMAPHORE_LIMIT=10-15
  • Tier 4: 5,000 RPM โ†’ SEMAPHORE_LIMIT=20-50

Anthropic:

  • Default tier: 50 RPM โ†’ SEMAPHORE_LIMIT=5-8
  • High tier: 1,000 RPM โ†’ SEMAPHORE_LIMIT=15-30

Azure OpenAI:

  • Consult your quota in Azure Portal and adjust accordingly
  • Start conservative and increase gradually

Ollama (local):

  • Hardware dependent โ†’ SEMAPHORE_LIMIT=1-5
  • Monitor CPU/GPU usage and adjust

Symptoms

  • Too high: 429 rate limit errors, increased API costs from parallel processing
  • Too low: Slow episode throughput, underutilized API quota

Monitoring

  • Watch logs for 429 rate limit errors
  • Monitor episode processing times in server logs
  • Check your LLM provider's dashboard for actual request rates
  • Track token usage and costs

Set this in your .env file:

bash
SEMAPHORE_LIMIT=10  # Adjust based on your LLM provider tier

Docker Deployment

The Graphiti MCP server can be deployed using Docker with your choice of database backend. The Dockerfile uses uv for package management, ensuring consistent dependency installation.

A pre-built Graphiti MCP container is available at: zepai/knowledge-graph-mcp

Environment Configuration

Before running Docker Compose, configure your API keys using a .env file (recommended):

  1. Create a .env file in the mcp_server directory:

    bash
    cd graphiti/mcp_server
    cp .env.example .env
  2. Edit the .env file to set your API keys:

    bash
    # Required - at least one LLM provider API key
    OPENAI_API_KEY=your_openai_api_key_here
    
    # Optional - other LLM providers
    ANTHROPIC_API_KEY=your_anthropic_key
    GOOGLE_API_KEY=your_google_key
    GROQ_API_KEY=your_groq_key
    
    # Optional - embedder providers
    VOYAGE_API_KEY=your_voyage_key

Important: The .env file must be in the mcp_server/ directory (the parent of the docker/ subdirectory).

Running with Docker Compose

All commands must be run from the mcp_server directory to ensure the .env file is loaded correctly:

bash
cd graphiti/mcp_server

Option 1: FalkorDB Combined Container (Default)

Single container with both FalkorDB and MCP server - simplest option:

bash
docker compose up

Option 2: Neo4j Database

Separate containers with Neo4j and MCP server:

bash
docker compose -f docker/docker-compose-neo4j.yml up

Default Neo4j credentials:

  • Username: neo4j
  • Password: demodemo
  • Bolt URI: bolt://neo4j:7687
  • Browser UI: http://localhost:7474

Option 3: FalkorDB with Separate Containers

Alternative setup with separate FalkorDB and MCP server containers:

bash
docker compose -f docker/docker-compose-falkordb.yml up

FalkorDB configuration:

  • Redis port: 6379
  • Web UI: http://localhost:3000
  • Connection: redis://falkordb:6379

Accessing the MCP Server

Once running, the MCP server is available at:

  • HTTP endpoint: http://localhost:8000/mcp/
  • Health check: http://localhost:8000/health

Running Docker Compose from a Different Directory

If you run Docker Compose from the docker/ subdirectory instead of mcp_server/, you'll need to modify the .env file path in the compose file:

yaml
# Change this line in the docker-compose file:
env_file:
  - path: ../.env    # When running from mcp_server/

# To this:
env_file:
  - path: .env       # When running from mcp_server/docker/

However, running from the mcp_server/ directory is recommended to avoid confusion.

Integrating with MCP Clients

VS Code / GitHub Copilot

VS Code with GitHub Copilot Chat extension supports MCP servers. Add to your VS Code settings (.vscode/mcp.json or global settings):

json
{
  "mcpServers": {
    "graphiti": {
      "uri": "http://localhost:8000/mcp/",
      "transport": {
        "type": "http"
      }
    }
  }
}

Other MCP Clients

To use the Graphiti MCP server with other MCP-compatible clients, configure it to connect to the server:

[!IMPORTANT]
You will need the Python package manager, uv installed. Please refer to the uv install instructions.

Ensure that you set the full path to the uv binary and your Graphiti project folder.

json
{
  "mcpServers": {
    "graphiti-memory": {
      "transport": "stdio",
      "command": "/Users//.local/bin/uv",
      "args": [
        "run",
        "--isolated",
        "--directory",
        "/Users/>/dev/zep/graphiti/mcp_server",
        "--project",
        ".",
        "main.py",
        "--transport",
        "stdio"
      ],
      "env": {
        "NEO4J_URI": "bolt://localhost:7687",
        "NEO4J_USER": "neo4j",
        "NEO4J_PASSWORD": "password",
        "OPENAI_API_KEY": "sk-XXXXXXXX",
        "MODEL_NAME": "gpt-6-luna"
      }
    }
  }
}

For HTTP transport (default), you can use this configuration:

json
{
  "mcpServers": {
    "graphiti-memory": {
      "transport": "http",
      "url": "http://localhost:8000/mcp/"
    }
  }
}

Available Tools

The Graphiti MCP server exposes the following tools:

  • add_memory: Add an episode to the knowledge graph (supports text, JSON, and message formats).
    Supports the bi-temporal reference_time, excluded_entity_types, custom_extraction_instructions,
    previous_episode_uuids, update_communities, and saga / saga_previous_episode_uuid.
  • add_triplet: Add a single fact (source entity -> fact -> target entity) directly, bypassing extraction.
  • search_nodes: Search the knowledge graph for relevant entities; supports entity_types and center_node_uuid.
  • search_memory_facts: Search for relevant facts (edges); supports edge_types, center_node_uuid,
    and valid_at / invalid_at date-range filters.
  • summarize_saga: Generate or refresh the running summary of a saga's episodes.
  • build_communities: Detect entity communities and produce higher-level community summaries.
  • get_episode_entities: Trace provenance โ€” the entities and facts created by specific episode UUIDs.
    Accepts an optional group_id; defaults to the configured group.
  • delete_entity_edge: Delete an entity edge from the knowledge graph.
    Accepts an optional group_id; defaults to the configured group.
  • delete_episode: Delete an episode and cascade-delete the entities/facts it solely created.
    Accepts an optional group_id; defaults to the configured group.
  • get_entity_edge: Get an entity edge by its UUID. Accepts an optional group_id; defaults to
    the configured group.
  • get_episodes: Get the most recent episodes for one or more groups (group_ids).
  • clear_graph: Clear all data from the knowledge graph for the given group(s).
  • get_status: Get the status of the Graphiti MCP server and database connection.

On FalkorDB, each group_id is stored in its own graph. Pass the same group_id that you used with
add_memory when you read, delete, or clear data for that group. Without a group_id, tools use the
server's configured default group.

Custom entity types and edge (fact) types โ€” including which edge types may connect which entity types โ€”
can be configured under the graphiti section of config/config.yaml. See the entity_types,
edge_types, and edge_type_map keys there.

Working with JSON Data

The Graphiti MCP server can process structured JSON data through the add_episode tool with source="json". This
allows you to automatically extract entities and relationships from structured data:

text
add_episode(
name="Customer Profile",
episode_body="{\"company\": {\"name\": \"Acme Technologies\"}, \"products\": [{\"id\": \"P001\", \"name\": \"CloudSync\"}, {\"id\": \"P002\", \"name\": \"DataMiner\"}]}",
source="json",
source_description="CRM data"
)

Integrating with the Cursor IDE

To integrate the Graphiti MCP Server with the Cursor IDE, follow these steps:

  1. Run the Graphiti MCP server using the default HTTP transport:
bash
uv run main.py --group-id <your_group_id>

Hint: specify a group_id to namespace graph data. If you do not specify a group_id, the server will use "main" as the group_id.

or

bash
docker compose up
  1. Configure Cursor to connect to the Graphiti MCP server.
json
{
  "mcpServers": {
    "graphiti-memory": {
      "url": "http://localhost:8000/mcp/"
    }
  }
}
  1. Add the Graphiti rules to Cursor's User Rules. See cursor_rules.md for details.

  2. Kick off an agent session in Cursor.

The integration enables AI assistants in Cursor to maintain persistent memory through Graphiti's knowledge graph
capabilities.

Integrating with Claude Desktop (Docker MCP Server)

The Graphiti MCP Server uses HTTP transport (at endpoint /mcp/). Claude Desktop does not natively support HTTP transport, so you'll need to use a gateway like mcp-remote.

  1. Run the Graphiti MCP server:

    bash
    docker compose up
    # Or run directly with uv:
    uv run main.py
  2. (Optional) Install mcp-remote globally:
    If you prefer to have mcp-remote installed globally, or if you encounter issues with npx fetching the package, you can install it globally. Otherwise, npx (used in the next step) will handle it for you.

    bash
    npm install mcp-remote
  3. Configure Claude Desktop:
    Open your Claude Desktop configuration file (usually claude_desktop_config.json) and add or modify the mcpServers section as follows:

    json
    {
      "mcpServers": {
        "graphiti-memory": {
          // You can choose a different name if you prefer
          "command": "npx", // Or the full path to mcp-remote if npx is not in your PATH
          "args": [
            "mcp-remote",
            "http://localhost:8000/mcp/" // The Graphiti server's HTTP endpoint
          ]
        }
      }
    }

    If you already have an mcpServers entry, add graphiti-memory (or your chosen name) as a new key within it.

  4. Restart Claude Desktop for the changes to take effect.

Requirements

  • Python 3.10 or higher
  • OpenAI API key (for LLM operations and embeddings) or other LLM provider API keys
  • MCP-compatible client
  • Docker and Docker Compose (for the default FalkorDB combined container)
  • (Optional) Neo4j database (version 5.26 or later) if not using the default FalkorDB setup

Telemetry

The Graphiti MCP server uses the Graphiti core library, which includes anonymous telemetry collection. When you initialize the Graphiti MCP server, anonymous usage statistics are collected to help improve the framework.

What's Collected

  • Anonymous identifier and system information (OS, Python version)
  • Graphiti version and configuration choices (LLM provider, database backend, embedder type)
  • No personal data, API keys, or actual graph content is ever collected

How to Disable

To disable telemetry in the MCP server, set the environment variable:

bash
export GRAPHITI_TELEMETRY_ENABLED=false

Or add it to your .env file:

text
GRAPHITI_TELEMETRY_ENABLED=false

For complete details about what's collected and why, see the Telemetry section in the main Graphiti README.

License

This project is licensed under the same license as the parent Graphiti project.


Overview (`server/README.md`)

graph-service

Graph service is a fast api server implementing the graphiti package.

Security: This server is a reference implementation. Do not use the server as a production deployment. The server has no authentication, no authorization, and no prompt-injection protection. These omissions are intentional. Any caller can read, change, or delete all graph data. Do not expose the server to an untrusted network. For production options, see Reference MCP and REST servers. For the security scope, see the security policy scope.

To expose the server on all interfaces, run Uvicorn with --host 0.0.0.0 or change the host-side port mapping in
Docker Compose; the server has no authentication.

Container Releases

The FastAPI server container is automatically built and published to Docker Hub when a v*.*.* tag is pushed (the same tags that publish graphiti-core to PyPI).

Image: zepai/graphiti

Available tags:

  • latest - Latest stable release
  • 0.30.2 - Specific version (matches graphiti-core version)

Platforms: linux/amd64, linux/arm64

The automated release workflow:

  1. Triggers on v*.*.* tag pushes (and can be run manually via workflow_dispatch)
  2. Waits for that graphiti-core version to be available on PyPI
  3. Builds multi-platform Docker image
  4. Tags with version number and latest
  5. Pushes to Docker Hub

Only stable releases are built automatically (pre-release versions are skipped).

Running Instructions

  1. Ensure you have Docker and Docker Compose installed on your system.

  2. Add zepai/graphiti:latest to your service setup

  3. Make sure to pass the following environment variables to the service

    text
    OPENAI_API_KEY=your_openai_api_key
    NEO4J_USER=your_neo4j_user
    NEO4J_PASSWORD=your_neo4j_password
    NEO4J_PORT=your_neo4j_port
  4. This service depends on having access to a neo4j instance, you may wish to add a neo4j image to your service setup as well. Or you may wish to use neo4j cloud or a desktop version if running this locally.

    An example of docker compose setup may look like this:

    yml
    version: '3.8'
    
       services:
       graph:
          image: zepai/graphiti:latest
          ports:
             - "127.0.0.1:8000:8000"
          
          environment:
             - OPENAI_API_KEY=${OPENAI_API_KEY}
             - NEO4J_URI=bolt://neo4j:${NEO4J_PORT}
             - NEO4J_USER=${NEO4J_USER}
             - NEO4J_PASSWORD=${NEO4J_PASSWORD}
       neo4j:
          image: neo4j:5.22.0
          
          ports:
             - "7474:7474"  # HTTP
             - "${NEO4J_PORT}:${NEO4J_PORT}"  # Bolt
          volumes:
             - neo4j_data:/data
          environment:
             - NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASSWORD}
    
       volumes:
       neo4j_data:
  5. Once you start the service, it will be available at http://localhost:8000 (or the port you have specified in the docker compose file).

  6. You may access the swagger docs at http://localhost:8000/docs. You may also access redocs at http://localhost:8000/redoc.

  7. You may also access the neo4j browser at http://localhost:7474 (the port depends on the neo4j instance you are using).


Overview (`.github/intake/README.md`)

Issue / PR intake automation

A fully deterministic triage bot for issues and pull requests. decide.py
fetches the item through the GitHub API and computes a decision from objective
facts only โ€” the issue-form sections, the labels the forms apply, the changed
file paths, and the Fixes #<number> references in the body. apply.py turns
that decision into allowlisted labels and one templated "sticky" comment. No
LLM is involved and no API key secret is needed: both scripts run on the
standard GITHUB_TOKEN and the Python standard library alone.

One-time setup

  1. Create the labels (required before the issue forms or bot run โ€” GitHub
    silently drops form labels that do not exist):

    bash
    bash .github/scripts/setup-triage-labels.sh
  2. (Optional) repository variable to disable intake without editing code:

    Variable Default Purpose
    INTAKE_ENABLED unset (enabled) Set to false to disable all intake + stale workflows (kill switch).

How it runs

  • .github/workflows/issue-intake.yml โ€” on issue open/edit/reopen. One
    job: decide.py --kind issue then apply.py --write.
  • .github/workflows/pr-intake.yml โ€” on PR open/sync/reopen/edit, for
    same-repo and fork branches. It uses pull_request_target so the token can
    label fork PRs, checks out the base-branch scripts (never the PR's), and
    reads the PR through the API, so it never runs PR-authored code.
  • .github/workflows/ai-moderator.yml โ€” spam and AI-generated-content
    detection for new issues and comments (the github/ai-moderator action).
  • .github/workflows/stale.yml โ€” daily; warns then closes items that keep
    any needs-* label (needs-info, needs-issue, needs-rfc, needs-tests,
    needs-rework) for 14 days. rfc-approved and security items are exempt.

Trusted authors (OWNER/MEMBER author association) and draft pull requests
are skipped: decide.py writes the empty decision {}, which apply.py
treats as a clean no-op.

Issue rules

The issue forms (.github/ISSUE_TEMPLATE/*.yml) render into ### <Label>
sections in the body. A section counts as missing when it is absent, blank, or
_No response_.

  • category: the first of bug, feature, documentation, question
    already on the issue (the form sets it), else other.

  • areas: from the Affected component (or Component) dropdown โ€”
    graphiti-core โ†’ scope:core, MCP server โ†’ scope:mcp, REST server โ†’
    scope:service, Documentation or examples โ†’ scope:docs,
    CI, Docker, or release โ†’ scope:ci. Other values and a missing section
    give no scope; a documentation issue with no scope defaults to
    scope:docs.

  • Required sections (missing ones produce needs-info and land in
    missing_fields):

    Category Required
    bug description, reproduction, expected, actual, environment
    feature problem, outcome
    question goal, attempted, environment
    documentation location, problem
  • needs-rfc: a feature whose Size is Large feature requiring design approval gets needs-rfc unless the issue already has rfc-approved, and
    proposal/alternatives/impact become required as well.

  • comment_id: ask_rfc_fields when needs-rfc; ask_repro for a bug
    missing fields; ask_info for anything else missing fields; else none.

Pull request rules

  • areas: derived from the changed file paths (see PATH_SCOPE_RULES).
  • needs-issue: no linked issue (Fixes #<number>) โ†’ needs-issue and
    the linked-issue missing field. A number that 404s or resolves to a pull
    request does not count.
  • category: feature/bug/documentation when a linked issue carries
    that label, else feature when the template's Feature checkbox is ticked,
    else other.
  • needs-rfc: a feature PR whose linked issue lacks rfc-approved.
  • needs-tests: the diff touches code but no test file, and the
    Tests are not applicable checkbox is not ticked.
  • needs-rework: needs-issue and needs-tests together.
  • comment_id: pr_needs_rework > pr_needs_rfc > pr_needs_tests.

Files

File Role
decide.py Read-only: fetch item, compute the deterministic decision, write JSON. Stdlib only.
apply.py Deterministic: validate the decision, apply allowlisted labels + one templated sticky comment. Stdlib only.
decision.schema.json The decision contract and the single source of truth for the label taxonomy (apply.py derives its allowlist from it).
templates/*.md The only text the bot can post; substitutions come from closed sets.

Tests: tests/intake/ (run by unit_tests.yml). The workflow guard tests in
test_workflows.py encode the security invariants โ€” keep them passing.


Overview (`examples/azure-openai/README.md`)

Azure OpenAI with Neo4j Example

This example demonstrates how to use Graphiti with Azure OpenAI and Neo4j to build a knowledge graph.

Prerequisites

  • Python 3.10+
  • Neo4j database (running locally or remotely)
  • Azure OpenAI subscription with deployed models

Setup

1. Install Dependencies

bash
uv sync

2. Configure Environment Variables

Copy the .env.example file to .env and fill in your credentials:

bash
cd examples/azure-openai
cp .env.example .env

Edit .env with your actual values:

env
# Neo4j connection settings
NEO4J_URI=bolt://localhost:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your-password

# Azure OpenAI settings
AZURE_OPENAI_ENDPOINT=https://your-resource-name.openai.azure.com
AZURE_OPENAI_API_KEY=your-api-key-here
AZURE_OPENAI_DEPLOYMENT=gpt-5-mini
AZURE_OPENAI_EMBEDDING_DEPLOYMENT=text-embedding-3-small

3. Azure OpenAI Model Deployments

This example requires two Azure OpenAI model deployments:

  1. Chat Completion Model: Used for entity extraction and relationship analysis

    • Set the deployment name in AZURE_OPENAI_DEPLOYMENT
  2. Embedding Model: Used for semantic search

    • Set the deployment name in AZURE_OPENAI_EMBEDDING_DEPLOYMENT

4. Neo4j Setup

Make sure Neo4j is running and accessible at the URI specified in your .env file.

For local development:

  • Download and install Neo4j Desktop
  • Create a new database
  • Start the database
  • Use the credentials in your .env file

Running the Example

bash
cd examples/azure-openai
uv run azure_openai_neo4j.py

What This Example Does

  1. Initialization: Sets up connections to Neo4j and Azure OpenAI
  2. Adding Episodes: Ingests text and JSON data about California politics
  3. Basic Search: Performs hybrid search combining semantic similarity and BM25 retrieval
  4. Center Node Search: Reranks results based on graph distance to a specific node
  5. Cleanup: Properly closes database connections

Key Concepts

Azure OpenAI Integration

The example shows how to configure Graphiti to use Azure OpenAI with the OpenAI v1 API:

python
# Initialize Azure OpenAI client using the standard OpenAI client
# with Azure's v1 API endpoint
azure_client = AsyncOpenAI(
    base_url=f"{azure_endpoint}/openai/v1/",
    api_key=azure_api_key,
)

# Create LLM and Embedder clients
llm_client = AzureOpenAILLMClient(
    azure_client=azure_client,
    config=LLMConfig(model=azure_deployment, small_model=azure_deployment)
)
embedder_client = AzureOpenAIEmbedderClient(
    azure_client=azure_client,
    model=azure_embedding_deployment
)

# Initialize Graphiti with custom clients
graphiti = Graphiti(
    neo4j_uri,
    neo4j_user,
    neo4j_password,
    llm_client=llm_client,
    embedder=embedder_client,
)

Note: This example uses Azure OpenAI's v1 API compatibility layer, which allows using the standard AsyncOpenAI client. The endpoint format is https://your-resource-name.openai.azure.com/openai/v1/.

Episodes

Episodes are the primary units of information in Graphiti. They can be:

  • Text: Raw text content (e.g., transcripts, documents)
  • JSON: Structured data with key-value pairs

Graphiti combines multiple search strategies:

  • Semantic Search: Uses embeddings to find semantically similar content
  • BM25: Keyword-based text retrieval
  • Graph Traversal: Leverages relationships between entities

Troubleshooting

Azure OpenAI API Errors

  • Verify your endpoint URL is correct (should end in .openai.azure.com)
  • Check that your API key is valid
  • Ensure your deployment names match actual deployments in Azure
  • Verify API version is supported by your deployment

Neo4j Connection Issues

  • Ensure Neo4j is running
  • Check firewall settings
  • Verify credentials are correct
  • Check URI format (should be bolt:// or neo4j://)

Next Steps

  • Explore other search recipes in graphiti_core/search/search_config_recipes.py
  • Try different episode types and content
  • Experiment with custom entity definitions
  • Add more episodes to build a larger knowledge graph
  • examples/quickstart/ - Basic Graphiti usage with OpenAI
  • examples/podcast/ - Processing longer content
  • examples/ecommerce/ - Domain-specific knowledge graphs

Overview (`examples/gliner2/README.md`)

GLiNER2 Hybrid LLM Client Example (Experimental)

Note: The GLiNER2Client is experimental and may change in future releases.

This example demonstrates using GLiNER2 as a hybrid LLM client for Graphiti. GLiNER2 handles entity extraction (NER) locally on CPU, while a general-purpose LLM client handles edge/fact extraction, deduplication, summarization, and other reasoning tasks.

Prerequisites

  • Python 3.11+
  • Neo4j 5.26+ (Neo4j Desktop or Docker)
  • An LLM provider API key (Google, OpenAI, Anthropic, etc.)

Setup

bash
# Install graphiti with the gliner2 extra
pip install graphiti-core[gliner2]

# Copy and configure environment variables
cp .env.example .env

The GLiNER2 model weights are downloaded automatically on first run.

LLM and Embedding Providers

The example uses Google Gemini (gemini-2.5-flash-lite) for the LLM and embeddings, but GLiNER2Client accepts any Graphiti LLMClient. To swap providers, replace GeminiClient and GeminiEmbedder with the equivalent from another provider:

  • graphiti_core.llm_client.openai_client.OpenAIClient
  • graphiti_core.llm_client.anthropic_client.AnthropicClient
  • graphiti_core.llm_client.groq_client.GroqClient
  • graphiti_core.embedder.openai.OpenAIEmbedder
  • graphiti_core.embedder.voyage.VoyageAIEmbedder

Configuration

Parameter Description Default
threshold GLiNER2 confidence threshold (0.0-1.0). Higher values reduce spurious extractions. 0.5
GLINER2_MODEL HuggingFace model ID fastino/gliner2-large-v1

Running

bash
python gliner2_neo4j.py

Overview (`examples/jev/README.md`)

Jev dedupe with FalkorDB

This example routes node deduplication and edge resolution to Jev. OpenAI
gpt-6-luna handles extraction, summaries, and all other prompts. The example
adds four episodes in order. The episodes show a name variant, a repeated
fact, and a transfer of responsibility for the customer billing platform from
Alice Chen to Priya Patel.

Prerequisites

  • Python 3.11+
  • FalkorDB
  • An OpenAI API key in OPENAI_API_KEY
  • A TypeSafe API key in JEV_API_KEY

Start FalkorDB with Docker:

bash
docker run -p 6379:6379 falkordb/falkordb:latest

Copy .env.example to .env and set both API keys. The example uses
localhost:6379 by default. Set FALKORDB_HOST, FALKORDB_PORT,
FALKORDB_USERNAME, or FALKORDB_PASSWORD to use other connection settings.

When to use a decision model

Jev is a decision model. It answers typed questions with probabilities. It does
not generate text. Use a general LLM as the default model. Route only
dedupe_nodes.nodes and dedupe_edges.resolve_edge to Jev. Do not use Jev for
extraction, summaries, or other generation tasks.

Prompt routing

Prompt Model
Extraction, summaries, and all other prompts OpenAI gpt-6-luna
dedupe_nodes.nodes Jev jev-latest
dedupe_edges.resolve_edge Jev jev-latest

The example uses the default OpenAI embedder. TypeSafe hosts the Jev API.
Graphiti sends dedupe prompt content to TypeSafe.

Expected output

One run showed Alice's billing-platform fact with
invalid_at=2025-01-10T00:00:00+00:00 and an expired_at value. Priya's
replacement fact was active. The contradiction probability was 0.89 for
Alice's fact and 0.04 for the Acme fact. The run made 2
dedupe_nodes.nodes calls and 3 dedupe_edges.resolve_edge calls. The final
node list showed one Alice Chen entity.

Extraction output can change between runs. If the model does not extract
Alice's billing-platform fact, or if it writes the change as a separate
termination fact, Alice's fact stays active. The current Graphiti contradiction
rule uses only the new fact's valid_at value.

Run the example

From the repository root, install the project dependencies:

bash
uv sync --extra dev

Then run the example from this directory:

bash
cd examples/jev
uv run python jev_dedupe_falkordb.py

The output lists the entities and facts for each episode. It then lists all
facts with their invalidation or expiration times and the final entity nodes.
The example does not call Graphiti.search.


Overview (`examples/openai_decisions/README.md`)

OpenAI Decisions dedupe with FalkorDB

This example routes node deduplication and edge resolution to OpenAI Decisions.
OpenAI gpt-6-luna Chat Completions handles extraction, summaries, and all
other prompts. The example adds four episodes in order. The episodes show a
name variant, a repeated fact, and a transfer of responsibility for the
customer billing platform from Alice Chen to Priya Patel.

Prerequisites

  • Python 3.11+
  • FalkorDB
  • An OpenAI API key in OPENAI_API_KEY

Start FalkorDB with Docker:

bash
docker run -p 6379:6379 falkordb/falkordb:latest

Copy .env.example to .env and set the API key. The example uses
localhost:6379 by default. Set FALKORDB_HOST, FALKORDB_PORT,
FALKORDB_USERNAME, or FALKORDB_PASSWORD to use other connection settings.

When to use a decision model

OpenAI Decisions is a decision model. It answers typed questions with
probabilities. It does not generate text. Use a general LLM as the default
model. Route only dedupe_nodes.nodes and dedupe_edges.resolve_edge to the
decision model. Do not use it for extraction, summaries, or other generation
tasks.

Prompt routing

Prompt Model
Extraction, summaries, and all other prompts OpenAI gpt-6-luna
dedupe_nodes.nodes OpenAI Decisions gpt-6-luna
dedupe_edges.resolve_edge OpenAI Decisions gpt-6-luna

The example uses the default OpenAI embedder. OpenAI hosts the Decisions API.
Graphiti sends the dedupe state and typed questions to OpenAI.

Expected output

One run showed Alice's billing-platform facts with
invalid_at=2025-01-10T00:00:00+00:00 and expired_at values. Priya's
replacement fact was active. The contradiction probability was 1.0 for both
Alice facts. The run made 2 dedupe_nodes.nodes calls and 3
dedupe_edges.resolve_edge calls. The final node list showed one Alice Chen
entity.

Extraction output can change between runs. If the model does not extract
Alice's billing-platform fact, or if it writes the change as a separate
termination fact, Alice's fact stays active. The current Graphiti contradiction
rule uses only the new fact's valid_at value.

Run the example

From the repository root, install the project dependencies:

bash
uv sync --extra dev

Then run the example from this directory:

bash
cd examples/openai_decisions
uv run python openai_decisions_dedupe_falkordb.py

The output lists the entities and facts for each episode. It then lists all
facts with their invalidation or expiration times and the final entity nodes.
The example does not call Graphiti.search.


Overview (`examples/opentelemetry/README.md`)

OpenTelemetry Stdout Tracing Example

Configure Graphiti with OpenTelemetry to output trace spans to stdout.

Setup

bash
uv sync
export OPENAI_API_KEY=your_api_key_here
uv run otel_stdout_example.py

Configure OpenTelemetry with Graphiti

python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor

# Set up OpenTelemetry with stdout exporter
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)

# Get tracer and pass to Graphiti
tracer = trace.get_tracer(__name__)
graphiti = Graphiti(
    graph_driver=kuzu_driver,
    tracer=tracer,
    trace_span_prefix='graphiti.example'
)

Overview (`examples/quickstart/README.md`)

Graphiti Quickstart Example

This example demonstrates the basic functionality of Graphiti, including:

  1. Connecting to a Neo4j or FalkorDB database
  2. Initializing Graphiti indices and constraints
  3. Adding episodes to the graph
  4. Searching the graph with semantic and keyword matching
  5. Exploring graph-based search with reranking using the top search result's source node UUID
  6. Performing node search using predefined search recipes

Prerequisites

  • Python 3.9+
  • OpenAI API key (set as OPENAI_API_KEY environment variable)
  • For Neo4j:
    • Neo4j Desktop installed and running
    • A local DBMS created and started in Neo4j Desktop
  • For FalkorDB:
  • For Amazon Neptune:

Setup Instructions

  1. Install the required dependencies:
bash
pip install graphiti-core
  1. Set up environment variables:
bash
# Required for LLM and embedding
export OPENAI_API_KEY=your_openai_api_key

# Optional Neo4j connection parameters (defaults shown)
export NEO4J_URI=bolt://localhost:7687
export NEO4J_USER=neo4j
export NEO4J_PASSWORD=password

# Optional FalkorDB connection parameters (defaults shown)
export FALKORDB_URI=falkor://localhost:6379

# Optional Amazon Neptune connection parameters
NEPTUNE_HOST=your_neptune_host
NEPTUNE_PORT=your_port_or_8182
AOSS_HOST=your_aoss_host
AOSS_PORT=your_port_or_443

# To use a different database, modify the driver constructor in the script

TIP: For Amazon Neptune host string please use the following formats

  • For Neptune Database: neptune-db://<cluster endpoint>
  • For Neptune Analytics: neptune-graph://<graph identifier>
  1. Run the example:
bash
python quickstart_neo4j.py

# For FalkorDB
python quickstart_falkordb.py

# For Amazon Neptune
python quickstart_neptune.py

What This Example Demonstrates

  • Graph Initialization: Setting up the Graphiti indices and constraints in Neo4j, Amazon Neptune, or FalkorDB
  • Adding Episodes: Adding text content that will be analyzed and converted into knowledge graph nodes and edges
  • Edge Search Functionality: Performing hybrid searches that combine semantic similarity and BM25 retrieval to find relationships (edges)
  • Graph-Aware Search: Using the source node UUID from the top search result to rerank additional search results based on graph distance
  • Node Search Using Recipes: Using predefined search configurations like NODE_HYBRID_SEARCH_RRF to directly search for nodes rather than edges
  • Result Processing: Understanding the structure of search results including facts, nodes, and temporal metadata

Next Steps

After running this example, you can:

  1. Modify the episode content to add your own information
  2. Try different search queries to explore the knowledge extraction
  3. Experiment with different center nodes for graph-distance-based reranking
  4. Try other predefined search recipes from graphiti_core.search.search_config_recipes
  5. Explore the more advanced examples in the other directories

Troubleshooting

"Graph not found: default_db" Error

If you encounter the error Neo.ClientError.Database.DatabaseNotFound: Graph not found: default_db, this occurs when the driver is trying to connect to a database that doesn't exist.

Solution:
The Neo4j driver defaults to using neo4j as the database name. If you need to use a different database, modify the driver constructor in the script:

python
# In quickstart_neo4j.py, change:
driver = Neo4jDriver(uri=neo4j_uri, user=neo4j_user, password=neo4j_password)

# To specify a different database:
driver = Neo4jDriver(uri=neo4j_uri, user=neo4j_user, password=neo4j_password, database="your_db_name")

Understanding the Output

Edge Search Results

The edge search results include EntityEdge objects with:

  • UUID: Unique identifier for the edge
  • Fact: The extracted fact from the episode
  • Valid at/invalid at: Time period during which the fact was true (if available)
  • Source/target node UUIDs: Connections between entities in the knowledge graph

Node Search Results

The node search results include EntityNode objects with:

  • UUID: Unique identifier for the node
  • Name: The name of the entity
  • Content Summary: A summary of the node's content
  • Node Labels: The types of the node (e.g., Person, Organization)
  • Created At: When the node was created
  • Attributes: Additional properties associated with the node

Overview (`mcp_server/docker/README.md`)

Docker Deployment for Graphiti MCP Server

This directory contains Docker Compose configurations for running the Graphiti MCP server with graph database backends: FalkorDB (combined image) and Neo4j.

Quick Start

bash
# Default configuration (FalkorDB combined image)
docker-compose up

# Neo4j (separate containers)
docker-compose -f docker-compose-neo4j.yml up

Environment Variables

Create a .env file in this directory with your API keys:

bash
# Required
OPENAI_API_KEY=your-api-key-here

# Optional
GRAPHITI_GROUP_ID=main
SEMAPHORE_LIMIT=10

# Database-specific variables (see database sections below)

Database Configurations

FalkorDB (Combined Image)

File: docker-compose.yml (default)

The default configuration uses a combined Docker image that bundles both FalkorDB and the MCP server together for simplified deployment.

Configuration

bash
# Environment variables
FALKORDB_URI=redis://localhost:6379  # Connection URI (services run in same container)
FALKORDB_PASSWORD=  # Password (default: empty)
FALKORDB_DATABASE=default_db  # Database name (default: default_db)

Accessing Services

Data Management

Backup:

bash
docker run --rm -v mcp_server_falkordb_data:/var/lib/falkordb/data -v $(pwd):/backup alpine \
  tar czf /backup/falkordb-backup.tar.gz -C /var/lib/falkordb/data .

Restore:

bash
docker run --rm -v mcp_server_falkordb_data:/var/lib/falkordb/data -v $(pwd):/backup alpine \
  tar xzf /backup/falkordb-backup.tar.gz -C /var/lib/falkordb/data

Clear Data:

bash
docker-compose down
docker volume rm mcp_server_falkordb_data
docker-compose up

Gotchas

  • Both FalkorDB and MCP server run in the same container
  • FalkorDB uses Redis persistence mechanisms (AOF/RDB)
  • Default configuration has no password - add one for production
  • Health check only monitors FalkorDB; MCP server startup visible in logs

See README-falkordb-combined.md for detailed information about the combined image.

Neo4j

File: docker-compose-neo4j.yml

Neo4j runs as a separate container service with its own web interface.

Configuration

bash
# Environment variables
NEO4J_URI=bolt://neo4j:7687  # Connection URI (default: bolt://neo4j:7687)
NEO4J_USER=neo4j  # Username (default: neo4j)
NEO4J_PASSWORD=demodemo  # Password (default: demodemo)
NEO4J_DATABASE=neo4j  # Database name (default: neo4j)
USE_PARALLEL_RUNTIME=false  # Enterprise feature (default: false)

Accessing Neo4j

Default credentials: neo4j / demodemo

Data Management

Backup:

bash
# Backup both data and logs volumes
docker run --rm -v docker_neo4j_data:/data -v $(pwd):/backup alpine \
  tar czf /backup/neo4j-data-backup.tar.gz -C /data .
docker run --rm -v docker_neo4j_logs:/logs -v $(pwd):/backup alpine \
  tar czf /backup/neo4j-logs-backup.tar.gz -C /logs .

Restore:

bash
# Restore both volumes
docker run --rm -v docker_neo4j_data:/data -v $(pwd):/backup alpine \
  tar xzf /backup/neo4j-data-backup.tar.gz -C /data
docker run --rm -v docker_neo4j_logs:/logs -v $(pwd):/backup alpine \
  tar xzf /backup/neo4j-logs-backup.tar.gz -C /logs

Clear Data:

bash
docker-compose -f docker-compose-neo4j.yml down
docker volume rm docker_neo4j_data docker_neo4j_logs
docker-compose -f docker-compose-neo4j.yml up

Gotchas

  • Neo4j takes 30+ seconds to start up - wait for the health check
  • The web interface requires authentication even for local access
  • Memory heap is configured for 512MB initial, 1GB max
  • Page cache is set to 512MB
  • Enterprise features like parallel runtime require a license

Switching Between Databases

To switch from FalkorDB to Neo4j (or vice versa):

  1. Stop current setup:

    bash
    docker-compose down  # Stop FalkorDB combined image
    # or
    docker-compose -f docker-compose-neo4j.yml down  # Stop Neo4j
  2. Start new database:

    bash
    docker-compose up  # Start FalkorDB combined image
    # or
    docker-compose -f docker-compose-neo4j.yml up  # Start Neo4j

Note: Data is not automatically migrated between different database types. You'll need to export from one and import to another using the MCP API.

Troubleshooting

Port Conflicts

If port 8000 is already in use:

bash
# Find what's using the port
lsof -i :8000

# Change the port in docker-compose.yml
# Under ports section: "8001:8000"

Container Won't Start

  1. Check logs:

    bash
    docker-compose logs graphiti-mcp
  2. Verify .env file exists and contains valid API keys:

    bash
    cat .env | grep API_KEY
  3. Ensure Docker has enough resources allocated

Database Connection Issues

FalkorDB:

  • Test Redis connectivity: docker compose exec graphiti-falkordb redis-cli ping
  • Check FalkorDB logs: docker compose logs graphiti-falkordb
  • Verify both services started: Look for "FalkorDB is ready!" and "Starting MCP server..." in logs

Neo4j:

  • Wait for health check to pass (can take 30+ seconds)
  • Check Neo4j logs: docker-compose -f docker-compose-neo4j.yml logs neo4j
  • Verify credentials match environment variables

FalkorDB:

  • Test Redis connectivity: redis-cli -h localhost ping

Data Not Persisting

  1. Verify volumes are created:

    bash
    docker volume ls | grep docker_
  2. Check volume mounts in container:

    bash
    docker inspect graphiti-mcp | grep -A 5 Mounts
  3. Ensure proper shutdown:

    bash
    docker-compose down  # Not docker-compose down -v (which removes volumes)

Performance Issues

FalkorDB:

  • Adjust SEMAPHORE_LIMIT environment variable
  • Monitor with: docker stats graphiti-falkordb
  • Check Redis memory: docker compose exec graphiti-falkordb redis-cli info memory

Neo4j:

  • Increase heap memory in docker-compose-neo4j.yml
  • Adjust page cache size based on data size
  • Check query performance in Neo4j browser

Docker Resources

Volumes

Each database configuration uses named volumes for data persistence:

  • FalkorDB (combined): falkordb_data
  • Neo4j: neo4j_data, neo4j_logs

Networks

All configurations use the default bridge network. Services communicate using container names as hostnames.

Resource Limits

No resource limits are set by default. To add limits, modify the docker-compose file:

yaml
services:
  graphiti-mcp:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 1G

Configuration Files

Each database has a dedicated configuration file in ../config/:

  • config-docker-falkordb-combined.yaml - FalkorDB combined image configuration
  • config-docker-neo4j.yaml - Neo4j configuration

These files are mounted read-only into the container at /app/mcp/config/config.yaml (for combined image) or /app/config/config.yaml (for Neo4j).


Overview (`mcp_server/tests/README.md`)

Graphiti MCP Server Integration Tests

This directory contains a comprehensive integration test suite for the Graphiti MCP Server using the official Python MCP SDK.

Overview

The test suite is designed to thoroughly test all aspects of the Graphiti MCP server with special consideration for LLM inference latency and system performance.

Test Organization

Core Test Modules

  • test_comprehensive_integration.py - Main integration test suite covering all MCP tools
  • test_async_operations.py - Tests for concurrent operations and async patterns
  • test_stress_load.py - Stress testing and load testing scenarios
  • test_fixtures.py - Shared fixtures and test utilities
  • test_mcp_integration.py - Original MCP integration tests
  • test_configuration.py - Configuration loading and validation tests

Test Categories

Tests are organized with pytest markers:

  • unit - Fast unit tests without external dependencies
  • integration - Tests requiring database and services
  • slow - Long-running tests (stress/load tests)
  • requires_neo4j - Tests requiring Neo4j
  • requires_falkordb - Tests requiring FalkorDB
  • requires_openai - Tests requiring OpenAI API key

Installation

bash
# Install test dependencies
uv add --dev pytest pytest-asyncio pytest-timeout pytest-xdist faker psutil

# Install MCP SDK
uv add mcp

Running Tests

Quick Start

bash
# Run smoke tests (quick validation)
python tests/run_tests.py smoke

# Run integration tests with mock LLM
python tests/run_tests.py integration --mock-llm

# Run all tests
python tests/run_tests.py all

Test Runner Options

bash
python tests/run_tests.py [suite] [options]

Suites:
  unit          - Unit tests only
  integration   - Integration tests
  comprehensive - Comprehensive integration suite
  async         - Async operation tests
  stress        - Stress and load tests
  smoke         - Quick smoke tests
  all           - All tests

Options:
  --database    - Database backend (neo4j, falkordb)
  --mock-llm    - Use mock LLM for faster testing
  --parallel N  - Run tests in parallel with N workers
  --coverage    - Generate coverage report
  --skip-slow   - Skip slow tests
  --timeout N   - Test timeout in seconds
  --check-only  - Only check prerequisites

Examples

bash
# Quick smoke test with FalkorDB (default)
python tests/run_tests.py smoke

# Full integration test with Neo4j
python tests/run_tests.py integration --database neo4j

# Stress testing with parallel execution
python tests/run_tests.py stress --parallel 4

# Run with coverage
python tests/run_tests.py all --coverage

# Check prerequisites only
python tests/run_tests.py all --check-only

Test Coverage

Core Operations

  • Server initialization and tool discovery
  • Adding memories (text, JSON, message)
  • Episode queue management
  • Search operations (semantic, hybrid)
  • Episode retrieval and deletion
  • Entity and edge operations

Async Operations

  • Concurrent operations
  • Queue management
  • Sequential processing within groups
  • Parallel processing across groups

Performance Testing

  • Latency measurement
  • Throughput testing
  • Batch processing
  • Resource usage monitoring

Stress Testing

  • Sustained load scenarios
  • Spike load handling
  • Memory leak detection
  • Connection pool exhaustion
  • Rate limit handling

Configuration

Environment Variables

bash
# Database configuration
export DATABASE_PROVIDER=falkordb  # or neo4j
export NEO4J_URI=bolt://localhost:7687
export NEO4J_USER=neo4j
export NEO4J_PASSWORD=graphiti
export FALKORDB_URI=redis://localhost:6379

# LLM configuration
export OPENAI_API_KEY=your_key_here  # or use --mock-llm

# Test configuration
export TEST_MODE=true
export LOG_LEVEL=INFO

pytest.ini Configuration

The pytest.ini file configures:

  • Test discovery patterns
  • Async mode settings
  • Test markers
  • Timeout settings
  • Output formatting

Test Fixtures

Data Generation

The test suite includes comprehensive data generators:

python
from test_fixtures import TestDataGenerator

# Generate test data
company = TestDataGenerator.generate_company_profile()
conversation = TestDataGenerator.generate_conversation()
document = TestDataGenerator.generate_technical_document()

Test Client

Simplified client creation:

python
from test_fixtures import graphiti_test_client

async with graphiti_test_client(database="falkordb") as (session, group_id):
    # Use session for testing
    result = await session.call_tool('add_memory', {...})

Performance Considerations

LLM Latency Management

The tests account for LLM inference latency through:

  1. Configurable timeouts - Different timeouts for different operations
  2. Mock LLM option - Fast testing without API calls
  3. Intelligent polling - Adaptive waiting for episode processing
  4. Batch operations - Testing efficiency of batched requests

Resource Management

  • Memory leak detection
  • Connection pool monitoring
  • Resource usage tracking
  • Graceful degradation testing

CI/CD Integration

GitHub Actions

yaml
name: MCP Integration Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    services:
      neo4j:
        image: neo4j:5.26
        env:
          NEO4J_AUTH: neo4j/graphiti
        ports:
          - 7687:7687

    steps:
      - uses: actions/checkout@v2

      - name: Install dependencies
        run: |
          pip install uv
          uv sync --extra dev

      - name: Run smoke tests
        run: python tests/run_tests.py smoke --mock-llm

      - name: Run integration tests
        run: python tests/run_tests.py integration --database neo4j
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

Troubleshooting

Common Issues

  1. Database connection failures

    bash
    # Check Neo4j
    curl http://localhost:7474
    
    # Check FalkorDB
    redis-cli ping
  2. API key issues

    bash
    # Use mock LLM for testing without API key
    python tests/run_tests.py all --mock-llm
  3. Timeout errors

    bash
    # Increase timeout for slow systems
    python tests/run_tests.py integration --timeout 600
  4. Memory issues

    bash
    # Skip stress tests on low-memory systems
    python tests/run_tests.py all --skip-slow

Test Reports

Performance Report

After running performance tests:

python
from test_fixtures import PerformanceBenchmark

benchmark = PerformanceBenchmark()
# ... run tests ...
print(benchmark.report())

Load Test Report

Stress tests generate detailed reports:

text
LOAD TEST REPORT
================
Test Run 1:
  Total Operations: 100
  Success Rate: 95.0%
  Throughput: 12.5 ops/s
  Latency (avg/p50/p95/p99/max): 0.8/0.7/1.5/2.1/3.2s

Contributing

When adding new tests:

  1. Use appropriate pytest markers
  2. Include docstrings explaining test purpose
  3. Use fixtures for common operations
  4. Consider LLM latency in test design
  5. Add timeout handling for long operations
  6. Include performance metrics where relevant

License

See main project LICENSE file.


Overview (`.github/actions/setup-socket-firewall/README.md`)

Setup Socket Firewall wrapper

Composite GitHub Action that installs Socket Firewall Enterprise (sfw) in
wrapper mode and routes supported package-manager commands through it for later
bash steps in the same job.

Usage

yaml
- name: Setup Socket Firewall wrapper
  uses: ./.github/actions/setup-socket-firewall
  with:
    socket-api-key: ${{ secrets.SOCKET_API_KEY }}

Call the action after checkout and before the first uv sync, uv lock,
uv pip, or pip install step.

The action:

  • downloads the Linux sfw binary when needed
  • exports SOCKET_API_KEY and SFW_TELEMETRY_DISABLED=true
  • configures SFW_CUSTOM_REGISTRIES with wrap hosts (including
    files.pythonhosted.org for PyPI artifact downloads)
  • writes a BASH_ENV file with package-manager wrapper functions

Wrapper functions apply only to later bash steps that source BASH_ENV. They
do not affect third-party Actions or dependency installs inside Docker builds
(those use BuildKit secrets โ€” see repository Dockerfiles).

Fork PRs / missing secret

Graphiti is a public repository. Fork pull requests do not receive repository
secrets. When socket-api-key is empty, this action soft-skips: it prints a
notice, sets SOCKET_FIREWALL_ENABLED=false, and leaves package managers
unwrapped so CI still succeeds. Same-repo runs with SOCKET_API_KEY configured
get full enforcement.

API key scopes

SOCKET_API_KEY should include the Socket scopes required for Enterprise
wrapper mode (packages and entitlements:list). Configure it as a repository
Actions secret and in the development / release environments used by CI.

Docker builds

Official release workflows pass socket_api_key as a BuildKit secret so image
dependency fetches go through sfw. They also set the non-secret
SOCKET_FIREWALL_ENABLED=true build argument, which separates enforced release
layers from public fallback layers in the BuildKit cache. In enforced mode, a
missing or empty socket_api_key fails the build. Dockerfiles default the
argument to false and install directly so community docker build / Compose
usage continues to work without a Socket key.

Cache bypass on enforced builds

sfw inspects network requests, so anything served from cache is never
scanned. Two caches would otherwise hide dependencies from an enforced release
build:

  • the BuildKit layer cache, which skips the install step entirely when its
    inputs are unchanged
  • the uv cache mount, which lets uv resolve wheels from disk without
    contacting PyPI even when the step does run

Enforced builds defeat both. Release workflows pass
SOCKET_SCAN_ID=<run_id>-<run_attempt>, which is unique per run and invalidates
the install layer, and the enforced branch exports UV_NO_CACHE=1. Without
these, an image whose dependencies had not changed could ship a package that
Socket flagged after the layer was first built. Community builds leave
SOCKET_SCAN_ID empty and keep both caches, so unauthenticated builds stay
fast.


Overview (`tests/evals/data/longmemeval_data/README.md`)

The longmemeval_oracle dataset is an open-source dataset that we are using.
We did not create this dataset and it can be found
here: https://huggingface.co/datasets/xiaowu0162/longmemeval/blob/main/longmemeval_oracle.


Mcp Server Docs Cursor Rules (`mcp_server/docs/cursor_rules.md`)

Instructions for Using Graphiti's MCP Tools for Agent Memory

Before Starting Any Task

  • Always search first: Use the search_nodes tool to look for relevant preferences and procedures before beginning work.
  • Search for facts too: Use the search_facts tool to discover relationships and factual information that may be relevant to your task.
  • Filter by entity type: Specify Preference, Procedure, or Requirement in your node search to get targeted results.
  • Review all matches: Carefully examine any preferences, procedures, or facts that match your current task.

Always Save New or Updated Information

  • Capture requirements and preferences immediately: When a user expresses a requirement or preference, use add_memory to store it right away.
    • Best practice: Split very long requirements into shorter, logical chunks.
  • Be explicit if something is an update to existing knowledge. Only add what's changed or new to the graph.
  • Document procedures clearly: When you discover how a user wants things done, record it as a procedure.
  • Record factual relationships: When you learn about connections between entities, store these as facts.
  • Be specific with categories: Label preferences and procedures with clear categories for better retrieval later.

During Your Work

  • Respect discovered preferences: Align your work with any preferences you've found.
  • Follow procedures exactly: If you find a procedure for your current task, follow it step by step.
  • Apply relevant facts: Use factual information to inform your decisions and recommendations.
  • Stay consistent: Maintain consistency with previously identified preferences, procedures, and facts.

Best Practices

  • Search before suggesting: Always check if there's established knowledge before making recommendations.
  • Combine node and fact searches: For complex tasks, search both nodes and facts to build a complete picture.
  • Use center_node_uuid: When exploring related information, center your search around a specific node.
  • Prioritize specific matches: More specific information takes precedence over general information.
  • Be proactive: If you notice patterns in user behavior, consider storing them as preferences or procedures.

Remember: The knowledge graph is your memory. Use it consistently to provide personalized assistance that respects the user's established preferences, procedures, and factual context.


--- METRICS ---