Skip to content

Neo4J-Memory SSE Support #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions servers/mcp-neo4j-memory/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ RUN pip install --no-cache-dir hatchling
COPY pyproject.toml /app/

# Install runtime dependencies
RUN pip install --no-cache-dir mcp>=0.10.0 neo4j>=5.26.0
RUN pip install --no-cache-dir mcp>=0.10.0 neo4j>=5.26.0 fastapi uvicorn

# Copy the source code
COPY src/ /app/src/
Expand All @@ -22,7 +22,13 @@ RUN pip install --no-cache-dir -e .
# Environment variables for Neo4j connection
ENV NEO4J_URL="bolt://host.docker.internal:7687"
ENV NEO4J_USERNAME="neo4j"
ENV NEO4J_PASSWORD="password"
ENV NEO4J_PASSWORD="neo4j_password"

# Set transport type (can be "sse" or "stdio")
ENV MCP_TRANSPORT="sse"

# Expose port for SSE transport
EXPOSE 8090

# Command to run the server using the package entry point
CMD ["sh", "-c", "mcp-neo4j-memory --db-url ${NEO4J_URL} --username ${NEO4J_USERNAME} --password ${NEO4J_PASSWORD}"]
CMD ["python", "-m", "src.mcp_neo4j_memory.main"]
5 changes: 3 additions & 2 deletions servers/mcp-neo4j-memory/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
[project]
name = "mcp-neo4j-memory"
version = "0.1.3"
version = "0.1.1"
description = "MCP Neo4j Knowledge Graph Memory Server"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"mcp>=0.10.0",
"neo4j>=5.26.0",
"fastapi"
]

[build-system]
Expand All @@ -21,7 +22,7 @@ dev-dependencies = [
]

[project.scripts]
mcp-neo4j-memory = "mcp_neo4j_memory:main"
mcp-neo4j-memory = "mcp_neo4j_memory.main:main"

[tool.pytest.ini_options]
pythonpath = [
Expand Down
6 changes: 3 additions & 3 deletions servers/mcp-neo4j-memory/src/mcp_neo4j_memory/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ def main():
"""Main entry point for the package."""
parser = argparse.ArgumentParser(description='Neo4j Cypher MCP Server')
parser.add_argument('--db-url',
default=os.getenv("NEO4J_URL", "bolt://localhost:7687"),
default="bolt://localhost:7687",
help='Neo4j connection URL')
parser.add_argument('--username',
default=os.getenv("NEO4J_USERNAME", "neo4j"),
default="neo4j",
help='Neo4j username')
parser.add_argument('--password',
default=os.getenv("NEO4J_PASSWORD", "password"),
default="password",
help='Neo4j password')

args = parser.parse_args()
Expand Down
79 changes: 79 additions & 0 deletions servers/mcp-neo4j-memory/src/mcp_neo4j_memory/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import logging
import os

from fastapi import FastAPI

from src.mcp_neo4j_memory.server import create_mcp_server
from src.mcp_neo4j_memory.transport import TransportLayer

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("mcp_neo4j_memory")


async def start_server(transport_type="sse"):
"""Start the MCP server with the specified transport"""
# Get environment variables for Neo4j connection
neo4j_uri = os.environ.get(
"NEO4J_URI", os.environ.get("NEO4J_URL", "bolt://host.docker.internal:7687")
)
neo4j_user = os.environ.get("NEO4J_USERNAME", os.environ.get("NEO4J_USER", "neo4j"))
neo4j_password = os.environ.get("NEO4J_PASSWORD", "neo4j_password")

try:
# Create the MCP server
logger.info(f"Creating MCP server with transport type: {transport_type}")
mcp_server = await create_mcp_server(neo4j_uri, neo4j_user, neo4j_password)

# Create transport and run server
transport = TransportLayer.create_transport(transport_type)
return await transport.run_server(mcp_server)
except Exception as e:
logger.error(f"Failed to start server: {e}")
raise e


# For FastAPI app
app = FastAPI()


@app.on_event("startup")
async def startup_event():
global app
transport_type = os.environ.get("MCP_TRANSPORT", "sse")
if transport_type.lower() == "sse":
# If using SSE, mount the SSE app to this app
sse_app = await start_server("sse")

# Add health check endpoint
@app.get("/health")
def health_check():
return {"status": "ok"}

# Add root endpoint
@app.get("/")
def read_root():
return {
"message": "Neo4j MCP Memory Server",
"transport": "SSE",
"sse_endpoint": "/sse",
}

# Mount all routes from the SSE app
for route in sse_app.routes:
app.routes.append(route)
else:
# For stdio, just inform that this app should not be used
@app.get("/")
def read_root():
return {
"error": "This server is configured to use stdio transport, not HTTP/SSE",
"message": "Please run this server directly from the command line",
}

@app.get("/health")
def health_check():
return {
"status": "error",
"message": "Server is configured for stdio transport",
}
55 changes: 55 additions & 0 deletions servers/mcp-neo4j-memory/src/mcp_neo4j_memory/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import argparse
import asyncio
import os


async def start_stdio_server():
"""Start the server with stdio transport"""
from src.mcp_neo4j_memory.app import start_server

await start_server("stdio")


def main():
"""Command-line entry point for running the MCP server"""
parser = argparse.ArgumentParser(description="MCP Neo4j Memory Server")
parser.add_argument(
"--transport",
choices=["sse", "stdio"],
default="sse",
help="Transport type (sse or stdio)",
)
parser.add_argument("--db-url", dest="neo4j_uri", help="Neo4j database URL")
parser.add_argument("--username", dest="neo4j_username", help="Neo4j username")
parser.add_argument("--password", dest="neo4j_password", help="Neo4j password")
parser.add_argument(
"--port",
type=int,
default=8090,
help="Port for HTTP server (when using SSE transport)",
)

args = parser.parse_args()

# Set environment variables from arguments
if args.neo4j_uri:
os.environ["NEO4J_URI"] = args.neo4j_uri
if args.neo4j_username:
os.environ["NEO4J_USERNAME"] = args.neo4j_username
if args.neo4j_password:
os.environ["NEO4J_PASSWORD"] = args.neo4j_password

os.environ["MCP_TRANSPORT"] = args.transport

if args.transport == "stdio":
# Run with stdio transport
asyncio.run(start_stdio_server())
else:
# Run with SSE transport via FastAPI/Uvicorn
import uvicorn

uvicorn.run("src.mcp_neo4j_memory.app:app", host="0.0.0.0", port=args.port, reload=False)


if __name__ == "__main__":
main()
Loading