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:textdocker run -p 6379:6379 -p 3000:3000 -it --rm falkordb/falkordb:latest
pip install graphiti-coreor
uv add graphiti-coreInstalling with FalkorDB Support
If you plan to use FalkorDB as your graph database backend, install with the FalkorDB extra:
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 aDeprecationWarning.
If you plan to use Kuzu as your graph database backend, install with the Kuzu extra:
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:
pip install graphiti-core[neptune]
# or with uv
uv add graphiti-core[neptune]You can also install optional LLM providers as extras:
# 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 anOPENAI_API_KEYis 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:
- Connecting to a Neo4j, Amazon Neptune, FalkorDB, or Kuzu database
- Initializing Graphiti indices and constraints
- Adding episodes to the graph (both text and structured JSON)
- Searching for relationships (edges) using hybrid search
- Reranking search results using graph distance
- 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:
bashdocker compose upThis will start the Neo4j Docker service and related components.
FalkorDB Docker:
bashdocker compose --profile falkordb upThis 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-corelibrary 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
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
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.
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
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
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 OpenAIKey Points:
- Use the standard
AsyncOpenAIclient 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:
uv add "graphiti-core[google-genai]"
# or
pip install "graphiti-core[google-genai]"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 componentsThe 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:
ollama pull deepseek-r1:7b # LLM
ollama pull nomic-embed-text # embeddingsfrom 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 modelsEnsure 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 viaresponse_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 honorjson_schemaโ including some local servers that accept thejson_schema
request but don't actually constrain output to it, wherejson_objectcan 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
```jsoncode fences are stripped automatically. - Keep
SEMAPHORE_LIMITlow (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 returnChatPrompt (system + user). Response schemas are fixed and not overridable:
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 raisesTypeError โ 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 andDefaultChatPromptLibrary.
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:
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 passesmodel_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 withoutllm_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. SetJEV_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 onlydedupe_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.
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. */
export GRAPHITI_TELEMETRY_ENABLED=falseOption 2: Set in your shell profile
# For bash users (~/.bashrc or ~/.bash_profile)
echo 'export GRAPHITI_TELEMETRY_ENABLED=false' >> ~/.bashrc
# For zsh users (~/.zshrc)
echo 'export GRAPHITI_TELEMETRY_ENABLED=false' >> ~/.zshrcOption 3: Set for a specific Python session
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
git clone https://github.com/getzep/graphiti.gitor
gh repo clone getzep/graphitiFor Claude Desktop and other `stdio` only clients
- Note the full path to this directory.
cd graphiti && pwdInstall the Graphiti prerequisites.
Configure Claude, Cursor, or other MCP client to use Graphiti with a
stdiotransport. See the client documentation on where to find their MCP configuration files.
For Cursor and other HTTP-enabled clients
- Change directory to the
mcp_serverdirectory
cd graphiti/mcp_server
- Start the combined FalkorDB + MCP server using Docker Compose (recommended)
docker compose upThis starts both FalkorDB and the MCP server in a single container.
Alternative: Run with separate containers using Neo4j:
docker compose -f docker/docker-compose-neo4j.yml up- Point your MCP client to
http://localhost:8000/mcp/
Installation
Prerequisites
- Docker and Docker Compose (for the default FalkorDB setup)
- OpenAI API key for LLM operations (or API keys for other supported LLM providers)
- (Optional) Python 3.10+ if running the MCP server standalone with an external FalkorDB instance
Setup
- Clone the repository and navigate to the mcp_server directory
- Use
uvto create a virtual environment and install dependencies:
# 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 providersConfiguration
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.
database:
provider: "falkordb" # Default
providers:
falkordb:
uri: "redis://localhost:6379"
password: "" # Optional
database: "default_db" # OptionalNeo4j
When you need a full-featured graph database, Neo4j is recommended:
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:
database:
provider: "falkordb"
providers:
falkordb:
uri: "redis://localhost:6379"
password: "" # Optional
database: "default_db" # OptionalConfiguration File (config.yaml)
The server supports multiple LLM providers (OpenAI, Anthropic, Gemini, Groq) and embedders. Edit config.yaml to configure:
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:
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 thestructured_output_mode(json_schemavsjson_object) trade-off, see the core README's
Structured output and small models section.
If an OpenAI-compatible endpoint acceptsjson_schemabut returns objects that miss fields such asextracted_entities, setstructured_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:
graphiti:
entity_types:
- name: "Preference"
- name: "Requirement"
# ... additional entity typesThe 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 defaultconfig.yamlenables them, so an existing deployment on the default config switches from attribute-free to rich-attribute extraction. To keep the previous behavior, setgraphiti.entity_typesto 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 keyAZURE_OPENAI_ENDPOINT: Azure OpenAI endpoint URLAZURE_OPENAI_DEPLOYMENT: Azure OpenAI deployment nameAZURE_OPENAI_EMBEDDINGS_ENDPOINT: Optional Azure OpenAI embeddings endpoint URLAZURE_OPENAI_EMBEDDINGS_DEPLOYMENT: Optional Azure OpenAI embeddings deployment nameAZURE_OPENAI_API_VERSION: Optional Azure OpenAI API versionUSE_AZURE_AD: Optional use Azure Managed Identities for authenticationSEMAPHORE_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:
docker compose upThis 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:
# This starts both Neo4j and the MCP server
docker compose -f docker/docker-compose.neo4j.yaml upOption 2: Direct Execution with Existing Neo4j
If you have Neo4j already running:
# 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 neo4jOr use the Neo4j configuration file:
uv run main.py --config config/config-docker-neo4j.yamlRunning with FalkorDB
Option 1: Using Docker Compose
# This starts both FalkorDB (Redis-based) and the MCP server
docker compose -f docker/docker-compose.falkordb.yaml upOption 2: Direct Execution with Existing FalkorDB
# Set environment variables
export FALKORDB_URI="redis://localhost:6379"
export FALKORDB_PASSWORD="" # If password protected
# Run with FalkorDB
uv run main.py --database-provider falkordbOr use the FalkorDB configuration file:
uv run main.py --config config/config-docker-falkordb.yamlAvailable 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
429rate 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:
SEMAPHORE_LIMIT=10 # Adjust based on your LLM provider tierDocker 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):
Create a .env file in the mcp_server directory:
bashcd graphiti/mcp_server cp .env.example .envEdit 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:
cd graphiti/mcp_serverOption 1: FalkorDB Combined Container (Default)
Single container with both FalkorDB and MCP server - simplest option:
docker compose upOption 2: Neo4j Database
Separate containers with Neo4j and MCP server:
docker compose -f docker/docker-compose-neo4j.yml upDefault 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:
docker compose -f docker/docker-compose-falkordb.yml upFalkorDB 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:
# 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):
{
"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,uvinstalled. Please refer to theuvinstall instructions.Ensure that you set the full path to the
uvbinary and your Graphiti project folder.
{
"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:
{
"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-temporalreference_time,excluded_entity_types,custom_extraction_instructions,previous_episode_uuids,update_communities, andsaga/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; supportsentity_typesandcenter_node_uuid.search_memory_facts: Search for relevant facts (edges); supportsedge_types,center_node_uuid,
andvalid_at/invalid_atdate-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 optionalgroup_id; defaults to the configured group.delete_entity_edge: Delete an entity edge from the knowledge graph.
Accepts an optionalgroup_id; defaults to the configured group.delete_episode: Delete an episode and cascade-delete the entities/facts it solely created.
Accepts an optionalgroup_id; defaults to the configured group.get_entity_edge: Get an entity edge by its UUID. Accepts an optionalgroup_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 withadd_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:
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:
- Run the Graphiti MCP server using the default HTTP transport:
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
docker compose up- Configure Cursor to connect to the Graphiti MCP server.
{
"mcpServers": {
"graphiti-memory": {
"url": "http://localhost:8000/mcp/"
}
}
}Add the Graphiti rules to Cursor's User Rules. See cursor_rules.md for details.
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.
Run the Graphiti MCP server:
bashdocker compose up # Or run directly with uv: uv run main.py(Optional) Install
mcp-remoteglobally:
If you prefer to havemcp-remoteinstalled globally, or if you encounter issues withnpxfetching the package, you can install it globally. Otherwise,npx(used in the next step) will handle it for you.bashnpm install mcp-remoteConfigure Claude Desktop:
Open your Claude Desktop configuration file (usuallyclaude_desktop_config.json) and add or modify themcpServerssection 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
mcpServersentry, addgraphiti-memory(or your chosen name) as a new key within it.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:
export GRAPHITI_TELEMETRY_ENABLED=falseOr add it to your .env file:
GRAPHITI_TELEMETRY_ENABLED=falseFor 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 release0.30.2- Specific version (matches graphiti-core version)
Platforms: linux/amd64, linux/arm64
The automated release workflow:
- Triggers on
v*.*.*tag pushes (and can be run manually viaworkflow_dispatch) - Waits for that
graphiti-coreversion to be available on PyPI - Builds multi-platform Docker image
- Tags with version number and
latest - Pushes to Docker Hub
Only stable releases are built automatically (pre-release versions are skipped).
Running Instructions
Ensure you have Docker and Docker Compose installed on your system.
Add
zepai/graphiti:latestto your service setupMake sure to pass the following environment variables to the service
textOPENAI_API_KEY=your_openai_api_key NEO4J_USER=your_neo4j_user NEO4J_PASSWORD=your_neo4j_password NEO4J_PORT=your_neo4j_portThis 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:
ymlversion: '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:Once you start the service, it will be available at
http://localhost:8000(or the port you have specified in the docker compose file).You may access the swagger docs at
http://localhost:8000/docs. You may also access redocs athttp://localhost:8000/redoc.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
Create the labels (required before the issue forms or bot run โ GitHub
silently drops form labels that do not exist):bashbash .github/scripts/setup-triage-labels.sh(Optional) repository variable to disable intake without editing code:
Variable Default Purpose INTAKE_ENABLEDunset (enabled) Set to falseto 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 issuethenapply.py --write..github/workflows/pr-intake.ymlโ on PR open/sync/reopen/edit, for
same-repo and fork branches. It usespull_request_targetso 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 (thegithub/ai-moderatoraction)..github/workflows/stale.ymlโ daily; warns then closes items that keep
anyneeds-*label (needs-info,needs-issue,needs-rfc,needs-tests,needs-rework) for 14 days.rfc-approvedandsecurityitems 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 ofbug,feature,documentation,question
already on the issue (the form sets it), elseother.areas: from theAffected component(orComponent) 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; adocumentationissue with no scope defaults toscope:docs.Required sections (missing ones produce
needs-infoand land inmissing_fields):Category Required bug description, reproduction, expected, actual, environment feature problem, outcome question goal, attempted, environment documentation location, problem needs-rfc: a feature whoseSizeisLarge feature requiring design approvalgetsneeds-rfcunless the issue already hasrfc-approved, andproposal/alternatives/impactbecome required as well.comment_id:ask_rfc_fieldswhenneeds-rfc;ask_reprofor a bug
missing fields;ask_infofor anything else missing fields; else none.
Pull request rules
areas: derived from the changed file paths (seePATH_SCOPE_RULES).needs-issue: no linked issue (Fixes #<number>) โneeds-issueand
thelinked-issuemissing field. A number that 404s or resolves to a pull
request does not count.category:feature/bug/documentationwhen a linked issue carries
that label, elsefeaturewhen the template's Feature checkbox is ticked,
elseother.needs-rfc: a feature PR whose linked issue lacksrfc-approved.needs-tests: the diff touches code but no test file, and theTests are not applicablecheckbox is not ticked.needs-rework:needs-issueandneeds-teststogether.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 intest_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
uv sync2. Configure Environment Variables
Copy the .env.example file to .env and fill in your credentials:
cd examples/azure-openai
cp .env.example .envEdit .env with your actual values:
# 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-small3. Azure OpenAI Model Deployments
This example requires two Azure OpenAI model deployments:
Chat Completion Model: Used for entity extraction and relationship analysis
- Set the deployment name in
AZURE_OPENAI_DEPLOYMENT
- Set the deployment name in
Embedding Model: Used for semantic search
- Set the deployment name in
AZURE_OPENAI_EMBEDDING_DEPLOYMENT
- Set the deployment name in
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
.envfile
Running the Example
cd examples/azure-openai
uv run azure_openai_neo4j.pyWhat This Example Does
- Initialization: Sets up connections to Neo4j and Azure OpenAI
- Adding Episodes: Ingests text and JSON data about California politics
- Basic Search: Performs hybrid search combining semantic similarity and BM25 retrieval
- Center Node Search: Reranks results based on graph distance to a specific node
- 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:
# 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
Hybrid Search
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://orneo4j://)
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
Related Examples
examples/quickstart/- Basic Graphiti usage with OpenAIexamples/podcast/- Processing longer contentexamples/ecommerce/- Domain-specific knowledge graphs
Overview (`examples/gliner2/README.md`)
GLiNER2 Hybrid LLM Client Example (Experimental)
Note: The
GLiNER2Clientis 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.
- Paper: GLiNER2: An Efficient Multi-Task Information Extraction System with Schema-Driven Interface
- Models on HuggingFace:
- fastino/gliner2-base-v1 (205M params)
- fastino/gliner2-large-v1 (340M params)
- fastino/gliner2-multi-v1 (multilingual)
Prerequisites
- Python 3.11+
- Neo4j 5.26+ (Neo4j Desktop or Docker)
- An LLM provider API key (Google, OpenAI, Anthropic, etc.)
Setup
# Install graphiti with the gliner2 extra
pip install graphiti-core[gliner2]
# Copy and configure environment variables
cp .env.example .envThe 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.OpenAIClientgraphiti_core.llm_client.anthropic_client.AnthropicClientgraphiti_core.llm_client.groq_client.GroqClientgraphiti_core.embedder.openai.OpenAIEmbeddergraphiti_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
python gliner2_neo4j.pyOverview (`examples/jev/README.md`)
Jev dedupe with FalkorDB
This example routes node deduplication and edge resolution to Jev. OpenAIgpt-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:
docker run -p 6379:6379 falkordb/falkordb:latestCopy .env.example to .env and set both API keys. The example useslocalhost: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 onlydedupe_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 withinvalid_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 2dedupe_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:
uv sync --extra devThen run the example from this directory:
cd examples/jev
uv run python jev_dedupe_falkordb.pyThe 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:
docker run -p 6379:6379 falkordb/falkordb:latestCopy .env.example to .env and set the API key. The example useslocalhost: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 withinvalid_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 3dedupe_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:
uv sync --extra devThen run the example from this directory:
cd examples/openai_decisions
uv run python openai_decisions_dedupe_falkordb.pyThe 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
uv sync
export OPENAI_API_KEY=your_api_key_here
uv run otel_stdout_example.pyConfigure OpenTelemetry with Graphiti
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:
- Connecting to a Neo4j or FalkorDB database
- Initializing Graphiti indices and constraints
- Adding episodes to the graph
- Searching the graph with semantic and keyword matching
- Exploring graph-based search with reranking using the top search result's source node UUID
- Performing node search using predefined search recipes
Prerequisites
- Python 3.9+
- OpenAI API key (set as
OPENAI_API_KEYenvironment variable) - For Neo4j:
- Neo4j Desktop installed and running
- A local DBMS created and started in Neo4j Desktop
- For FalkorDB:
- FalkorDB server running (see FalkorDB documentation for setup)
- For Amazon Neptune:
- Amazon server running (see Amazon Neptune documentation for setup)
Setup Instructions
- Install the required dependencies:
pip install graphiti-core- Set up environment variables:
# 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 scriptTIP: For Amazon Neptune host string please use the following formats
- For Neptune Database:
neptune-db://<cluster endpoint> - For Neptune Analytics:
neptune-graph://<graph identifier>
- Run the example:
python quickstart_neo4j.py
# For FalkorDB
python quickstart_falkordb.py
# For Amazon Neptune
python quickstart_neptune.pyWhat 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:
- Modify the episode content to add your own information
- Try different search queries to explore the knowledge extraction
- Experiment with different center nodes for graph-distance-based reranking
- Try other predefined search recipes from
graphiti_core.search.search_config_recipes - 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:
# 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
# Default configuration (FalkorDB combined image)
docker-compose up
# Neo4j (separate containers)
docker-compose -f docker-compose-neo4j.yml upEnvironment Variables
Create a .env file in this directory with your API keys:
# 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
# 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
- FalkorDB (Redis): redis://localhost:6379
- FalkorDB Web UI: http://localhost:3000
- MCP Server: http://localhost:8000
Data Management
Backup:
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:
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/dataClear Data:
docker-compose down
docker volume rm mcp_server_falkordb_data
docker-compose upGotchas
- 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
# 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
- Web Interface: http://localhost:7474
- Bolt Protocol: bolt://localhost:7687
- MCP Server: http://localhost:8000
Default credentials: neo4j / demodemo
Data Management
Backup:
# 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:
# 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 /logsClear Data:
docker-compose -f docker-compose-neo4j.yml down
docker volume rm docker_neo4j_data docker_neo4j_logs
docker-compose -f docker-compose-neo4j.yml upGotchas
- 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):
Stop current setup:
bashdocker-compose down # Stop FalkorDB combined image # or docker-compose -f docker-compose-neo4j.yml down # Stop Neo4jStart new database:
bashdocker-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:
# 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
Check logs:
bashdocker-compose logs graphiti-mcpVerify
.envfile exists and contains valid API keys:bashcat .env | grep API_KEYEnsure 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
Verify volumes are created:
bashdocker volume ls | grep docker_Check volume mounts in container:
bashdocker inspect graphiti-mcp | grep -A 5 MountsEnsure proper shutdown:
bashdocker-compose down # Not docker-compose down -v (which removes volumes)
Performance Issues
FalkorDB:
- Adjust
SEMAPHORE_LIMITenvironment 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:
services:
graphiti-mcp:
deploy:
resources:
limits:
cpus: '2.0'
memory: 1GConfiguration Files
Each database has a dedicated configuration file in ../config/:
config-docker-falkordb-combined.yaml- FalkorDB combined image configurationconfig-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 toolstest_async_operations.py- Tests for concurrent operations and async patternstest_stress_load.py- Stress testing and load testing scenariostest_fixtures.py- Shared fixtures and test utilitiestest_mcp_integration.py- Original MCP integration teststest_configuration.py- Configuration loading and validation tests
Test Categories
Tests are organized with pytest markers:
unit- Fast unit tests without external dependenciesintegration- Tests requiring database and servicesslow- Long-running tests (stress/load tests)requires_neo4j- Tests requiring Neo4jrequires_falkordb- Tests requiring FalkorDBrequires_openai- Tests requiring OpenAI API key
Installation
# Install test dependencies
uv add --dev pytest pytest-asyncio pytest-timeout pytest-xdist faker psutil
# Install MCP SDK
uv add mcpRunning Tests
Quick Start
# 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 allTest Runner Options
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 prerequisitesExamples
# 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-onlyTest 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
# 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=INFOpytest.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:
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:
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:
- Configurable timeouts - Different timeouts for different operations
- Mock LLM option - Fast testing without API calls
- Intelligent polling - Adaptive waiting for episode processing
- 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
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
Database connection failures
bash# Check Neo4j curl http://localhost:7474 # Check FalkorDB redis-cli pingAPI key issues
bash# Use mock LLM for testing without API key python tests/run_tests.py all --mock-llmTimeout errors
bash# Increase timeout for slow systems python tests/run_tests.py integration --timeout 600Memory 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:
from test_fixtures import PerformanceBenchmark
benchmark = PerformanceBenchmark()
# ... run tests ...
print(benchmark.report())Load Test Report
Stress tests generate detailed reports:
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.2sContributing
When adding new tests:
- Use appropriate pytest markers
- Include docstrings explaining test purpose
- Use fixtures for common operations
- Consider LLM latency in test design
- Add timeout handling for long operations
- 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
- 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
sfwbinary when needed - exports
SOCKET_API_KEYandSFW_TELEMETRY_DISABLED=true - configures
SFW_CUSTOM_REGISTRIESwith wrap hosts (includingfiles.pythonhosted.orgfor PyPI artifact downloads) - writes a
BASH_ENVfile 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-secretSOCKET_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
uvcache mount, which letsuvresolve wheels from disk without
contacting PyPI even when the step does run
Enforced builds defeat both. Release workflows passSOCKET_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 leaveSOCKET_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_nodestool to look for relevant preferences and procedures before beginning work. - Search for facts too: Use the
search_factstool to discover relationships and factual information that may be relevant to your task. - Filter by entity type: Specify
Preference,Procedure, orRequirementin 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_memoryto 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 ---
- Files Extracted: 15
- Estimated Token Budget: ~25963 tokens
- Canonical Reference: https://codewiki.google/github.com/getzep/graphiti