feat(V2): __main__ con lifespan + 6 router + integration test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,73 @@
|
|||||||
"""Entrypoint cerbero-mcp."""
|
"""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 __future__ import annotations
|
||||||
|
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
|
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, 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:
|
def main() -> None:
|
||||||
raise NotImplementedError("server da implementare nelle phase successive")
|
configure_root_logging()
|
||||||
|
settings = Settings()
|
||||||
|
app = _make_app(settings)
|
||||||
|
uvicorn.run(
|
||||||
|
app,
|
||||||
|
log_config=None,
|
||||||
|
host=settings.host,
|
||||||
|
port=settings.port,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
|
||||||
|
def test_app_boots_and_health_responds(monkeypatch):
|
||||||
|
from tests.unit.test_settings import _minimal_env
|
||||||
|
for k, v in _minimal_env().items():
|
||||||
|
monkeypatch.setenv(k, v)
|
||||||
|
|
||||||
|
from cerbero_mcp.__main__ import _make_app
|
||||||
|
from cerbero_mcp.settings import Settings
|
||||||
|
|
||||||
|
app = _make_app(Settings())
|
||||||
|
c = TestClient(app)
|
||||||
|
|
||||||
|
r = c.get("/health")
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert r.json()["status"] == "healthy"
|
||||||
|
|
||||||
|
r = c.get("/openapi.json")
|
||||||
|
assert r.status_code == 200
|
||||||
|
spec = r.json()
|
||||||
|
paths = spec["paths"].keys()
|
||||||
|
assert any(p.startswith("/mcp-deribit/") for p in paths)
|
||||||
|
assert any(p.startswith("/mcp-bybit/") for p in paths)
|
||||||
|
assert any(p.startswith("/mcp-hyperliquid/") for p in paths)
|
||||||
|
assert any(p.startswith("/mcp-alpaca/") for p in paths)
|
||||||
|
assert any(p.startswith("/mcp-macro/") for p in paths)
|
||||||
|
assert any(p.startswith("/mcp-sentiment/") for p in paths)
|
||||||
|
|
||||||
|
|
||||||
|
def test_apidocs_available_after_boot(monkeypatch):
|
||||||
|
from tests.unit.test_settings import _minimal_env
|
||||||
|
for k, v in _minimal_env().items():
|
||||||
|
monkeypatch.setenv(k, v)
|
||||||
|
|
||||||
|
from cerbero_mcp.__main__ import _make_app
|
||||||
|
from cerbero_mcp.settings import Settings
|
||||||
|
|
||||||
|
c = TestClient(_make_app(Settings()))
|
||||||
|
r = c.get("/apidocs")
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert "Cerbero MCP" in r.text
|
||||||
Reference in New Issue
Block a user