#!/usr/bin/env python3 """ HTTP Server Entry Point for Nadlan-MCP. Serves three things on a single port: / → React SPA (search & browse Israeli real estate data) /api/... → REST endpoints used by the SPA (also documented at /api/docs) /mcp → FastMCP streamable-http endpoint (for LLM clients) For local Claude Desktop integration, use run_fastmcp_server.py (stdio). """ import logging import os import sys import uvicorn from nadlan_mcp.web_app import create_app logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", ) logger = logging.getLogger(__name__) # Module-level app for ASGI servers (uvicorn web_app:app, gunicorn, etc.). app = create_app() def main() -> None: port = int(os.environ.get("PORT", 8000)) host = "0.0.0.0" logger.info("=" * 60) logger.info("Starting Nadlan-MCP HTTP Server") logger.info("=" * 60) logger.info(f" UI: http://{host}:{port}/") logger.info(f" API docs: http://{host}:{port}/api/docs") logger.info(f" MCP: http://{host}:{port}/mcp") logger.info(f" Health: http://{host}:{port}/health") logger.info("=" * 60) try: # server_header=False stops uvicorn from advertising its name+version; # date_header=False is harmless and trims one more byte of fingerprint. # proxy_headers=True + forwarded_allow_ips="*" so request.client.host # reflects the real client IP behind Traefik (used by the rate limiter). uvicorn.run( app, host=host, port=port, log_level="info", server_header=False, proxy_headers=True, forwarded_allow_ips="*", ) except Exception as e: logger.error(f"Failed to start HTTP server: {e}", exc_info=True) sys.exit(1) if __name__ == "__main__": main()