Skip to main content
Glama
hingaibm

Data Intelligence MCP Server

by hingaibm
main.py9.22 kB
#!/usr/bin/env python3 # Copyright [2025] [IBM] # Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) # See the LICENSE file in the project root for license information. # This file has been modified with the assistance of IBM Bob AI tool """WXDI MCP Server""" import argparse import importlib import pkgutil import sys import os from pathlib import Path from typing import Any from fastmcp import FastMCP import app.services from app.core.registry import prompt_registry, service_registry from app.core.settings import settings # Ensure the project root is in the Python path for module resolution project_root = Path(__file__).parent.parent if str(project_root) not in sys.path: sys.path.insert(0, str(project_root)) def _import_modules_from_path(module_path: Path, package_prefix: str, module_type: str): """Helper function to import all modules from a given path. Args: module_path: Path to the directory containing modules package_prefix: Package prefix for module names (e.g., "app.services.search.tools") module_type: Type of module for error messages (e.g., "tool", "prompt") """ if not module_path.is_dir(): return # First, import the package itself to trigger the __init__.py importlib.import_module(package_prefix) # Then, iterate over any other modules that might not be in __init__.py for _, module_name, _ in pkgutil.iter_modules([str(module_path)], f"{package_prefix}."): try: importlib.import_module(module_name) except ImportError as e: print(f"Warning: Could not import {module_type} module '{module_name}': {e}", file=sys.stderr) def discover_and_import_services(package): """Dynamically imports all tool and prompt modules to trigger registration decorators.""" for _, service_name, _ in pkgutil.iter_modules(package.__path__, package.__name__ + "."): service_module = importlib.import_module(service_name) service_path = Path(service_module.__file__).parent # Discover and import tools tools_path = service_path / "tools" _import_modules_from_path(tools_path, f"{service_name}.tools", "tool") # Discover and import prompts prompts_path = service_path / "prompts" _import_modules_from_path(prompts_path, f"{service_name}.prompts", "prompt") def create_server() -> FastMCP: """Creates and configures the MCP server.""" print("Discovering services...", file=sys.stderr) discover_and_import_services(app.services) mcp = FastMCP("WXDI MCP Server", version="1.0.0") # Register tools first to get the actual count service_registry.register_all(mcp) actual_registered_count = service_registry.get_registered_count() print(f"Registering {actual_registered_count} discovered tools...", file=sys.stderr) print("✅ Tool registration complete.", file=sys.stderr) # Register prompts prompt_registry.register_all(mcp) actual_prompt_count = prompt_registry.get_registered_count() if actual_prompt_count > 0: print(f"Registering {actual_prompt_count} discovered prompts...", file=sys.stderr) print("✅ Prompt registration complete.", file=sys.stderr) return mcp def apply_cli_settings_overrides(args): """Apply command line argument overrides to settings and print notifications. Args: args: Parsed command line arguments """ if args.transport != settings.server_transport: settings.server_transport = args.transport print(f"ℹ Transport overridden via CLI: {args.transport}", file=sys.stderr) if args.di_url != settings.di_service_url: settings.di_service_url = args.di_url print(f"Data Intelligence service URL overridden via CLI: {args.di_url}", file=sys.stderr) if args.wxo: settings.wxo = True print("✅ Watsonx orchestrator compatibility mode enabled", file=sys.stderr) else: settings.wxo = False def main(): """Main server entry point.""" parser = argparse.ArgumentParser(description="IKC MCP Server") parser.add_argument("--transport", choices=["stdio", "http"], default=settings.server_transport, help="Transport protocol") parser.add_argument("--host", default=settings.server_host, help="Server host address") parser.add_argument("--port", type=int, default=settings.server_port, help="Server port number") parser.add_argument("--ssl-cert", help="Path to SSL certificate file") parser.add_argument("--ssl-key", help="Path to SSL private key file") parser.add_argument("--di-url", default=settings.di_service_url, help="Data Intelligence service URL") parser.add_argument("--wxo", action="store_true", help="Enable watsonx orchestrator compatibility mode") args = parser.parse_args() apply_cli_settings_overrides(args) print(" Starting IKC MCP Server...", file=sys.stderr) print(f" Transport: {args.transport}", file=sys.stderr) try: mcp = create_server() # Get the actual registered count after registration actual_registered_count = service_registry.get_registered_count() print(f"✅ Server initialized with {actual_registered_count} registered tools.", file=sys.stderr) if args.transport == "http": # Initialize protocol and port for display protocol = "http" port = args.port kwargs = { "transport": "streamable-http", "host": args.host, "port": args.port, "stateless_http": True } # Configure uvicorn for high concurrency handling uvicorn_config: dict[str, Any] = { "limit_concurrency": settings.server_limit_concurrency, "timeout_keep_alive": settings.server_timeout_keep_alive, "backlog": settings.server_backlog, } kwargs["uvicorn_config"] = uvicorn_config print( f" Server concurrency settings: " f"limit_concurrency={settings.server_limit_concurrency}, " f"timeout_keep_alive={settings.server_timeout_keep_alive}s, " f"backlog={settings.server_backlog}", file=sys.stderr ) # Add SSL configuration if certificate and key are provided ssl_cert = args.ssl_cert or settings.ssl_cert_path ssl_key = args.ssl_key or settings.ssl_key_path if not settings.use_https: highlight = "\033[1;33m" # Bold yellow reset = "\033[0m" # Reset formatting print(f"⚠️ WARNING: Starting server in HTTP mode because {highlight}SERVER_HTTPS=False{reset}.", file=sys.stderr) # Check if we should use HTTPS based on settings if settings.use_https: # If certificates are available, configure HTTPS if ssl_cert and ssl_key: ciphers = [ "ECDHE-ECDSA-AES256-GCM-SHA384", "ECDHE-RSA-AES256-GCM-SHA384", "ECDHE-ECDSA-AES128-GCM-SHA256", "ECDHE-RSA-AES128-GCM-SHA256", "DHE-RSA-AES128-GCM-SHA256", "DHE-RSA-AES256-GCM-SHA384", ] kwargs["port"] = 443 port = 443 # Update port for display protocol = "https" # Ensure protocol is https # Merge SSL configuration with existing uvicorn_config uvicorn_config["ssl_keyfile"] = ssl_key uvicorn_config["ssl_certfile"] = ssl_cert uvicorn_config["ssl_ciphers"] = ":".join(ciphers) kwargs["uvicorn_config"] = uvicorn_config else: # No certificates found, but HTTPS is required error_msg = ( "Server cert and key not found. MCP server is by default started in HTTPS mode. " "Either set SSL_CERT_PATH and SSL_KEY_PATH environment variables or provide " "the cert/keys via --ssl-cert and --ssl-key options OR set SERVER_HTTPS=False " "to start the server without HTTPS (i.e., HTTP). For details on cert/key generation for HTTPS, " "pls. refer to https://github.com/IBM/data-intelligence-mcp-server/blob/main/readme_guides/SERVER_HTTPS.md" ) print(f"❌ Error: {error_msg}", file=sys.stderr) sys.exit(1) # Print address with correct protocol and port print(f" Address: {protocol}://{args.host}:{port}", file=sys.stderr) mcp.run(**kwargs) else: mcp.run() # Default stdio transport except Exception as e: print(f"❌ Failed to start server: {e}", file=sys.stderr) sys.exit(1) if __name__ == "__main__": main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hingaibm/data-intelligence-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server