Files
Cerbero-Bite/docs/04-mcp-integration.md
T
Adriano 881bc8a1bf Phase 0: project skeleton
- pyproject.toml with uv, deps for runtime + gui + backtest + dev
- ruff/mypy strict config, pre-commit hooks for ruff/mypy/pytest
- src/cerbero_bite/ layout with empty modules ready for Phase 1+
- structlog JSONL logger with daily rotation
- click CLI with placeholder subcommands (status, start, kill-switch,
  gui, replay, config hash, audit verify)
- 6 smoke tests passing, mypy --strict clean, ruff clean

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 23:10:30 +02:00

8.4 KiB

04 — MCP Integration

Tutti i server MCP sono già configurati a livello di CerberoSuite (vedi Cerbero_Office/.mcp.json). Cerbero Bite vi si connette come client MCP usando l'SDK ufficiale mcp per Python.

Configurazione di connessione

Cerbero Bite legge ~/.config/cerbero-suite/mcp.json (o, in dev, da .mcp.json locale puntato via env var CERBERO_BITE_MCP_CONFIG). I server vengono risolti per nome dichiarato nel file di config.

# clients/_base.py — abstract
class McpClient:
    name: str                        # "cerbero-deribit", ecc.
    timeout_s: float = 8.0
    retry_max: int = 3
    retry_base_delay: float = 1.0    # esponenziale

    async def call(self, tool: str, **params) -> dict: ...

Ogni wrapper concreto eredita McpClient ed espone metodi tipizzati. La logica di retry e timeout è centralizzata.

Server MCP usati

cerbero-deribit

Tool consumati:

Tool Uso Frequenza
get_index_price(asset="ETH") Spot ETH per calcolo strike Ogni ciclo entry + monitor
get_dvol() Volatilità implicita aggregata ETH Ogni ciclo entry + monitor
get_options_chain(asset, expiry_window) Lista strumenti per dato DTE Solo entry
get_instrument(instrument_name) Mid, bid, ask, greche su singolo strumento Entry + monitor
get_orderbook(instrument_name, depth=5) Profondità per liquidity_gate e slippage Solo entry
get_combo_mark(legs) Mark price del combo (debito di chiusura) Solo monitor
get_account_summary(currency="USDC") Equity Deribit, margin libero Periodico

Wrapper:

# clients/deribit.py
class DeribitClient(McpClient):
    name = "cerbero-deribit"

    async def index_price(self, asset: str) -> Decimal: ...
    async def dvol(self) -> Decimal: ...
    async def options_chain(self, asset: str, dte_min: int, dte_max: int) -> list[InstrumentSnapshot]: ...
    async def instrument(self, name: str) -> InstrumentSnapshot: ...
    async def orderbook(self, name: str, depth: int = 5) -> OrderbookSnapshot: ...
    async def combo_mark(self, legs: list[OptionLeg]) -> Decimal: ...
    async def account_summary(self) -> AccountSummary: ...

Note:

  • Tutti i prezzi sono ricevuti come float dal MCP, convertiti in Decimal con quantize a 6 cifre nel wrapper.
  • Greche convertite con la stessa quantizzazione.
  • Se mark_iv = 7% o 300% o bid = 0 su orderbook ATM su tutti gli strumenti → wrapper solleva DeribitDataAnomalyError (probabile testnet o feed rotto). Il decision orchestrator cattura, alert, skippa il ciclo.

cerbero-hyperliquid

Tool Uso
get_perp_funding_rate(asset="ETH") Filtro entry §2.6
get_perp_summary(asset="ETH") Volume 24h, conferma liquidità correlata
get_account_summary() Solo per coerenza, non usato in decision loop
class HyperliquidClient(McpClient):
    async def funding_rate_annualized(self, asset: str) -> Decimal: ...
    async def perp_summary(self, asset: str) -> PerpSummary: ...

cerbero-sentiment

Tool Uso
get_funding_cross_exchange(asset="ETH") Bias direzionale §3.1 (mediana 4 maggiori)

Le news qualitative non sono usate nel decision loop (no LLM). Vengono eventualmente lette da Adriano in occasione del report settimanale.

class SentimentClient(McpClient):
    async def funding_cross_median(self, asset: str) -> Decimal: ...

cerbero-macro

Tool Uso
get_calendar(days_ahead=18) Filtro eventi macro pre-entry

Eventi rilevanti (filtra per severity = high e country in {US, EU}): FOMC, FED minutes, CPI, NFP, ECB, GDP, Powell speech, Lagarde speech.

class MacroClient(McpClient):
    async def upcoming_events(self, days_ahead: int) -> list[MacroEvent]: ...
    async def first_high_severity_within(self, days: int) -> int | None:
        """Days until first high-severity event, None if none in window."""

