From 50b4e24242e24602d8a48bdae8a9fe2b21e16dda Mon Sep 17 00:00:00 2001 From: latinogino <154024559+latinogino@users.noreply.github.com> Date: Mon, 22 Sep 2025 20:29:24 +0200 Subject: [PATCH] Enhance: Improve error handling, logging, and API connection test --- src/dolibarr_mcp/dolibarr_mcp_server.py | 71 ++++++++++++++++++------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/src/dolibarr_mcp/dolibarr_mcp_server.py b/src/dolibarr_mcp/dolibarr_mcp_server.py index 9d59dd3..9aa176d 100644 --- a/src/dolibarr_mcp/dolibarr_mcp_server.py +++ b/src/dolibarr_mcp/dolibarr_mcp_server.py @@ -4,6 +4,8 @@ import asyncio import json import sys import os +import logging +from contextlib import asynccontextmanager # Import MCP components from mcp.server.models import InitializationOptions @@ -16,6 +18,13 @@ from .config import Config from .dolibarr_client import DolibarrClient, DolibarrAPIError +# Configure logging to stderr so it doesn't interfere with MCP protocol +logging.basicConfig( + level=logging.WARNING, # Reduce noise in MCP communication + format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", + handlers=[logging.StreamHandler(sys.stderr)] +) + # Create server instance server = Server("dolibarr-mcp") @@ -634,12 +643,14 @@ async def handle_call_tool(name: str, arguments: dict): except Exception as e: error_result = {"error": f"Tool execution failed: {str(e)}", "type": "internal_error"} + print(f"šŸ”„ Tool execution error: {e}", file=sys.stderr) # Debug logging return [TextContent(type="text", text=json.dumps(error_result, indent=2))] -async def main(): - """Run the Dolibarr MCP server.""" - # Quick API test using the proper client +@asynccontextmanager +async def test_api_connection(): + """Test API connection and yield client if successful.""" + config = None try: config = Config() async with DolibarrClient(config) as client: @@ -648,31 +659,55 @@ async def main(): if 'success' in result or 'dolibarr_version' in str(result): print("āœ… Dolibarr API connection successful", file=sys.stderr) print("šŸŽÆ Full CRUD operations available for all Dolibarr modules", file=sys.stderr) + yield True else: print(f"āŒ API test failed: {result.get('error', 'Unknown error')}", file=sys.stderr) - return + yield False except Exception as e: print(f"āŒ API test error: {e}", file=sys.stderr) - return + if config is None: + print("šŸ’” Check your .env file configuration", file=sys.stderr) + yield False + + +async def main(): + """Run the Dolibarr MCP server.""" + + # Quick API test using the proper client + async with test_api_connection() as api_ok: + if not api_ok: + print("🚨 Cannot start server without valid API connection", file=sys.stderr) + sys.exit(1) # Run server print("šŸš€ Starting Professional Dolibarr MCP server...", file=sys.stderr) print("āœ… Server ready with comprehensive ERP management capabilities", file=sys.stderr) - async with stdio_server() as (read_stream, write_stream): - await server.run( - read_stream, - write_stream, - InitializationOptions( - server_name="dolibarr-mcp", - server_version="1.0.0", - capabilities=server.get_capabilities( - notification_options=NotificationOptions(), - experimental_capabilities={}, + try: + async with stdio_server() as (read_stream, write_stream): + await server.run( + read_stream, + write_stream, + InitializationOptions( + server_name="dolibarr-mcp", + server_version="1.0.1", + capabilities=server.get_capabilities( + notification_options=NotificationOptions(), + experimental_capabilities={}, + ), ), - ), - ) + ) + except Exception as e: + print(f"šŸ’„ Server error: {e}", file=sys.stderr) + raise if __name__ == "__main__": - asyncio.run(main()) + try: + asyncio.run(main()) + except KeyboardInterrupt: + print("\nšŸ‘‹ Server stopped by user", file=sys.stderr) + sys.exit(0) + except Exception as e: + print(f"āŒ Server startup error: {e}", file=sys.stderr) + sys.exit(1)