diff --git a/.github/workflows/mcp-server-tests.yml b/.github/workflows/mcp-server-tests.yml index 928c3908..f658df6d 100644 --- a/.github/workflows/mcp-server-tests.yml +++ b/.github/workflows/mcp-server-tests.yml @@ -68,11 +68,6 @@ jobs: cd mcp_server uv run tests/test_configuration.py - - name: Run syntax validation tests - run: | - cd mcp_server - uv run tests/test_simple_validation.py - - name: Run unit tests (if pytest tests exist) run: | cd mcp_server diff --git a/mcp_server/src/config/schema.py b/mcp_server/src/config/schema.py index 905d2faf..a2ed36c2 100644 --- a/mcp_server/src/config/schema.py +++ b/mcp_server/src/config/schema.py @@ -58,7 +58,10 @@ class YamlSettingsSource(PydanticBaseSettingsSource): class ServerConfig(BaseModel): """Server configuration.""" - transport: str = Field(default='sse', description='Transport type: sse (default) or stdio') + transport: str = Field( + default='sse', + description='Transport type: sse (default), stdio, or http (streamable HTTP)', + ) host: str = Field(default='0.0.0.0', description='Server host') port: int = Field(default=8000, description='Server port') diff --git a/mcp_server/src/graphiti_mcp_server.py b/mcp_server/src/graphiti_mcp_server.py index 0ab8d94f..de375384 100644 --- a/mcp_server/src/graphiti_mcp_server.py +++ b/mcp_server/src/graphiti_mcp_server.py @@ -646,8 +646,8 @@ async def initialize_server() -> ServerConfig: # Transport arguments parser.add_argument( '--transport', - choices=['sse', 'stdio'], - help='Transport to use for communication with the client', + choices=['sse', 'stdio', 'http'], + help='Transport to use: sse (Server-Sent Events), stdio (standard I/O), or http (streamable HTTP)', ) parser.add_argument( '--host', @@ -777,6 +777,15 @@ async def run_mcp_server(): f'Running MCP server with SSE transport on {mcp.settings.host}:{mcp.settings.port}' ) await mcp.run_sse_async() + elif mcp_config.transport == 'http': + logger.info( + f'Running MCP server with streamable HTTP transport on {mcp.settings.host}:{mcp.settings.port}' + ) + await mcp.run_streamable_http_async() + else: + raise ValueError( + f'Unsupported transport: {mcp_config.transport}. Use "sse", "stdio", or "http"' + ) def main(): diff --git a/mcp_server/tests/test_simple_validation.py b/mcp_server/tests/test_simple_validation.py deleted file mode 100644 index b774bb58..00000000 --- a/mcp_server/tests/test_simple_validation.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python3 -""" -Simple validation test for the refactored Graphiti MCP Server. -Tests basic server startup functionality. -""" - -import os -import subprocess -import sys -import time - - -def test_server_startup(): - """Test that the refactored server starts up successfully.""" - print('๐Ÿš€ Testing Graphiti MCP Server Startup...') - - # Skip server startup test in CI - we have comprehensive integration tests - if os.environ.get('CI'): - print( - ' โš ๏ธ Skipping server startup test in CI (comprehensive integration tests handle this)' - ) - return True - - # Check if uv is available - uv_cmd = None - for potential_uv in ['uv', '/Users/danielchalef/.local/bin/uv', '/root/.local/bin/uv']: - try: - result = subprocess.run([potential_uv, '--version'], capture_output=True, timeout=5) - if result.returncode == 0: - uv_cmd = potential_uv - break - except (subprocess.TimeoutExpired, FileNotFoundError): - continue - - if not uv_cmd: - print(' โš ๏ธ uv not found in PATH, skipping server startup test') - return True - - try: - # Start the server and capture output - process = subprocess.Popen( - [uv_cmd, 'run', 'main.py', '--transport', 'stdio'], - env={ - 'NEO4J_URI': 'bolt://localhost:7687', - 'NEO4J_USER': 'neo4j', - 'NEO4J_PASSWORD': 'demodemo', - 'PATH': os.environ.get('PATH', ''), - }, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - ) - - # Wait for initialization and capture output - captured_output = [] - start_time = time.time() - server_initialized = False - - # Monitor server output - while time.time() - start_time < 10: - try: - # Check if process has terminated - if process.poll() is not None: - stdout, stderr = process.communicate(timeout=1) - captured_output.extend([' ๐Ÿ“‹ ' + line for line in stdout.split('\n') if line]) - captured_output.extend([' ๐Ÿ“‹ ' + line for line in stderr.split('\n') if line]) - break - - # Check stderr for initialization messages - while True: - line = process.stderr.readline() - if not line: - break - print(f' ๐Ÿ“‹ {line.strip()}') - if 'Starting MCP server' in line or 'Successfully initialized' in line: - server_initialized = True - break - if 'Failed to initialize' in line or 'Error' in line: - break - - if server_initialized: - break - time.sleep(0.5) - except subprocess.TimeoutExpired: - pass - - # Clean up process - if process.poll() is None: - process.terminate() - time.sleep(1) - if process.poll() is None: - process.kill() - - return server_initialized or process.returncode == 0 - - except Exception as e: - print(f' โš ๏ธ Timeout waiting for initialization or server startup failed') - return False - - -if __name__ == '__main__': - print('๐Ÿงช Graphiti MCP Server Validation') - print('=' * 55) - - startup_pass = test_server_startup() - - print('\n' + '=' * 55) - print('๐Ÿ“Š VALIDATION SUMMARY') - print('-------------------------') - print(f'Startup Validation: {"โœ… PASS" if startup_pass else "โŒ FAIL"}') - print('-------------------------') - print(f'๐ŸŽฏ OVERALL: {"โœ… PASSED" if startup_pass else "โŒ FAILED"}') - - if not startup_pass: - print('\nโš ๏ธ Some validation issues detected.') - print(' Please review the failed tests above.') - sys.exit(1) \ No newline at end of file