fix: Resolve CI/CD issues for MCP server
- Fixed code formatting with ruff (removed trailing whitespace) - Fixed linting issues (removed unused imports) - Updated Dockerfile for new directory structure - Improved FalkorDB container health checks and timeouts - Enhanced FalkorDB readiness check with GRAPH module verification - Added debugging for FalkorDB startup failures 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d20340701f
commit
694ea46f66
6 changed files with 72 additions and 53 deletions
33
.github/workflows/mcp-server-tests.yml
vendored
33
.github/workflows/mcp-server-tests.yml
vendored
|
|
@ -40,11 +40,11 @@ jobs:
|
||||||
- 6379:6379
|
- 6379:6379
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
options: >-
|
options: >-
|
||||||
--health-cmd "redis-cli -h localhost -p 6379 ping"
|
--health-cmd "redis-cli -h localhost -p 6379 ping || exit 1"
|
||||||
--health-interval 15s
|
--health-interval 20s
|
||||||
--health-timeout 10s
|
--health-timeout 15s
|
||||||
--health-retries 8
|
--health-retries 12
|
||||||
--health-start-period 30s
|
--health-start-period 60s
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
|
|
@ -200,12 +200,26 @@ jobs:
|
||||||
- name: Wait for FalkorDB to be ready
|
- name: Wait for FalkorDB to be ready
|
||||||
run: |
|
run: |
|
||||||
echo "🔄 Waiting for FalkorDB to be ready..."
|
echo "🔄 Waiting for FalkorDB to be ready..."
|
||||||
max_attempts=30
|
|
||||||
|
# Install redis-tools first if not available
|
||||||
|
if ! command -v redis-cli &> /dev/null; then
|
||||||
|
echo "📦 Installing redis-tools..."
|
||||||
|
sudo apt-get update && sudo apt-get install -y redis-tools
|
||||||
|
fi
|
||||||
|
|
||||||
|
max_attempts=40
|
||||||
attempt=1
|
attempt=1
|
||||||
while [ $attempt -le $max_attempts ]; do
|
while [ $attempt -le $max_attempts ]; do
|
||||||
if redis-cli -h localhost -p 6379 ping >/dev/null 2>&1; then
|
if redis-cli -h localhost -p 6379 ping 2>/dev/null | grep -q PONG; then
|
||||||
echo "✅ FalkorDB is ready!"
|
echo "✅ FalkorDB is ready!"
|
||||||
break
|
|
||||||
|
# Verify GRAPH module is loaded
|
||||||
|
if redis-cli -h localhost -p 6379 MODULE LIST 2>/dev/null | grep -q graph; then
|
||||||
|
echo "✅ FalkorDB GRAPH module is loaded!"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
echo "⏳ Waiting for GRAPH module to load..."
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
echo "⏳ Attempt $attempt/$max_attempts - FalkorDB not ready yet..."
|
echo "⏳ Attempt $attempt/$max_attempts - FalkorDB not ready yet..."
|
||||||
sleep 3
|
sleep 3
|
||||||
|
|
@ -214,6 +228,9 @@ jobs:
|
||||||
|
|
||||||
if [ $attempt -gt $max_attempts ]; then
|
if [ $attempt -gt $max_attempts ]; then
|
||||||
echo "❌ FalkorDB failed to start within timeout"
|
echo "❌ FalkorDB failed to start within timeout"
|
||||||
|
# Get container logs for debugging
|
||||||
|
docker ps -a
|
||||||
|
docker logs $(docker ps -q -f "ancestor=falkordb/falkordb:v4.12.4") 2>&1 | tail -50 || echo "Could not fetch logs"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,9 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
uv sync --frozen --no-dev
|
uv sync --frozen --no-dev
|
||||||
|
|
||||||
# Copy application code and configuration
|
# Copy application code and configuration
|
||||||
COPY *.py ./
|
COPY main.py ./
|
||||||
COPY config.yaml ./
|
COPY src/ ./src/
|
||||||
|
COPY config/ ./config/
|
||||||
|
|
||||||
# Change ownership to app user
|
# Change ownership to app user
|
||||||
RUN chown -Rv app:app /app
|
RUN chown -Rv app:app /app
|
||||||
|
|
@ -47,4 +48,4 @@ USER app
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
# Command to run the application
|
# Command to run the application
|
||||||
CMD ["uv", "run", "graphiti_mcp_server.py"]
|
CMD ["uv", "run", "main.py"]
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import json
|
||||||
import time
|
import time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from mcp import ClientSession, StdioServerParameters
|
from mcp import StdioServerParameters
|
||||||
from mcp.client.stdio import stdio_client
|
from mcp.client.stdio import stdio_client
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -37,14 +37,14 @@ class GraphitiFalkorDBIntegrationTest:
|
||||||
|
|
||||||
# Start the stdio client
|
# Start the stdio client
|
||||||
self.session = await stdio_client(server_params).__aenter__()
|
self.session = await stdio_client(server_params).__aenter__()
|
||||||
print(f' 📡 Started MCP client session with FalkorDB backend')
|
print(' 📡 Started MCP client session with FalkorDB backend')
|
||||||
return self
|
return self
|
||||||
|
|
||||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||||
"""Clean up the MCP client session."""
|
"""Clean up the MCP client session."""
|
||||||
if self.session:
|
if self.session:
|
||||||
await self.session.close()
|
await self.session.close()
|
||||||
print(f' 🔌 Closed MCP client session')
|
print(' 🔌 Closed MCP client session')
|
||||||
|
|
||||||
async def call_mcp_tool(self, tool_name: str, arguments: dict[str, Any]) -> dict[str, Any]:
|
async def call_mcp_tool(self, tool_name: str, arguments: dict[str, Any]) -> dict[str, Any]:
|
||||||
"""Call an MCP tool via the stdio client."""
|
"""Call an MCP tool via the stdio client."""
|
||||||
|
|
@ -76,7 +76,7 @@ class GraphitiFalkorDBIntegrationTest:
|
||||||
# Check if status indicates FalkorDB is working
|
# Check if status indicates FalkorDB is working
|
||||||
status_text = result.get('raw_response', result.get('content', ''))
|
status_text = result.get('raw_response', result.get('content', ''))
|
||||||
if 'running' in str(status_text).lower() or 'ready' in str(status_text).lower():
|
if 'running' in str(status_text).lower() or 'ready' in str(status_text).lower():
|
||||||
print(f' ✅ Server status OK with FalkorDB')
|
print(' ✅ Server status OK with FalkorDB')
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
print(f' ⚠️ Status unclear: {status_text}')
|
print(f' ⚠️ Status unclear: {status_text}')
|
||||||
|
|
@ -90,7 +90,7 @@ class GraphitiFalkorDBIntegrationTest:
|
||||||
'name': 'FalkorDB Test Episode',
|
'name': 'FalkorDB Test Episode',
|
||||||
'episode_body': 'This is a test episode to verify FalkorDB integration works correctly.',
|
'episode_body': 'This is a test episode to verify FalkorDB integration works correctly.',
|
||||||
'source': 'text',
|
'source': 'text',
|
||||||
'source_description': 'Integration test for FalkorDB backend'
|
'source_description': 'Integration test for FalkorDB backend',
|
||||||
}
|
}
|
||||||
|
|
||||||
result = await self.call_mcp_tool('add_episode', episode_data)
|
result = await self.call_mcp_tool('add_episode', episode_data)
|
||||||
|
|
@ -99,7 +99,7 @@ class GraphitiFalkorDBIntegrationTest:
|
||||||
print(f' ❌ Add episode failed: {result["error"]}')
|
print(f' ❌ Add episode failed: {result["error"]}')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
print(f' ✅ Episode added successfully to FalkorDB')
|
print(' ✅ Episode added successfully to FalkorDB')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def test_search_functionality(self) -> bool:
|
async def test_search_functionality(self) -> bool:
|
||||||
|
|
@ -110,16 +110,15 @@ class GraphitiFalkorDBIntegrationTest:
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
# Test node search
|
# Test node search
|
||||||
search_result = await self.call_mcp_tool('search_nodes', {
|
search_result = await self.call_mcp_tool(
|
||||||
'query': 'FalkorDB test episode',
|
'search_nodes', {'query': 'FalkorDB test episode', 'limit': 5}
|
||||||
'limit': 5
|
)
|
||||||
})
|
|
||||||
|
|
||||||
if 'error' in search_result:
|
if 'error' in search_result:
|
||||||
print(f' ⚠️ Search returned error (may be expected): {search_result["error"]}')
|
print(f' ⚠️ Search returned error (may be expected): {search_result["error"]}')
|
||||||
return True # Don't fail on search errors in integration test
|
return True # Don't fail on search errors in integration test
|
||||||
|
|
||||||
print(f' ✅ Search functionality working with FalkorDB')
|
print(' ✅ Search functionality working with FalkorDB')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def test_clear_graph(self) -> bool:
|
async def test_clear_graph(self) -> bool:
|
||||||
|
|
@ -132,7 +131,7 @@ class GraphitiFalkorDBIntegrationTest:
|
||||||
print(f' ❌ Clear graph failed: {result["error"]}')
|
print(f' ❌ Clear graph failed: {result["error"]}')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
print(f' ✅ Graph cleared successfully in FalkorDB')
|
print(' ✅ Graph cleared successfully in FalkorDB')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,9 @@ def test_server_startup():
|
||||||
|
|
||||||
# Skip server startup test in CI - we have comprehensive integration tests
|
# Skip server startup test in CI - we have comprehensive integration tests
|
||||||
if os.environ.get('CI'):
|
if os.environ.get('CI'):
|
||||||
print(' ⚠️ Skipping server startup test in CI (comprehensive integration tests handle this)')
|
print(
|
||||||
|
' ⚠️ Skipping server startup test in CI (comprehensive integration tests handle this)'
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Check if uv is available
|
# Check if uv is available
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue