Skip to content

Commit 9814aac

Browse files
committed
Neptune MCP Support
1 parent 352977a commit 9814aac

File tree

11 files changed

+967
-30
lines changed

11 files changed

+967
-30
lines changed

‎mcp_server/config/config.yaml‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ embedder:
7171
model: "voyage-3"
7272

7373
database:
74-
provider: "falkordb" # Default: falkordb. Options: neo4j, falkordb
74+
provider: "falkordb" # Default: falkordb. Options: neo4j, falkordb, neptune
7575

7676
providers:
7777
falkordb:
@@ -86,6 +86,13 @@ database:
8686
database: ${NEO4J_DATABASE:neo4j}
8787
use_parallel_runtime: ${USE_PARALLEL_RUNTIME:false}
8888

89+
neptune:
90+
host: ${NEPTUNE_HOST:neptune-db://localhost}
91+
aoss_host: ${AOSS_HOST}
92+
port: ${NEPTUNE_PORT:8182}
93+
aoss_port: ${AOSS_PORT:443}
94+
region: ${AWS_REGION:}
95+
8996
graphiti:
9097
group_id: ${GRAPHITI_GROUP_ID:main}
9198
episode_id_prefix: ${EPISODE_ID_PREFIX:}

‎mcp_server/docker/Dockerfile‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,17 @@ ENV UV_COMPILE_BYTECODE=1 \
3333
WORKDIR /app/mcp
3434

3535
# Accept graphiti-core version as build argument
36-
ARG GRAPHITI_CORE_VERSION=0.23.1
36+
ARG GRAPHITI_CORE_VERSION=0.24.1
3737

3838
# Copy project files for dependency installation
3939
COPY pyproject.toml uv.lock ./
4040

4141
# Remove the local path override for graphiti-core in Docker builds
42+
# Install with falkordb and neptune extras for maximum flexibility
4243
# and regenerate lock file to match the PyPI version
4344
RUN sed -i '/\[tool\.uv\.sources\]/,/graphiti-core/d' pyproject.toml && \
4445
if [ -n "${GRAPHITI_CORE_VERSION}" ]; then \
45-
sed -i "s/graphiti-core\[falkordb\]>=[0-9]\+\.[0-9]\+\.[0-9]\+$/graphiti-core[falkordb]==${GRAPHITI_CORE_VERSION}/" pyproject.toml; \
46+
sed -i "s/graphiti-core\[falkordb\]>=[0-9]\+\.[0-9]\+\.[0-9]\+$/graphiti-core[falkordb,neptune]==${GRAPHITI_CORE_VERSION}/" pyproject.toml; \
4647
fi && \
4748
echo "Regenerating lock file for PyPI graphiti-core..." && \
4849
rm -f uv.lock && \
@@ -112,7 +113,7 @@ EOF
112113
RUN chmod +x /start-services.sh
113114

114115
# Add Docker labels with version information
115-
ARG MCP_SERVER_VERSION=1.0.1
116+
ARG MCP_SERVER_VERSION=1.0.2
116117
ARG BUILD_DATE
117118
ARG VCS_REF
118119
LABEL org.opencontainers.image.title="FalkorDB + Graphiti MCP Server" \

‎mcp_server/docker/Dockerfile.standalone‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ ENV UV_COMPILE_BYTECODE=1 \
2828
WORKDIR /app/mcp
2929

3030
# Accept graphiti-core version as build argument
31-
ARG GRAPHITI_CORE_VERSION=0.23.1
31+
ARG GRAPHITI_CORE_VERSION=0.24.1
3232

3333
# Copy project files for dependency installation
3434
COPY pyproject.toml uv.lock ./
3535

3636
# Remove the local path override for graphiti-core in Docker builds
37-
# Install with BOTH neo4j and falkordb extras for maximum flexibility
37+
# Install with neo4j, falkordb, and neptune extras for maximum flexibility
3838
# and regenerate lock file to match the PyPI version
3939
RUN sed -i '/\[tool\.uv\.sources\]/,/graphiti-core/d' pyproject.toml && \
40-
sed -i "s/graphiti-core\[falkordb\]>=[0-9]\+\.[0-9]\+\.[0-9]\+$/graphiti-core[neo4j,falkordb]==${GRAPHITI_CORE_VERSION}/" pyproject.toml && \
40+
sed -i "s/graphiti-core\[falkordb\]>=[0-9]\+\.[0-9]\+\.[0-9]\+$/graphiti-core[neo4j,falkordb,neptune]==${GRAPHITI_CORE_VERSION}/" pyproject.toml && \
4141
echo "Regenerating lock file for PyPI graphiti-core..." && \
4242
rm -f uv.lock && \
4343
uv lock
@@ -58,7 +58,7 @@ COPY config/ ./config/
5858
RUN mkdir -p /var/log/graphiti
5959

6060
# Add Docker labels with version information
61-
ARG MCP_SERVER_VERSION=1.0.1
61+
ARG MCP_SERVER_VERSION=1.0.2
6262
ARG BUILD_DATE
6363
ARG VCS_REF
6464
LABEL org.opencontainers.image.title="Graphiti MCP Server (Standalone)" \

‎mcp_server/pyproject.toml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
[project]
22
name = "mcp-server"
3-
version = "1.0.1"
3+
version = "1.0.2"
44
description = "Graphiti MCP Server"
55
readme = "README.md"
66
requires-python = ">=3.10,<4"
77
dependencies = [
88
"mcp>=1.9.4",
99
"openai>=1.91.0",
10-
"graphiti-core[falkordb]>=0.23.1",
10+
"graphiti-core[falkordb,neptune]>=0.23.1",
1111
"pydantic-settings>=2.0.0",
1212
"pyyaml>=6.0",
1313
"typing-extensions>=4.0.0",

‎mcp_server/src/config/schema.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,42 @@ class FalkorDBProviderConfig(BaseModel):
191191
database: str = 'default_db'
192192

193193

194+
class NeptuneProviderConfig(BaseModel):
195+
"""Neptune provider configuration."""
196+
197+
host: str = 'neptune-db://localhost'
198+
aoss_host: str | None = None
199+
port: int = Field(default=8182, ge=1, le=65535)
200+
aoss_port: int = Field(default=443, ge=1, le=65535)
201+
region: str | None = None
202+
203+
def model_post_init(self, __context) -> None:
204+
"""Validate Neptune-specific requirements."""
205+
if not self.host.startswith(('neptune-db://', 'neptune-graph://')):
206+
raise ValueError(
207+
'Neptune host must start with neptune-db:// or neptune-graph://\n'
208+
'Examples:\n'
209+
' - Database: neptune-db://my-cluster.us-east-1.neptune.amazonaws.com\n'
210+
' - Analytics: neptune-graph://g-abc123xyz'
211+
)
212+
213+
if not self.aoss_host:
214+
raise ValueError(
215+
'Neptune requires aoss_host for full-text search.\n'
216+
'Set AOSS_HOST environment variable or add to config:\n'
217+
' database:\n'
218+
' providers:\n'
219+
' neptune:\n'
220+
' aoss_host: "your-aoss-endpoint.us-east-1.aoss.amazonaws.com"'
221+
)
222+
223+
194224
class DatabaseProvidersConfig(BaseModel):
195225
"""Database providers configuration."""
196226

197227
neo4j: Neo4jProviderConfig | None = None
198228
falkordb: FalkorDBProviderConfig | None = None
229+
neptune: NeptuneProviderConfig | None = None
199230

200231

201232
class DatabaseConfig(BaseModel):

‎mcp_server/src/graphiti_mcp_server.py‎

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,23 @@ async def initialize(self) -> None:
228228
embedder=embedder_client,
229229
max_coroutines=self.semaphore_limit,
230230
)
231+
elif self.config.database.provider.lower() == 'neptune':
232+
# For Neptune, create a NeptuneDriver instance directly
233+
from graphiti_core.driver.neptune_driver import NeptuneDriver
234+
235+
neptune_driver = NeptuneDriver(
236+
host=db_config['host'],
237+
aoss_host=db_config['aoss_host'],
238+
port=db_config['port'],
239+
aoss_port=db_config['aoss_port'],
240+
)
241+
242+
self.client = Graphiti(
243+
graph_driver=neptune_driver,
244+
llm_client=llm_client,
245+
embedder=embedder_client,
246+
max_coroutines=self.semaphore_limit,
247+
)
231248
else:
232249
# For Neo4j (default), use the original approach
233250
self.client = Graphiti(
@@ -266,6 +283,25 @@ async def initialize(self) -> None:
266283
f' - Or run Neo4j manually: docker run -p 7474:7474 -p 7687:7687 neo4j:latest\n\n'
267284
f'{"=" * 70}\n'
268285
) from db_error
286+
elif db_provider.lower() == 'neptune':
287+
raise RuntimeError(
288+
f'\n{"=" * 70}\n'
289+
f'Database Connection Error: Neptune is not accessible\n'
290+
f'{"=" * 70}\n\n'
291+
f'Neptune: {db_config.get("host", "unknown")}\n'
292+
f'OpenSearch: {db_config.get("aoss_host", "unknown")}\n\n'
293+
f'Troubleshooting:\n'
294+
f' 1. Verify Neptune endpoint format (neptune-db:// or neptune-graph://)\n'
295+
f' 2. Check AWS credentials: aws sts get-caller-identity\n'
296+
f' 3. Verify security groups allow access\n'
297+
f' 4. Confirm OpenSearch Serverless endpoint is accessible\n'
298+
f' 5. Check IAM permissions (neptune-db:*, aoss:*, neptune-graph:*)\n\n'
299+
f'AWS Setup:\n'
300+
f' - Region: {db_config.get("region", "not set")}\n'
301+
f' - Run: aws neptune describe-db-clusters (for Database)\n'
302+
f' - Run: aws neptune-graph list-graphs (for Analytics)\n\n'
303+
f'{"=" * 70}\n'
304+
) from db_error
269305
else:
270306
raise RuntimeError(
271307
f'\n{"=" * 70}\n'
@@ -806,7 +842,7 @@ async def initialize_server() -> ServerConfig:
806842
)
807843
parser.add_argument(
808844
'--database-provider',
809-
choices=['neo4j', 'falkordb'],
845+
choices=['neo4j', 'falkordb', 'neptune'],
810846
help='Database provider to use',
811847
)
812848

‎mcp_server/src/services/factories.py‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@
1616
except ImportError:
1717
HAS_FALKOR = False
1818

19+
# Try to import NeptuneDriver if available
20+
try:
21+
from graphiti_core.driver.neptune_driver import NeptuneDriver # noqa: F401
22+
23+
HAS_NEPTUNE = True
24+
except ImportError:
25+
HAS_NEPTUNE = False
26+
1927
# Kuzu support removed - FalkorDB is now the default
2028
from graphiti_core.embedder import EmbedderClient, OpenAIEmbedder
2129
from graphiti_core.llm_client import LLMClient, OpenAIClient
@@ -433,5 +441,76 @@ def create_config(config: DatabaseConfig) -> dict:
433441
'database': falkor_config.database,
434442
}
435443