cerbero-portfolio

Tool Uso
get_holdings() Capitale corrente complessivo
get_holdings_by_asset() Filtro entry §2.7 (ETH < 30% portfolio)
get_correlation() Sanity check, non bloccante
class PortfolioClient(McpClient):
    async def total_equity_usd(self) -> Decimal: ...
    async def asset_pct(self, asset: str) -> Decimal: ...

cerbero-memory

Tool Uso
push_user_instruction(payload, source="cerbero-bite") Invio istruzione apertura/chiusura a Cerbero core
get_pending(source="cerbero-bite") Verifica ack di Cerbero core
class MemoryClient(McpClient):
    async def push_instruction(self, instruction: CerberoInstruction) -> str:
        """Returns instruction_id."""
    async def is_acknowledged(self, instruction_id: str) -> bool: ...

Payload CerberoInstruction (schema condiviso con Cerbero core, documentato in Cerbero/prompt.base v4):

{
  "source": "cerbero-bite",
  "kind": "open_combo" | "close_combo",
  "exchange": "deribit",
  "asset": "ETH",
  "proposal_id": "uuid-...",
  "legs": [
    {"instrument": "ETH-13MAY26-1900-P", "side": "SELL", "size": 2,
     "limit_price_eth": "0.0048"},
    {"instrument": "ETH-13MAY26-1810-P", "side": "BUY", "size": 2,
     "limit_price_eth": "0.0021"}
  ],
  "limit_combo_eth": "0.0027",
  "tif": "GTC",
  "expires_at": "2026-04-27T16:00:00Z",
  "max_slippage_eth": "0.0005",
  "reason": "weekly_open" | "profit_take" | "stop_loss" | "vol_stop" |
            "time_stop" | "delta_breach" | "adverse_move",
  "milestone": "advisory_only" | "approved_by_user"
}

Cerbero core deduplica per proposal_id (idempotenza in caso di retry).

cerbero-telegram

Tool Uso
send_message(text, parse_mode="MarkdownV2") Report pre/post trade, alert
send_with_buttons(text, buttons) Conferma ad Adriano (yes/no)

Le conferme devono ritornare entro 60 minuti (entry) o 30 minuti (exit). Implementazione: l'engine si mette in await su una coda interna alimentata dal callback Telegram via webhook locale.

class TelegramClient(McpClient):
    async def send(self, text: str, parse_mode: str = "MarkdownV2") -> int: ...
    async def request_confirmation(self, text: str, timeout_s: int) -> bool: ...

cerbero-brain-bridge

Tool Uso
kb_search(query) Lookup pre-trade su pattern simili (consultivo)
kb_read(path) Lettura nota wiki specifica
kb_write(path, content) Salvataggio learning post-trade

Importante: il brain-bridge non partecipa al decision loop. Le chiamate kb_search sono consultive e i risultati allegati al report di Adriano per contesto, mai consumati come input ai filtri deterministici.

class BrainBridgeClient(McpClient):
    async def search(self, query: str, limit: int = 5) -> list[KbHit]: ...
    async def write_note(self, path: str, content: str) -> None: ...

cerbero-scheduler

Non usato dal decision loop. Cerbero Bite ha il proprio scheduler APScheduler interno. Il MCP scheduler resta a disposizione del core Cerbero per altre routine.

Errori e degradation

Server down Comportamento
cerbero-deribit Skip ciclo entry; per monitor → alert e marca posizione come unknown_state (non chiude alla cieca)
cerbero-hyperliquid Skip filtro funding §2.6 con warning; entry può proseguire se altre condizioni soddisfatte
cerbero-sentiment Bias §3.1 cade in no_entry per default (no funding cross → niente direzione)
cerbero-macro Hard fail: senza calendar non si apre. È un filtro irrinunciabile
cerbero-portfolio Skip filtro §2.7 con warning; sizing usa ultimo capitale noto da SQLite con warning
cerbero-memory Hard fail per esecuzione: senza push_user_instruction non si può aprire/chiudere
cerbero-telegram Skip ciclo: senza canale di conferma niente proposta
cerbero-brain-bridge Skip lookup, log warning. Mai bloccante

Ogni "hard fail" → alert sonoro su Telegram via canale di backup (BotPapà), kill switch armato fino al ripristino.

Versioning

Cerbero Bite verifica all'avvio la versione di ciascun MCP via get_version() (tool standard). Schema di versioning attesa:

EXPECTED_MCP_VERSIONS = {
    "cerbero-deribit": "^2.0.0",
    "cerbero-hyperliquid": "^1.5.0",
    "cerbero-memory": "^4.0.0",
    "cerbero-portfolio": "^1.2.0",
    ...
}

Mismatch → kill switch e alert manuale. Mai partire con MCP a versione incompatibile.