Files
Cerbero-mcp/CLAUDE.md
T
Adriano 6faf21369d refactor(V2): get_historical & get_indicators are common-only on /mcp
Consolidate the cross-cutting data tools onto the unified interface and
remove their per-exchange duplicates.

- /mcp/tools/get_historical: single call, `exchange` now optional. Set →
  that venue's candles (native symbol); omitted → cross-exchange consensus
  (canonical symbol, median OHLC + div_pct). Folds in the former
  /mcp-cross consensus, whose router is deleted.
- /mcp/tools/get_indicators: new common tool computing sma/rsi/atr/macd/adx
  over the single-or-consensus series. Computation centralized in
  common/indicators.py::compute_indicators (was duplicated per exchange).
- Remove get_historical from /mcp-deribit and /mcp-hyperliquid; remove
  get_technical_indicators (deribit) and get_indicators (hyperliquid),
  including the now-dead client methods, Req schemas and tool wrappers.
  The client get_historical METHODS stay (used by the unified dispatch).

Tests: rewrite cross tests into test_unified (instruments, historical
single + consensus + failures, indicators single + consensus); drop the
old CrossClient test; tighten app-boot surface assertions (/mcp owns the
data tools; no /mcp-cross, no per-exchange historical/indicators).

Docs: API_REFERENCE / README / CLAUDE updated; smoke run_unified.sh now
covers consensus + indicators.

324 passed, ruff clean. Verified live against Deribit/Hyperliquid.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 10:51:21 +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); 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_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.