444+
case 'neptune':
445+
if not HAS_NEPTUNE:
446+
raise ValueError(
447+
'Neptune driver not available. Install with:\n'
448+
' pip install graphiti-core[neptune]\n'
449+
'or:\n'
450+
' uv add graphiti-core[neptune]'
451+
)
452+
453+
# Validate AWS credentials early
454+
import boto3
455+
456+
try:
457+
session = boto3.Session()
458+
credentials = session.get_credentials()
459+
if not credentials:
460+
raise ValueError(
461+
'AWS credentials not configured for Neptune.\n'
462+
'Configure using one of:\n'
463+
' 1. AWS CLI: aws configure\n'
464+
' 2. Environment: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY\n'
465+
' 3. IAM role (if running on AWS)\n'
466+
' 4. Credentials file: ~/.aws/credentials'
467+
)
468+
469+
region = session.region_name
470+
if not region:
471+
import logging
472+
473+
logger = logging.getLogger(__name__)
474+
logger.warning('AWS region not detected, using default from config')
475+
except Exception as e:
476+
raise ValueError(f'AWS credential error: {e}') from e
477+
478+
# Load Neptune config
479+
if config.providers.neptune:
480+
neptune_config = config.providers.neptune
481+
else:
482+
from config.schema import NeptuneProviderConfig
483+
484+
neptune_config = NeptuneProviderConfig()
485+
486+
# Environment overrides
487+
import os
488+
489+
host = os.environ.get('NEPTUNE_HOST', neptune_config.host)
490+
aoss_host = os.environ.get('AOSS_HOST', neptune_config.aoss_host)
491+
port = int(os.environ.get('NEPTUNE_PORT', str(neptune_config.port)))
492+
aoss_port = int(os.environ.get('AOSS_PORT', str(neptune_config.aoss_port)))
493+
region_override = os.environ.get('AWS_REGION', region or neptune_config.region)
494+
495+
if not aoss_host:
496+
raise ValueError(
497+
'Neptune requires AOSS_HOST for full-text search.\n'
498+
'Set it in config or environment variable.'
499+
)
500+
501+
import logging
502+
503+
logger = logging.getLogger(__name__)
504+
logger.info(f'Creating Neptune driver for {host} with region {region_override}')
505+
506+
return {
507+
'driver': 'neptune',
508+
'host': host,
509+
'aoss_host': aoss_host,
510+
'port': port,
511+
'aoss_port': aoss_port,
512+
'region': region_override,
513+
}
514+
436515
case _:
437516
raise ValueError(f'Unsupported Database provider: {provider}')

‎mcp_server/tests/test_configuration.py‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
import sys
77
from pathlib import Path
88

9-
# Add the current directory to the path
10-
sys.path.insert(0, str(Path(__file__).parent.parent / 'src'))
11-
129
from config.schema import GraphitiConfig
1310
from services.factories import DatabaseDriverFactory, EmbedderFactory, LLMClientFactory
1411

0 commit comments

Comments
 (0)