Repository navigation
Description
Bug Description
The MCP server does not pass a cross_encoder argument when constructing the Graphiti client. This causes Graphiti.__init__ to always fall back to OpenAIRerankerClient(), which requires OPENAI_API_KEY. This makes it impossible to run the MCP server without an OpenAI API key, even when using Anthropic/Gemini/Groq for both LLM and embeddings.
Steps to Reproduce
Configure the MCP server to use non-OpenAI providers for both LLM and embeddings:
# config.yaml
llm:
provider: "anthropic"
model: "claude-haiku-4-5-20251001"
temperature: 0.0
providers:
anthropic:
api_key: "${ANTHROPIC_API_KEY}"
embedder:
provider: "gemini"
model: "gemini-embedding-001"
providers:
gemini:
api_key: "${GOOGLE_API_KEY}"
database:
provider: "falkordb"Start the MCP server. Both LLM and embedder clients are created successfully, but initialization crashes when Graphiti.__init__ tries to create the default OpenAIRerankerClient.
Expected Behavior
The MCP server should allow configuring the cross-encoder/reranker provider, or at minimum select a matching reranker based on the configured LLM provider.
Actual Behavior
The server crashes with:
openai.OpenAIError: The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable
Traceback:
File "/app/mcp/src/graphiti_mcp_server.py", line 225, in initialize
self.client = Graphiti(
File "/app/mcp/.venv/lib/python3.11/site-packages/graphiti_core/graphiti.py", line 224, in __init__
self.cross_encoder = OpenAIRerankerClient()
File "/app/mcp/.venv/lib/python3.11/site-packages/graphiti_core/cross_encoder/openai_reranker_client.py", line 55, in __init__
self.client = AsyncOpenAI(api_key=config.api_key, base_url=config.base_url)
openai.OpenAIError: The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable
Environment
- Graphiti Version: graphiti-core 0.28.2, MCP server 1.0.2 (Docker image
zepai/knowledge-graph-mcp:1.0.2-graphiti-0.28.2) - Python Version: 3.11
- Operating System: Docker (Debian-based)
- Database Backend: FalkorDB
- LLM Provider & Model: Anthropic claude-haiku-4-5-20251001
Installation Method
- Docker (
zepai/knowledge-graph-mcp:1.0.2-graphiti-0.28.2)
Root Cause
graphiti_mcp_server.py lines 225-231 and 233-239 construct Graphiti(...) passing llm_client and embedder but not cross_encoder:
self.client = Graphiti(
graph_driver=falkor_driver,
llm_client=llm_client,
embedder=embedder_client,
max_coroutines=self.semaphore_limit,
# cross_encoder is missing here
)Graphiti.__init__ (graphiti.py line 142) accepts an optional cross_encoder parameter, but when it's not provided, it defaults to OpenAIRerankerClient() (line 224), which unconditionally requires OPENAI_API_KEY.
Workaround
Monkey-patch Graphiti.__init__ to inject an alternative reranker before the server starts. For example, for Gemini:
import graphiti_core.graphiti as _graphiti
_orig_init = _graphiti.Graphiti.__init__
def _patched_init(self, *args, cross_encoder=None, **kwargs):
if cross_encoder is None:
from graphiti_core.cross_encoder.gemini_reranker_client import GeminiRerankerClient
cross_encoder = GeminiRerankerClient()
_orig_init(self, *args, cross_encoder=cross_encoder, **kwargs)
_graphiti.Graphiti.__init__ = _patched_initPossible Solution
graphiti-core already ships GeminiRerankerClient and BGERerankerClient alongside OpenAIRerankerClient. The MCP server could:
- Add a
reranker(orcross_encoder) section to the config schema, mirroring the existingllm/embedderpattern. - Or, as a simpler default, infer the reranker from the configured LLM provider (e.g., Anthropic/Gemini LLM →
GeminiRerankerClient, OpenAI →OpenAIRerankerClient). - Pass the resulting
cross_encoderto theGraphiti()constructor.
Related
- [BUG] - OpenAIRerankerClient / cross encoder #834 —
OpenAIRerankerClientignoring model config (closed, narrower scope) - Question: How to setup the graphiti to use my OpenRouter and Voyage? #517 — User confusion about configuring non-OpenAI providers in MCP Docker setup
Activity
winklemad commentedon Jul 8, 2026
I'd like to take this — confirmed against main. Both Graphiti() construction sites in mcp_server/src/graphiti_mcp_server.py (the FalkorDB and Neo4j branches) pass llm_client/embedder but no cross_encoder, so Graphiti.init (L224-227 in graphiti_core/graphiti.py) falls back to OpenAIRerankerClient() and needs OPENAI_API_KEY — exactly the traceback here. Since graphiti-core already ships GeminiRerankerClient and BGERerankerClient, this is pure wiring. My plan: default to your option 2 — infer the reranker from the configured LLM provider via the existing factory in services/factories.py (OpenAI→OpenAIReranker, Anthropic/Gemini→GeminiReranker, etc.) — plus an optional explicit reranker config block (option 1) for override, threaded into both Graphiti() calls. Tests: a factory unit test + a boot test asserting the server starts on a non-OpenAI config without OPENAI_API_KEY. Does "infer-by-default + optional explicit config" match what you'd want, or would you rather I ship just the explicit config block first?
fix(mcp): configure cross-encoder from providers instead of hardcoded…