Files
Cerbero-mcp/tests/smoke/run_unified.sh
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

80 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Smoke test interfaccia comune /mcp contro un server vivo + upstream reali.
# get_instruments/get_historical/get_indicators di Deribit/Hyperliquid sono
# pubblici, ma bearer (testnet o mainnet) e X-Bot-Tag sono comunque richiesti.
set -euo pipefail
PORT="${PORT:-9000}"
BASE="${GATEWAY:-http://localhost:${PORT}}"
TOKEN="${MAINNET_TOKEN:-${TESTNET_TOKEN:-}}"
TAG="${BOT_TAG:-smoke}"
if [[ -z "${TOKEN}" ]]; then
echo "==> skip: né MAINNET_TOKEN né TESTNET_TOKEN settati"
exit 0
fi
PY="$(command -v python3 || command -v python)"
auth=(-H "Authorization: Bearer ${TOKEN}" -H "X-Bot-Tag: ${TAG}" -H "Content-Type: application/json")
start="$(date -u -d '7 days ago' +%F)"
end="$(date -u +%F)"
# post PATH JSON_BODY EXPECTED_STATUS PY_ASSERT
post() {
local path="$1" body="$2" want="$3" assert="${4:-}"
local resp status out
resp="$(curl -s -w '\n%{http_code}' -X POST "${BASE}${path}" "${auth[@]}" -d "${body}")"
status="$(printf '%s' "${resp}" | tail -n1)"
out="$(printf '%s' "${resp}" | sed '$d')"
if [[ "${status}" != "${want}" ]]; then
echo " FAIL ${path}: atteso HTTP ${want}, got ${status}"
printf '%s\n' "${out}" | head -c 400; echo
exit 1
fi
if [[ -n "${assert}" ]]; then
printf '%s' "${out}" | "${PY}" -c "import sys,json; d=json.load(sys.stdin); ${assert}" \
|| { echo " FAIL ${path}: assert"; exit 1; }
fi
echo " OK ${path} → HTTP ${status}"
}
echo "==> get_instruments exchange=deribit (fees + history_start live + meta)"
post "/mcp/tools/get_instruments" '{"exchange":"deribit","currency":"BTC","kind":"future"}' 200 \
"assert d['instruments']; i=d['instruments'][0]; assert i['exchange']=='deribit'; assert 'fees' in i and 'history_start' in i; assert 'has_more' in d['meta']['deribit']; print(' ', i['symbol'], i['fees'], i['history_start'], '| meta:', d['meta']['deribit'])"
echo "==> get_instruments deribit option chain paginato (kind=option, limit=5)"
post "/mcp/tools/get_instruments" '{"exchange":"deribit","currency":"BTC","kind":"option","limit":5,"offset":0}' 200 \
"assert len(d['instruments'])<=5; assert d['meta']['deribit']['limit']==5; print(' got:', len(d['instruments']), '| total:', d['meta']['deribit'].get('total'), '| has_more:', d['meta']['deribit'].get('has_more'))"
echo "==> get_instruments fan-out (deribit + hyperliquid)"
post "/mcp/tools/get_instruments" '{}' 200 \
"exs={i['exchange'] for i in d['instruments']}; assert {'deribit','hyperliquid'} <= exs, exs; print(' venues:', sorted(exs))"
echo "==> get_instruments NON più su /mcp-deribit → 404"
post "/mcp-deribit/tools/get_instruments" '{"currency":"BTC"}' 404
echo "==> get_historical SINGLE deribit BTC-PERPETUAL 1h"
post "/mcp/tools/get_historical" "{\"exchange\":\"deribit\",\"instrument\":\"BTC-PERPETUAL\",\"interval\":\"1h\",\"start_date\":\"${start}\",\"end_date\":\"${end}\"}" 200 \
"assert d['exchange']=='deribit'; assert d['candles']; c=d['candles'][0]; assert {'timestamp','open','high','low','close','volume'} <= set(c); print(' candles:', len(d['candles']))"
echo "==> get_historical SINGLE hyperliquid BTC 1h"
post "/mcp/tools/get_historical" "{\"exchange\":\"hyperliquid\",\"instrument\":\"BTC\",\"interval\":\"1h\",\"start_date\":\"${start}\",\"end_date\":\"${end}\"}" 200 \
"assert d['exchange']=='hyperliquid'; assert d['candles']; print(' candles:', len(d['candles']))"
echo "==> get_historical CONSENSUS (no exchange) BTC 1h"
post "/mcp/tools/get_historical" "{\"instrument\":\"BTC\",\"interval\":\"1h\",\"start_date\":\"${start}\",\"end_date\":\"${end}\"}" 200 \
"assert d['exchange'] is None; assert {'deribit','hyperliquid'} <= set(d['sources_used']), d['sources_used']; assert 'div_pct' in d['candles'][0]; print(' sources:', d['sources_used'], '| candles:', len(d['candles']))"
echo "==> get_indicators SINGLE deribit BTC-PERPETUAL"
post "/mcp/tools/get_indicators" "{\"exchange\":\"deribit\",\"instrument\":\"BTC-PERPETUAL\",\"indicators\":[\"rsi\",\"atr\",\"macd\"],\"interval\":\"1h\",\"start_date\":\"${start}\",\"end_date\":\"${end}\"}" 200 \
"assert set(d['indicators']) == {'rsi','atr','macd'}; print(' rsi:', d['indicators']['rsi'], '| candles_used:', d['candles_used'])"
echo "==> get_indicators CONSENSUS BTC"
post "/mcp/tools/get_indicators" "{\"instrument\":\"BTC\",\"indicators\":\"rsi,atr\",\"interval\":\"1h\",\"start_date\":\"${start}\",\"end_date\":\"${end}\"}" 200 \
"assert d['exchange'] is None; assert 'rsi' in d['indicators']; print(' sources:', d['sources_used'])"
echo "==> get_historical exchange non supportato → 422"
post "/mcp/tools/get_historical" "{\"exchange\":\"bybit\",\"instrument\":\"BTCUSDT\",\"interval\":\"1h\",\"start_date\":\"${start}\",\"end_date\":\"${end}\"}" 422
echo "==> SMOKE /mcp OK"