"""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 from contextlib import asynccontextmanager from typing import Literal, cast import uvicorn from fastapi import FastAPI 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 ( alpaca, bybit, deribit, hyperliquid, macro, sentiment, ) 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: await app.state.registry.aclose() app.router.lifespan_context = lifespan app.include_router(deribit.make_router()) app.include_router(bybit.make_router()) app.include_router(hyperliquid.make_router()) app.include_router(alpaca.make_router()) app.include_router(macro.make_router()) app.include_router(sentiment.make_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()