From d97c24855152aa5b36114282c7ab1835e6f9d743 Mon Sep 17 00:00:00 2001 From: Daniel Chalef <131175+danielchalef@users.noreply.github.com> Date: Sat, 8 Nov 2025 18:31:24 -0800 Subject: [PATCH] Fix MCP server telemetry and update graphiti-core to v0.23.0 (#1057) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix MCP server telemetry and update graphiti-core to v0.23.0 - Regenerate uv.lock in Docker builds to ensure posthog dependency is included - Update graphiti-core version to 0.23.0 across all configurations - Fix Python 3.11 compatibility for Pydantic TypedDict import - Add FalkorDB Browser UI access information to startup logs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude * Add typing-extensions as explicit dependency Required for Python 3.11 compatibility with Pydantic 2.11.7, which mandates typing_extensions.TypedDict on Python < 3.12. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude * Use built-in TypedDict from typing module Python 3.10+ includes TypedDict in the standard library. Removed typing-extensions dependency as it's unnecessary. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude * Revert to typing_extensions.TypedDict for Pydantic compatibility Pydantic requires typing_extensions.TypedDict on Python < 3.12. Docker container uses Python 3.11, so this is necessary. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude * Add Ruff linter rule to prevent typing.TypedDict usage Adds banned-api configuration to both main and MCP server pyproject.toml files to enforce typing_extensions.TypedDict usage, required for Pydantic compatibility on Python < 3.12. Also includes Ruff auto-formatting changes to quote styles. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude * Bump MCP server version to 1.0.1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --------- Co-authored-by: Claude --- mcp_server/docker/Dockerfile | 10 +++-- mcp_server/docker/Dockerfile.standalone | 8 +++- mcp_server/docker/docker-compose.yml | 2 +- mcp_server/pyproject.toml | 11 ++++-- mcp_server/src/graphiti_mcp_server.py | 51 ++++++++++++++----------- mcp_server/src/models/response_types.py | 4 +- mcp_server/uv.lock | 2 + pyproject.toml | 4 ++ 8 files changed, 59 insertions(+), 33 deletions(-) diff --git a/mcp_server/docker/Dockerfile b/mcp_server/docker/Dockerfile index d4c4d37d..4b37e16c 100644 --- a/mcp_server/docker/Dockerfile +++ b/mcp_server/docker/Dockerfile @@ -33,16 +33,20 @@ ENV UV_COMPILE_BYTECODE=1 \ WORKDIR /app/mcp # Accept graphiti-core version as build argument -ARG GRAPHITI_CORE_VERSION=0.22.0 +ARG GRAPHITI_CORE_VERSION=0.23.0 # Copy project files for dependency installation COPY pyproject.toml uv.lock ./ # Remove the local path override for graphiti-core in Docker builds +# and regenerate lock file to match the PyPI version RUN sed -i '/\[tool\.uv\.sources\]/,/graphiti-core/d' pyproject.toml && \ if [ -n "${GRAPHITI_CORE_VERSION}" ]; then \ - sed -i "s/graphiti-core\[falkordb\]>=0\.16\.0/graphiti-core[falkordb]==${GRAPHITI_CORE_VERSION}/" pyproject.toml; \ - fi + sed -i "s/graphiti-core\[falkordb\]>=0\.23\.0/graphiti-core[falkordb]==${GRAPHITI_CORE_VERSION}/" pyproject.toml; \ + fi && \ + echo "Regenerating lock file for PyPI graphiti-core..." && \ + rm -f uv.lock && \ + uv lock # Install Python dependencies RUN --mount=type=cache,target=/root/.cache/uv \ diff --git a/mcp_server/docker/Dockerfile.standalone b/mcp_server/docker/Dockerfile.standalone index 6db22d95..042d22d5 100644 --- a/mcp_server/docker/Dockerfile.standalone +++ b/mcp_server/docker/Dockerfile.standalone @@ -28,15 +28,19 @@ ENV UV_COMPILE_BYTECODE=1 \ WORKDIR /app/mcp # Accept graphiti-core version as build argument -ARG GRAPHITI_CORE_VERSION=0.22.0 +ARG GRAPHITI_CORE_VERSION=0.23.0 # Copy project files for dependency installation COPY pyproject.toml uv.lock ./ # Remove the local path override for graphiti-core in Docker builds # Install with BOTH neo4j and falkordb extras for maximum flexibility +# and regenerate lock file to match the PyPI version RUN sed -i '/\[tool\.uv\.sources\]/,/graphiti-core/d' pyproject.toml && \ - sed -i "s/graphiti-core\[falkordb\]>=0\.16\.0/graphiti-core[neo4j,falkordb]==${GRAPHITI_CORE_VERSION}/" pyproject.toml + sed -i "s/graphiti-core\[falkordb\]>=0\.23\.0/graphiti-core[neo4j,falkordb]==${GRAPHITI_CORE_VERSION}/" pyproject.toml && \ + echo "Regenerating lock file for PyPI graphiti-core..." && \ + rm -f uv.lock && \ + uv lock # Install Python dependencies RUN --mount=type=cache,target=/root/.cache/uv \ diff --git a/mcp_server/docker/docker-compose.yml b/mcp_server/docker/docker-compose.yml index 9ec7daf0..a4f8b257 100644 --- a/mcp_server/docker/docker-compose.yml +++ b/mcp_server/docker/docker-compose.yml @@ -5,7 +5,7 @@ services: context: .. dockerfile: docker/Dockerfile args: - GRAPHITI_CORE_VERSION: ${GRAPHITI_CORE_VERSION:-0.22.0} + GRAPHITI_CORE_VERSION: ${GRAPHITI_CORE_VERSION:-0.23.0} MCP_SERVER_VERSION: ${MCP_SERVER_VERSION:-1.0.0} BUILD_DATE: ${BUILD_DATE:-} VCS_REF: ${VCS_REF:-} diff --git a/mcp_server/pyproject.toml b/mcp_server/pyproject.toml index 65e8a2d6..0370fd3c 100644 --- a/mcp_server/pyproject.toml +++ b/mcp_server/pyproject.toml @@ -1,15 +1,16 @@ [project] name = "mcp-server" -version = "1.0.0" +version = "1.0.1" description = "Graphiti MCP Server" readme = "README.md" requires-python = ">=3.10,<4" dependencies = [ "mcp>=1.9.4", "openai>=1.91.0", - "graphiti-core[falkordb]>=0.16.0", + "graphiti-core[falkordb]>=0.23.0", "pydantic-settings>=2.0.0", "pyyaml>=6.0", + "typing-extensions>=4.0.0", ] [project.optional-dependencies] @@ -24,7 +25,7 @@ providers = [ "sentence-transformers>=2.0.0", ] dev = [ - "graphiti-core>=0.16.0", + "graphiti-core>=0.23.0", "httpx>=0.28.1", "mcp>=1.9.4", "pyright>=1.1.404", @@ -58,6 +59,10 @@ select = [ ] ignore = ["E501"] +[tool.ruff.lint.flake8-tidy-imports.banned-api] +# Required by Pydantic on Python < 3.12 +"typing.TypedDict".msg = "Use typing_extensions.TypedDict instead." + [tool.ruff.format] quote-style = "single" indent-style = "space" diff --git a/mcp_server/src/graphiti_mcp_server.py b/mcp_server/src/graphiti_mcp_server.py index 0c9a568a..833bc5d9 100644 --- a/mcp_server/src/graphiti_mcp_server.py +++ b/mcp_server/src/graphiti_mcp_server.py @@ -245,35 +245,35 @@ class GraphitiService: db_provider = self.config.database.provider if db_provider.lower() == 'falkordb': raise RuntimeError( - f"\n{'='*70}\n" - f"Database Connection Error: FalkorDB is not running\n" - f"{'='*70}\n\n" - f"FalkorDB at {db_config['host']}:{db_config['port']} is not accessible.\n\n" - f"To start FalkorDB:\n" - f" - Using Docker Compose: cd mcp_server && docker compose up\n" - f" - Or run FalkorDB manually: docker run -p 6379:6379 falkordb/falkordb\n\n" - f"{'='*70}\n" + f'\n{"=" * 70}\n' + f'Database Connection Error: FalkorDB is not running\n' + f'{"=" * 70}\n\n' + f'FalkorDB at {db_config["host"]}:{db_config["port"]} is not accessible.\n\n' + f'To start FalkorDB:\n' + f' - Using Docker Compose: cd mcp_server && docker compose up\n' + f' - Or run FalkorDB manually: docker run -p 6379:6379 falkordb/falkordb\n\n' + f'{"=" * 70}\n' ) from db_error elif db_provider.lower() == 'neo4j': raise RuntimeError( - f"\n{'='*70}\n" - f"Database Connection Error: Neo4j is not running\n" - f"{'='*70}\n\n" - f"Neo4j at {db_config.get('uri', 'unknown')} is not accessible.\n\n" - f"To start Neo4j:\n" - f" - Using Docker Compose: cd mcp_server && docker compose -f docker/docker-compose-neo4j.yml up\n" - f" - Or install Neo4j Desktop from: https://neo4j.com/download/\n" - f" - Or run Neo4j manually: docker run -p 7474:7474 -p 7687:7687 neo4j:latest\n\n" - f"{'='*70}\n" + f'\n{"=" * 70}\n' + f'Database Connection Error: Neo4j is not running\n' + f'{"=" * 70}\n\n' + f'Neo4j at {db_config.get("uri", "unknown")} is not accessible.\n\n' + f'To start Neo4j:\n' + f' - Using Docker Compose: cd mcp_server && docker compose -f docker/docker-compose-neo4j.yml up\n' + f' - Or install Neo4j Desktop from: https://neo4j.com/download/\n' + f' - Or run Neo4j manually: docker run -p 7474:7474 -p 7687:7687 neo4j:latest\n\n' + f'{"=" * 70}\n' ) from db_error else: raise RuntimeError( - f"\n{'='*70}\n" - f"Database Connection Error: {db_provider} is not running\n" - f"{'='*70}\n\n" - f"{db_provider} at {db_config.get('uri', 'unknown')} is not accessible.\n\n" - f"Please ensure {db_provider} is running and accessible.\n\n" - f"{'='*70}\n" + f'\n{"=" * 70}\n' + f'Database Connection Error: {db_provider} is not running\n' + f'{"=" * 70}\n\n' + f'{db_provider} at {db_config.get("uri", "unknown")} is not accessible.\n\n' + f'Please ensure {db_provider} is running and accessible.\n\n' + f'{"=" * 70}\n' ) from db_error # Re-raise other errors raise @@ -931,6 +931,11 @@ async def run_mcp_server(): logger.info(f' Base URL: http://{display_host}:{mcp.settings.port}/') logger.info(f' MCP Endpoint: http://{display_host}:{mcp.settings.port}/mcp/') logger.info(' Transport: HTTP (streamable)') + + # Show FalkorDB Browser UI access if enabled + if os.environ.get('BROWSER', '1') == '1': + logger.info(f' FalkorDB Browser UI: http://{display_host}:3000/') + logger.info('=' * 60) logger.info('For MCP clients, connect to the /mcp/ endpoint above') diff --git a/mcp_server/src/models/response_types.py b/mcp_server/src/models/response_types.py index eca20324..16d96bca 100644 --- a/mcp_server/src/models/response_types.py +++ b/mcp_server/src/models/response_types.py @@ -1,6 +1,8 @@ """Response type definitions for Graphiti MCP Server.""" -from typing import Any, TypedDict +from typing import Any + +from typing_extensions import TypedDict class ErrorResponse(TypedDict): diff --git a/mcp_server/uv.lock b/mcp_server/uv.lock index 2ff3dfc0..77450508 100644 --- a/mcp_server/uv.lock +++ b/mcp_server/uv.lock @@ -1082,6 +1082,7 @@ dependencies = [ { name = "openai" }, { name = "pydantic-settings" }, { name = "pyyaml" }, + { name = "typing-extensions" }, ] [package.optional-dependencies] @@ -1132,6 +1133,7 @@ requires-dist = [ { name = "pyyaml", specifier = ">=6.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.7.1" }, { name = "sentence-transformers", marker = "extra == 'providers'", specifier = ">=2.0.0" }, + { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "voyageai", marker = "extra == 'providers'", specifier = ">=0.2.3" }, ] provides-extras = ["azure", "providers", "dev"] diff --git a/pyproject.toml b/pyproject.toml index c5821657..4984808c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,6 +90,10 @@ select = [ ] ignore = ["E501"] +[tool.ruff.lint.flake8-tidy-imports.banned-api] +# Required by Pydantic on Python < 3.12 +"typing.TypedDict".msg = "Use typing_extensions.TypedDict instead." + [tool.ruff.format] quote-style = "single" indent-style = "space"