Files
Cerbero-mcp/CLAUDE.md
T
Adriano 8d7e2ca30f refactor(V2): get_instruments common-only on /mcp (enriched with Deribit filters)
Move get_instruments off the per-exchange Deribit router and onto the
unified interface, without losing the advanced Deribit filtering.

- /mcp/tools/get_instruments now accepts the Deribit-specific filters
  (currency, kind, expiry_from/to, strike_min/max, min_open_interest) and
  pagination (offset/limit). Venues that list everything (Hyperliquid)
  ignore them. Response adds `meta: {deribit: {total, offset, limit,
  has_more}}` surfacing per-source pagination.
- Remove /mcp-deribit/tools/get_instruments (endpoint + tool wrapper +
  GetInstrumentsReq schema). The DeribitClient.get_instruments METHOD
  stays — it's what the unified normalizer calls.

Tests: cover the enriched filters + meta passthrough; app-boot asserts
/mcp-deribit/tools/get_instruments is gone. Docs (API_REFERENCE/README/
CLAUDE) and smoke updated; also fixed the stale Hyperliquid tool count
(14 → 15) found during the doc check.

325 passed, ruff clean. Verified live: kind=option limit=5 → 5/940
has_more=true; /mcp-deribit/tools/get_instruments → 404.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 11:06:09 +00:00

4.4 KiB

CLAUDE.md

Guida per Claude Code che lavora su Cerbero MCP — server MCP multi-exchange (FastAPI) distribuito come singola immagine Docker, con routing testnet/mainnet per-request basato sul token bearer.

Comandi

Gestione progetto con uv (Python ≥ 3.11):

uv sync                          # installa dipendenze (incl. dev)
uv run cerbero-mcp               # avvia il server (porta da .env, default 9000)
uv run pytest                    # suite completa (~323 test attesi)
uv run pytest tests/unit -v      # solo unit
uv run pytest tests/unit/exchanges/cross/test_unified.py::test_get_historical_single_exchange  # singolo test
uv run ruff check src tests      # lint (E,F,I,W,UP,B,SIM; line-length 100)
uv run mypy src/cerbero_mcp      # type check (non-strict)

Tutti e quattro (pytest, ruff, mypy) devono essere verdi prima di committare. testpaths = ["tests"]old/ non viene mai raccolto dai test.

Architettura

Flusso runtime:

Bot → Authorization: Bearer <TESTNET|MAINNET>_TOKEN  (+ header X-Bot-Tag)
   → auth middleware → request.state.environment ∈ {testnet, mainnet}
   → Router  (/mcp/... , /mcp-{exchange}/... , /mcp-cross/...)
   → ClientRegistry.get(exchange, env) → client cached lazy per (exchange, env)
   → tool function (logica pura) → exchange API

File chiave:

  • src/cerbero_mcp/__main__.py_make_app() registra tutti i router.
  • src/cerbero_mcp/server.pybuild_app(), Swagger, exception handler, e _TimestampInjectorMiddleware che inietta data_timestamp (ISO UTC) nel top level di ogni risposta JSON sotto /tools/* (+ header X-Data-Timestamp).
  • src/cerbero_mcp/auth.py — bearer → env, e X-Bot-Tag obbligatorio (path whitelisted: /health, /health/ready, /apidocs, /openapi.json).
  • src/cerbero_mcp/client_registry.py — cache {(exchange, env): client}.
  • src/cerbero_mcp/exchanges/__init__.pybuild_client(): factory per exchange.
  • src/cerbero_mcp/settings.py — Pydantic Settings da .env.
  • src/cerbero_mcp/routers/ — un file per exchange + unified.py (/mcp) + cross.py (/mcp-cross).
  • src/cerbero_mcp/exchanges/<ex>/{client.py,tools.py} — client HTTP + schemi Pydantic / wrapper tool. cross/ contiene aggregatore consensus, interfaccia unificata, normalizzatori e symbol-map.

Exchange attivi

Trading: deribit, hyperliquid, ibkr. Data-provider read-only: macro, sentiment. Bybit e Alpaca sono ritirati dalla superficie API in V2: codice archiviato in old/ (fuori dal package, non importato, non testato). Nota: nel modulo sentiment "bybit" resta come fonte dati pubblica (funding/OI), non come client di trading.

Interfacce dati

  • /mcp (comune) — gli unici tool dati trasversali. get_instruments (schema uniforme: exchange, fees, history_start, type, tick_size, native; filtri/paginazione Deribit + meta per-sorgente); get_historical e get_indicators con exchange opzionale → singolo venue se valorizzato, consenso multi-exchange (mediana OHLC + div_pct) se omesso. Supporta deribit + hyperliquid (IBKR non integrato).
  • /mcp-{exchange} — router per-exchange per il resto (ticker, ordini, options analytics, …). NON espongono più get_instruments/get_historical/get_indicators.

Convenzione: get_historical ritorna la chiave uniforme candles: [{timestamp(ms), open, high, low, close, volume}] (validatore in common/candles.py). fees/history_start sono popolati live dove l'upstream li espone (oggi: Deribit), altrimenti null. Il calcolo indicatori è centralizzato in common/indicators.py::compute_indicators.

Convenzioni

  • Schemi richiesta = modelli Pydantic in <ex>/tools.py; il router fa solo dependency-injection di env + client e chiama il wrapper del tool.
  • Errori applicativi: sollevare fastapi.HTTPException; gli handler in server.py li avvolgono in un envelope con request_id.
  • Firme/crittografia: il signing L1 Hyperliquid usa eth_utils.to_hex come l'SDK ufficiale → r/s hex possono essere < 66 char (byte alto a zero, ~1/256); non assumere lunghezza fissa.
  • Branch di produzione: V2.0.0 (non main). Deploy via scripts/deploy-vps.sh.

Documentazione

  • README.md — overview, setup, deploy, migrazione V1→V2, IBKR OAuth.
  • docs/API_REFERENCE.md — catalogo completo endpoint/tool. Aggiornarlo quando si aggiungono/rimuovono tool o si cambiano gli schemi.