Files
Cerbero-mcp/CLAUDE.md
T
Adriano 652e50ad99 docs(V2): update README + add CLAUDE.md for /mcp interface and Bybit/Alpaca retirement
- README: three active exchanges (Deribit/Hyperliquid/IBKR); document the
  unified /mcp interface (get_instruments uniform schema + per-exchange
  get_historical); drop Bybit/Alpaca from endpoints, tool list, audit
  filters, migration table and URL-override notes; update test count (323)
  and source layout (routers/unified.py, old/).
- CLAUDE.md: new project guide — commands (uv/pytest/ruff/mypy), runtime
  architecture, active exchanges, data interfaces, conventions.

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

92 lines
4.2 KiB
Markdown

# 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):
```bash
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.py``build_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__.py``build_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, raccomandata)** — `get_instruments` con schema uniforme
(ogni elemento porta `exchange`, `fees`, `history_start`, `type`, `tick_size`,
`native`); `get_historical` con `exchange` selezionabile (singolo venue).
Supporta deribit + hyperliquid (IBKR non ancora integrato).
- **`/mcp-cross`** — `get_historical` a consenso multi-exchange (mediana OHLC,
`sources`, `div_pct`).
- **`/mcp-{exchange}`** — router per-exchange legacy, ancora attivi.
Convenzione: ogni `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`.
## 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.