From de0a146eb1c4499fc2cddc00ec7ee77c61002be4 Mon Sep 17 00:00:00 2001 From: ened Date: Tue, 26 Aug 2025 02:50:40 +0900 Subject: [PATCH] update bug --- diagnostic.py | 249 +++++++++++++++++++++++++++++++++++++++ main.py | 119 ++----------------- requirements.txt | 4 +- simple_test.py | 126 ++++++++++++++++++++ src/server/mcp_server.py | 154 ++++++++++++------------ start.bat | 32 +++-- 6 files changed, 485 insertions(+), 199 deletions(-) create mode 100644 diagnostic.py create mode 100644 simple_test.py diff --git a/diagnostic.py b/diagnostic.py new file mode 100644 index 0000000..51fad6f --- /dev/null +++ b/diagnostic.py @@ -0,0 +1,249 @@ +""" +Test script to diagnose FLUX.1 Edit MCP Server issues +""" + +import sys +import os +import asyncio +import logging +from pathlib import Path + +# Add src to path +sys.path.insert(0, str(Path(__file__).parent / 'src')) + +def test_imports(): + """Test all required imports""" + print("šŸ” Testing imports...") + + # Test standard library imports + try: + import json + import logging + import asyncio + print("āœ… Standard library imports OK") + except ImportError as e: + print(f"āŒ Standard library import failed: {e}") + return False + + # Test third-party dependencies + deps = { + 'aiohttp': '3.11.7', + 'httpx': '0.28.1', + 'mcp': '1.1.0+', + 'PIL': 'Pillow 11.0.0', + 'dotenv': 'python-dotenv 1.0.1', + 'pydantic': '2.10.3' + } + + for module, expected in deps.items(): + try: + __import__(module) + print(f"āœ… {module} ({expected}) OK") + except ImportError as e: + print(f"āŒ {module} missing: {e}") + return False + + # Test MCP specific imports + try: + import mcp.types as types + import mcp.server + from mcp.server import Server + from mcp.server.stdio import stdio_server + print("āœ… MCP imports OK") + except ImportError as e: + print(f"āŒ MCP import failed: {e}") + return False + + # Test local module imports + try: + from src.connector import Config + print("āœ… Config import OK") + except ImportError as e: + print(f"āŒ Config import failed: {e}") + return False + + try: + from src.server.models import TOOL_DEFINITIONS, ToolName + print("āœ… Models import OK") + except ImportError as e: + print(f"āŒ Models import failed: {e}") + return False + + try: + from src.server.handlers import ToolHandlers + print("āœ… Handlers import OK") + except ImportError as e: + print(f"āŒ Handlers import failed: {e}") + return False + + try: + from src.utils import validate_edit_parameters + print("āœ… Utils import OK") + except ImportError as e: + print(f"āŒ Utils import failed: {e}") + return False + + return True + + +def test_config(): + """Test configuration loading""" + print("\nšŸ” Testing configuration...") + + try: + from src.connector import Config + config = Config() + + print(f"āœ… Config loaded") + print(f" - API key: {'***' + config.api_key[-4:] if config.api_key else 'Not Set'}") + print(f" - Input path: {config.input_path}") + print(f" - Output path: {config.generated_images_path}") + + # Test config validation + if config.validate(): + print("āœ… Config validation passed") + else: + print("āŒ Config validation failed") + return False + + return True + + except Exception as e: + print(f"āŒ Config test failed: {e}") + return False + + +def test_mcp_server_creation(): + """Test MCP server creation""" + print("\nšŸ” Testing MCP server creation...") + + try: + from src.server.mcp_server import FluxEditMCPServer + + server = FluxEditMCPServer() + print("āœ… MCP server created successfully") + + # Test tool definitions + from src.server.models import TOOL_DEFINITIONS + print(f"āœ… Tool definitions loaded: {len(TOOL_DEFINITIONS)} tools") + for tool_name in TOOL_DEFINITIONS: + print(f" - {tool_name}") + + return True + + except Exception as e: + print(f"āŒ MCP server creation failed: {e}") + import traceback + traceback.print_exc() + return False + + +async def test_mcp_server_init(): + """Test MCP server initialization""" + print("\nšŸ” Testing MCP server initialization...") + + try: + from src.server.mcp_server import create_server + + server = create_server() + print("āœ… MCP server initialized") + + # Test configuration validation + if server.validate_config(): + print("āœ… Server config validation passed") + else: + print("āŒ Server config validation failed") + return False + + return True + + except Exception as e: + print(f"āŒ MCP server initialization failed: {e}") + import traceback + traceback.print_exc() + return False + + +def test_directories(): + """Test directory structure""" + print("\nšŸ” Testing directory structure...") + + base_path = Path(__file__).parent + + required_dirs = [ + 'src', + 'src/connector', + 'src/server', + 'src/utils', + 'input_images', + 'generated_images' + ] + + for dir_path in required_dirs: + full_path = base_path / dir_path + if full_path.exists(): + print(f"āœ… {dir_path}/") + else: + print(f"āŒ {dir_path}/ (missing)") + try: + full_path.mkdir(parents=True, exist_ok=True) + print(f"āœ… Created {dir_path}/") + except Exception as e: + print(f"āŒ Failed to create {dir_path}/: {e}") + return False + + return True + + +def main(): + """Main test function""" + print("šŸš€ FLUX.1 Edit MCP Server Diagnostic Tool") + print("=" * 50) + + tests = [ + ("Directory Structure", test_directories), + ("Import Dependencies", test_imports), + ("Configuration", test_config), + ("MCP Server Creation", test_mcp_server_creation), + ("MCP Server Initialization", lambda: asyncio.run(test_mcp_server_init())), + ] + + results = [] + for test_name, test_func in tests: + print(f"\nšŸ“‹ Running {test_name}...") + try: + result = test_func() + results.append((test_name, result)) + if result: + print(f"āœ… {test_name} PASSED") + else: + print(f"āŒ {test_name} FAILED") + except Exception as e: + print(f"āŒ {test_name} FAILED with exception: {e}") + results.append((test_name, False)) + + # Summary + print("\n" + "=" * 50) + print("šŸ“Š DIAGNOSTIC SUMMARY") + print("=" * 50) + + passed = sum(1 for _, result in results if result) + total = len(results) + + for test_name, result in results: + status = "āœ… PASS" if result else "āŒ FAIL" + print(f"{status} {test_name}") + + print(f"\nšŸŽÆ Results: {passed}/{total} tests passed") + + if passed == total: + print("šŸŽ‰ All tests passed! Server should work correctly.") + else: + print("šŸ”§ Some tests failed. Please fix the issues above.") + + return passed == total + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/main.py b/main.py index 38958d5..2804160 100644 --- a/main.py +++ b/main.py @@ -1,123 +1,30 @@ """Main entry point for FLUX.1 Edit MCP Server""" import asyncio -import logging import sys -import traceback from pathlib import Path # Add src to path for imports sys.path.insert(0, str(Path(__file__).parent / 'src')) -def setup_logging(): - """Setup logging configuration""" - # Only log to file, not stdout to avoid JSON parsing issues - logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', - handlers=[ - logging.FileHandler('flux1-edit.log', mode='a', encoding='utf-8') - ] - ) - - # Set specific loggers - logging.getLogger('aiohttp').setLevel(logging.WARNING) - logging.getLogger('PIL').setLevel(logging.WARNING) - - -def check_dependencies(): - """Check if all required dependencies are available - silently check for MCP compatibility""" - missing_deps = [] - - try: - import aiohttp - # Silent check - no print to avoid JSON parsing issues - except ImportError as e: - missing_deps.append(f"aiohttp: {e}") - - try: - import httpx - # Silent check - no print to avoid JSON parsing issues - except ImportError as e: - missing_deps.append(f"httpx: {e}") - - try: - import mcp - # Silent check - no print to avoid JSON parsing issues - except ImportError as e: - missing_deps.append(f"mcp: {e}") - - try: - from PIL import Image - # Silent check - no print to avoid JSON parsing issues - except ImportError as e: - missing_deps.append(f"Pillow: {e}") - - try: - import dotenv - # Silent check - no print to avoid JSON parsing issues - except ImportError as e: - missing_deps.append(f"python-dotenv: {e}") - - try: - import pydantic - # Silent check - no print to avoid JSON parsing issues - except ImportError as e: - missing_deps.append(f"pydantic: {e}") - - if missing_deps: - # Log to file instead of print to avoid JSON parsing issues - logger = logging.getLogger(__name__) - logger.error(f"Missing dependencies: {missing_deps}") - return False - - return True - - -def check_local_imports(): - """Check if local modules can be imported - silently check for MCP compatibility""" - logger = logging.getLogger(__name__) - - try: - from src.connector import Config - # Silent check - no print to avoid JSON parsing issues - except ImportError as e: - logger.error(f"Failed to import local Config: {e}") - return False - - try: - from src.server import main - # Silent check - no print to avoid JSON parsing issues - return True - except ImportError as e: - logger.error(f"Failed to import local server main: {e}", exc_info=True) - return False - - if __name__ == "__main__": - setup_logging() - logger = logging.getLogger(__name__) - - # Check dependencies first - silently for MCP compatibility - if not check_dependencies(): - logger.error("Dependencies check failed") - sys.exit(1) - - # Check local imports - silently for MCP compatibility - if not check_local_imports(): - logger.error("Local imports check failed") - sys.exit(1) - - # Start the MCP server without console output to avoid JSON parsing issues try: - # Import main function after checks - from src.server import main - logger.info("Starting FLUX.1 Edit MCP Server...") + # Import and run the main server function + from src.server.mcp_server import main asyncio.run(main()) except KeyboardInterrupt: - logger.info("Server stopped by user") sys.exit(0) except Exception as e: - logger.error(f"Server error: {e}", exc_info=True) + # Log to stderr for debugging, but avoid stdout pollution for MCP + import logging + logging.basicConfig( + level=logging.ERROR, + format='%(asctime)s [%(name)s] %(levelname)s: %(message)s', + handlers=[ + logging.FileHandler('flux1-edit.log', mode='a', encoding='utf-8') + ] + ) + logger = logging.getLogger(__name__) + logger.error(f"Fatal error: {e}", exc_info=True) sys.exit(1) diff --git a/requirements.txt b/requirements.txt index cc834df..aa71b9f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # FLUX.1 Edit MCP Server Dependencies -# Core MCP Server -mcp==1.1.0 +# Core MCP Server - Updated version +mcp==1.2.0 # HTTP Client for FLUX API httpx==0.28.1 diff --git a/simple_test.py b/simple_test.py new file mode 100644 index 0000000..c4b06bc --- /dev/null +++ b/simple_test.py @@ -0,0 +1,126 @@ +""" +Simple test script for FLUX.1 Edit MCP Server +""" + +import sys +import asyncio +import json +from pathlib import Path + +# Add src to path +sys.path.insert(0, str(Path(__file__).parent / 'src')) + +async def test_server_import(): + """Test if the server can be imported and initialized""" + print("šŸ” Testing server import and initialization...") + + try: + # Test imports + from src.server.mcp_server import create_server + from src.connector import Config + + print("āœ… Successfully imported server components") + + # Test configuration + config = Config() + if config.validate(): + print("āœ… Configuration validation passed") + else: + print("āŒ Configuration validation failed") + return False + + # Test server creation + server = create_server() + print("āœ… Server created successfully") + + # Test server validation + if server.validate_config(): + print("āœ… Server configuration validated") + else: + print("āŒ Server configuration validation failed") + return False + + return True + + except Exception as e: + print(f"āŒ Error: {e}") + import traceback + traceback.print_exc() + return False + +async def test_mcp_protocol(): + """Test MCP protocol basics""" + print("\nšŸ” Testing MCP protocol basics...") + + try: + import mcp.types as types + from mcp.server import Server + from mcp.server.stdio import stdio_server + + print("āœ… MCP imports successful") + + # Create a minimal server for testing + server = Server("test-server") + + @server.list_tools() + async def list_tools(): + return [ + types.Tool( + name="test_tool", + description="Test tool", + inputSchema={ + "type": "object", + "properties": { + "test_param": { + "type": "string", + "description": "Test parameter" + } + }, + "required": ["test_param"] + } + ) + ] + + print("āœ… MCP server handlers configured") + return True + + except Exception as e: + print(f"āŒ MCP protocol test failed: {e}") + import traceback + traceback.print_exc() + return False + +def main(): + """Main test function""" + print("šŸš€ FLUX.1 Edit MCP Server - Simple Test") + print("=" * 50) + + # Run async tests + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + try: + test1_result = loop.run_until_complete(test_server_import()) + test2_result = loop.run_until_complete(test_mcp_protocol()) + + print("\n" + "=" * 50) + print("šŸ“Š TEST RESULTS") + print("=" * 50) + + print(f"Server Import & Init: {'āœ… PASS' if test1_result else 'āŒ FAIL'}") + print(f"MCP Protocol Basic: {'āœ… PASS' if test2_result else 'āŒ FAIL'}") + + if test1_result and test2_result: + print("\nšŸŽ‰ All tests passed! Server should be ready.") + print("\nšŸ’” Try running: python main.py") + return True + else: + print("\nšŸ”§ Some tests failed. Check the errors above.") + return False + + finally: + loop.close() + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/src/server/mcp_server.py b/src/server/mcp_server.py index 1a1566c..e266e61 100644 --- a/src/server/mcp_server.py +++ b/src/server/mcp_server.py @@ -5,9 +5,8 @@ import asyncio from typing import Dict, Any, List import mcp.types as types -from mcp import server from mcp.server import Server -from mcp.server.models import InitializationOptions +from mcp.server.stdio import stdio_server from ..connector import Config from .models import TOOL_DEFINITIONS, ToolName @@ -16,23 +15,44 @@ from .handlers import ToolHandlers logger = logging.getLogger(__name__) -class FluxEditMCPServer: - """FLUX.1 Edit MCP Server""" +async def main(): + """Main entry point for the MCP server""" - def __init__(self): - """Initialize the MCP server""" - self.config = Config() - self.app = Server("flux1-edit") - self.handlers = ToolHandlers(self.config) - self._setup_handlers() - - logger.info("FLUX.1 Edit MCP Server initialized") + # Setup logging with minimal output for MCP compatibility + logging.basicConfig( + level=logging.WARNING, # Only warnings and errors + format='%(asctime)s [%(name)s] %(levelname)s: %(message)s', + handlers=[ + logging.FileHandler('flux1-edit.log', mode='a', encoding='utf-8') + ] + ) - def _setup_handlers(self): - """Setup MCP server handlers""" + # Silence noisy loggers completely + logging.getLogger('aiohttp').setLevel(logging.ERROR) + logging.getLogger('PIL').setLevel(logging.ERROR) + logging.getLogger('httpx').setLevel(logging.ERROR) + + logger = logging.getLogger(__name__) + + try: + # Create configuration + config = Config() - # List tools handler - @self.app.list_tools() + # Validate configuration + if not config.validate(): + logger.error("Configuration validation failed") + raise RuntimeError("Configuration validation failed") + + # Create MCP server + server = Server("flux1-edit") + + # Create tool handlers + handlers = ToolHandlers(config) + + logger.info("Setting up MCP server handlers...") + + # Set up list_tools handler + @server.list_tools() async def list_tools() -> List[types.Tool]: """List available tools""" tools = [] @@ -76,23 +96,32 @@ class FluxEditMCPServer: logger.debug(f"Listed {len(tools)} tools") return tools - # Call tool handler - @self.app.call_tool() + # Set up call_tool handler + @server.call_tool() async def call_tool(name: str, arguments: Dict[str, Any]) -> List[types.TextContent | types.ImageContent]: """Handle tool calls""" try: logger.info(f"Tool call: {name}") - logger.debug(f"Arguments: {self._sanitize_args_for_logging(arguments)}") + + # Sanitize arguments for logging + safe_args = arguments.copy() + if 'input_image_b64' in safe_args: + b64_data = safe_args['input_image_b64'] + safe_args['input_image_b64'] = f"" + if 'prompt' in safe_args and len(safe_args['prompt']) > 100: + safe_args['prompt'] = safe_args['prompt'][:100] + '...' + + logger.debug(f"Arguments: {safe_args}") # Route to appropriate handler if name == ToolName.FLUX_EDIT_IMAGE: - return await self.handlers.handle_flux_edit_image(arguments) + return await handlers.handle_flux_edit_image(arguments) elif name == ToolName.FLUX_EDIT_IMAGE_FROM_FILE: - return await self.handlers.handle_flux_edit_image_from_file(arguments) + return await handlers.handle_flux_edit_image_from_file(arguments) elif name == ToolName.VALIDATE_IMAGE: - return await self.handlers.handle_validate_image(arguments) + return await handlers.handle_validate_image(arguments) elif name == ToolName.MOVE_TEMP_TO_OUTPUT: - return await self.handlers.handle_move_temp_to_output(arguments) + return await handlers.handle_move_temp_to_output(arguments) else: return [types.TextContent( type="text", @@ -105,74 +134,39 @@ class FluxEditMCPServer: type="text", text=f"[ERROR] Tool execution error: {str(e)}" )] + + logger.info("Starting FLUX.1 Edit MCP Server...") + logger.info(f"API key configured: {'Yes' if config.api_key else 'No'}") + logger.info(f"Input directory: {config.input_path}") + logger.info(f"Output directory: {config.generated_images_path}") + + # Run the server using stdio + await stdio_server(server) + + except Exception as e: + logger.error(f"Server startup failed: {e}", exc_info=True) + raise + + +class FluxEditMCPServer: + """Legacy wrapper class (kept for compatibility)""" - def _sanitize_args_for_logging(self, args: Dict[str, Any]) -> Dict[str, Any]: - """ - Remove sensitive data from arguments for logging - - Args: - args: Original arguments - - Returns: - dict: Sanitized arguments - """ - safe_args = args.copy() - - # Don't log full base64 image data - if 'input_image_b64' in safe_args: - b64_data = safe_args['input_image_b64'] - safe_args['input_image_b64'] = f"" - - # Truncate long prompts - if 'prompt' in safe_args and len(safe_args['prompt']) > 100: - safe_args['prompt'] = safe_args['prompt'][:100] + '...' - - return safe_args + def __init__(self): + """Initialize the MCP server""" + self.config = Config() + self.server = Server("flux1-edit") + self.handlers = ToolHandlers(self.config) + logger.info("FLUX.1 Edit MCP Server initialized") def validate_config(self) -> bool: """Validate server configuration""" return self.config.validate() - - async def run(self): - """Run the MCP server""" - if not self.validate_config(): - logger.error("Configuration validation failed") - return False - - logger.info("Starting FLUX.1 Edit MCP Server...") - logger.info(f"Configuration:\n{self.config}") - - # Run the server - async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): - await self.app.run( - read_stream, - write_stream, - InitializationOptions( - server_name="flux1-edit", - server_version="1.0.0" - ) - ) -# Server factory function def create_server() -> FluxEditMCPServer: """Create and return a FLUX.1 Edit MCP Server instance""" return FluxEditMCPServer() -# Main function for running the server -async def main(): - """Main entry point for the server""" - # Setup logging - logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' - ) - - # Create and run server - server_instance = create_server() - await server_instance.run() - - if __name__ == "__main__": asyncio.run(main()) diff --git a/start.bat b/start.bat index 07c3509..ed1400e 100644 --- a/start.bat +++ b/start.bat @@ -2,24 +2,34 @@ echo FLUX.1 Edit MCP Server - Quick Start echo ==================================== -echo Checking dependencies first... REM Set UTF-8 encoding to prevent Unicode errors chcp 65001 >nul 2>&1 set PYTHONIOENCODING=utf-8 set PYTHONUTF8=1 -python check_dependencies.py + +echo Running simple test first... +python simple_test.py if errorlevel 1 ( echo. - echo Dependencies check failed. Running installation... - call install_dependencies.bat - if errorlevel 1 ( - echo Failed to install dependencies. - pause - exit /b 1 - ) + echo Simple test failed. Please check the errors above. + pause + exit /b 1 ) echo. -echo Dependencies OK! Running original startup script... +echo Simple test passed! Starting MCP server... echo. -call run.bat + +REM Start the main MCP server +python main.py + +if errorlevel 1 ( + echo. + echo Server failed to start. Check flux1-edit.log for details. + pause + exit /b 1 +) + +echo. +echo Server stopped. +pause