#!/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)" 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; print(' ', i['symbol'], i['fees'], i['history_start'])" 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_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"