867180f4bf
Configura il gateway Caddy per il deploy su cerbero-mcp.tielogic.xyz: - Build custom Caddy con plugin mholt/caddy-ratelimit (Dockerfile + build via xcaddy). - TLS automatico via Let's Encrypt (richiede DNS A record + porte 80/443 raggiungibili), HSTS preload, header di sicurezza. - Rate limit per IP (60 req/min sui read, 10 req/min sui write, sliding window). - Allowlist IP sui write endpoint (place_*, cancel_*, set_*, close_*, transfer_*, amend_*, switch_*): IP non in WRITE_ALLOWLIST → 403. - Default WRITE_ALLOWLIST copre loopback + Docker bridge: bot sulla stessa macchina (host o container) funziona senza configurazione, IP pubblici esterni vanno aggiunti esplicitamente. - Smoke test e README aggiornati per il nuovo URL gateway. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
90 lines
3.3 KiB
Markdown
90 lines
3.3 KiB
Markdown
# Cerbero_mcp
|
|
|
|
Server MCP riusabili (exchange + market data) per la suite Cerbero.
|
|
Spinta da `Cerbero/` (commit `pre-split-2026-04-27`) come parte dello
|
|
split documentato in `docs/superpowers/specs/2026-04-27-split-mcp-core-design.md`
|
|
(nel repo storico).
|
|
|
|
## Servizi
|
|
- `mcp-alpaca`, `mcp-bybit`, `mcp-deribit`, `mcp-hyperliquid` — exchange
|
|
con `place_order`, `environment_info`, leverage cap server-side
|
|
- `mcp-deribit` e `mcp-bybit` espongono inoltre `place_combo_order`:
|
|
- Deribit: `private/create_combo` + ordine sul combo → 1 sola crociata
|
|
di spread invece di N (slippage atteso ridotto su strutture liquide).
|
|
- Bybit: `place_batch_order` su `category=option` → multi-leg atomico
|
|
in un solo round-trip API (no sconto fee, solo atomicità + latenza).
|
|
- `mcp-macro`, `mcp-sentiment` — read-only market data
|
|
|
|
## Avvio locale
|
|
|
|
```bash
|
|
docker compose up -d
|
|
bash tests/smoke/run.sh
|
|
```
|
|
|
|
## Configurazione
|
|
|
|
Vedi `secrets/*.json` e variabili `*_TESTNET` / `ALPACA_PAPER` in
|
|
`docker-compose.yml` per override ambiente.
|
|
|
|
### Deploy su VPS pubblica (`cerbero-mcp.tielogic.xyz`)
|
|
|
|
Il gateway Caddy è configurato per:
|
|
- TLS automatico via Let's Encrypt (richiede DNS A/AAAA che punti al
|
|
VPS e porte 80+443 raggiungibili).
|
|
- HSTS preload, header di sicurezza (`X-Content-Type-Options`,
|
|
`X-Frame-Options`, `Referrer-Policy`).
|
|
- Rate limit per IP (60 req/min su read, 10 req/min su write) tramite
|
|
plugin `mholt/caddy-ratelimit`.
|
|
- Allowlist IP sui write endpoint (`place_*`, `cancel_*`, `set_*`,
|
|
`close_*`, `transfer_*`, `amend_*`, `switch_*`): IP non presenti in
|
|
`WRITE_ALLOWLIST` ricevono `403 forbidden`.
|
|
|
|
Variabili d'ambiente per il deploy:
|
|
|
|
```bash
|
|
# .env (su VPS)
|
|
ACME_EMAIL=adrianodalpastro@tielogic.com
|
|
GATEWAY_HTTP_PORT=80
|
|
GATEWAY_HTTPS_PORT=443
|
|
|
|
# Allowlist write endpoint (CIDR space-separated). Default copre:
|
|
# - loopback IPv4/IPv6 (bot sull'host VPS chiama http://localhost)
|
|
# - Docker bridge 172.16.0.0/12 (bot in container nella stessa compose network)
|
|
# Aggiungi gli IP pubblici dei tuoi bot esterni se li hai.
|
|
WRITE_ALLOWLIST="127.0.0.1/32 ::1/128 172.16.0.0/12 1.2.3.4/32"
|
|
```
|
|
|
|
Tre scenari per il trading bot:
|
|
1. Bot container nella stessa compose network → chiama `http://gateway:80`
|
|
internamente. Source IP = Docker bridge → coperto dalla default.
|
|
2. Bot processo sull'host VPS → chiama `http://localhost`. Source IP =
|
|
`127.0.0.1` → coperto dalla default.
|
|
3. Bot esterno (laptop, altro server) → chiama
|
|
`https://cerbero-mcp.tielogic.xyz` con TLS. Devi aggiungere l'IP
|
|
pubblico del bot in `WRITE_ALLOWLIST`.
|
|
|
|
Senza configurare `WRITE_ALLOWLIST` la default è loopback + Docker bridge:
|
|
nessun IP pubblico esterno può triggerare ordini.
|
|
|
|
Sull'host VPS i secret devono avere permessi restrittivi:
|
|
|
|
```bash
|
|
chmod 600 secrets/*.json secrets/*.token
|
|
```
|
|
|
|
### Risoluzione environment (testnet/mainnet)
|
|
|
|
Ogni servizio exchange usa `mcp_common.environment.resolve_environment()`
|
|
che applica la precedenza:
|
|
|
|
1. env var di override (`DERIBIT_TESTNET`, `BYBIT_TESTNET`,
|
|
`HYPERLIQUID_TESTNET`, `ALPACA_PAPER`)
|
|
2. flag nel secret JSON (`testnet` o `paper` per alpaca)
|
|
3. default `testnet`
|
|
|
|
Gli URL canonici live/testnet sono passati come kwargs
|
|
`default_base_url_live` / `default_base_url_testnet` direttamente al
|
|
resolver — non serve duplicarli nel secret JSON, ma se presenti
|
|
prevalgono sui default del codice.
|