"""Entrypoint cerbero-mcp. Boot: - carica Settings da .env - costruisce app FastAPI con router per ogni exchange - crea ClientRegistry con builder - monta lifespan per chiusura pulita - avvia uvicorn """ from __future__ import annotations import contextlib from contextlib import asynccontextmanager from typing import Literal, cast import uvicorn from fastapi import FastAPI from cerbero_mcp import admin from cerbero_mcp.client_registry import ClientRegistry from cerbero_mcp.common.logging import configure_root_logging from cerbero_mcp.exchanges import build_client from cerbero_mcp.routers import ( deribit, hyperliquid, ibkr, macro, sentiment, unified, ) from cerbero_mcp.server import build_app from cerbero_mcp.settings import Settings def _make_app(settings: Settings) -> FastAPI: app = build_app( testnet_token=settings.testnet_token.get_secret_value(), mainnet_token=settings.mainnet_token.get_secret_value(), title="Cerbero MCP", version="2.0.0", ) app.state.settings = settings async def builder(exchange: str, env: str): return await build_client( settings, exchange, cast(Literal["testnet", "mainnet"], env) ) app.state.registry = ClientRegistry(builder=builder) @asynccontextmanager async def lifespan(app: FastAPI): try: yield finally: # Stop any IBKR WebSocket singletons before closing client registry ibkr_ws_dict = getattr(app.state, "ibkr_ws", {}) or {} for ws in ibkr_ws_dict.values(): with contextlib.suppress(Exception): await ws.stop() await app.state.registry.aclose() app.router.lifespan_context = lifespan app.include_router(deribit.make_router()) app.include_router(hyperliquid.make_router()) app.include_router(ibkr.make_router()) app.include_router(macro.make_router()) app.include_router(sentiment.make_router()) app.include_router(unified.make_router()) app.include_router(admin.make_admin_router()) return app def main() -> None: configure_root_logging() settings = Settings() # type: ignore[call-arg] app = _make_app(settings) uvicorn.run( app, log_config=None, host=settings.host, port=settings.port, ) if __name__ == "__main__": main()