c4d3699669
- server_header=False — uvicorn was adding "server: uvicorn" after our middleware ran, defeating the banner-strip in security_headers(). - proxy_headers + forwarded_allow_ips=* — so request.client.host reflects the real client IP from X-Forwarded-For (Traefik), which is what the per-IP rate limiter keys on. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
63 lines
1.9 KiB
Python
63 lines
1.9 KiB
Python
#!/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()
|