Agents IA

Serveur MCP crypto pour agents IA

Un agent IA se connecte, découvre onze outils, lit leurs descriptions pour comprendre quelles données existent, et compose ses propres requêtes. Aucune URL à construire, aucun schéma REST à analyser.

Le serveur parle le protocole MCP sur transport HTTP. Il relaie chaque appel vers l’API avec votre clé, sous les noms, unités et conventions de l’API, et présente le résultat pour un agent IA : lignes compactes, résumé par série, taille bornée.

#Connecter votre IA au serveur MCP crypto

Une URL et un en-tête. Le serveur est fermé par défaut : sans X-API-KEY valide, aucun outil n’est annoncé et toute requête est refusée en 401 (X-Deny-Reason: missing_api_key si l’en-tête est absent, invalid_api_key si la clé est inconnue ou révoquée).

{
  "mcpServers": {
    "bytnode": {
      "type": "http",
      "url": "https://api.bytnode.com/mcp",
      "headers": { "X-API-KEY": "your_key" }
    }
  }
}

La forme exacte du fichier de configuration dépend de l’agent IA, et le bloc générique ci-dessus ne convient pas à tous : Claude Desktop, ChatGPT et Gemini CLI le lisent autrement. La page du serveur MCP donne la config prête à coller de chaque client : Claude Desktop, Claude Code, ChatGPT, Cursor, Codex, VS Code, LangChain, n8n et d’autres.

Le transport est Streamable HTTP sans session : chaque requête se suffit à elle-même. serverInfo.version est la version de la surface MCP (1.0.0) — ses outils, ses instructions et la forme de ses réponses —, distincte de la version du contrat de l’API (1.0.2) ; chaque réponse la répète dans mcp_version. Certains clients gardent les définitions d’outils reçues à la connexion : quand mcp_version change (une nouvelle version majeure signale un changement auquel s’adapter), reconnectez le connecteur pour charger les nouvelles. Les capacités n’annoncent que ce qui existe — outils et ressources, sans notification listChanged — et une ressource inconnue répond l’erreur JSON-RPC -32002. Le CORS est ouvert sur /mcp : un client MCP qui tourne dans un navigateur peut se connecter. Les connecteurs qui se connectent par OAuth (claude.ai, ChatGPT, Claude Code) n’ont besoin d’aucune clé : une requête sans clé reçoit 401 avec WWW-Authenticate: Bearer resource_metadata=…, qui désigne le serveur d’autorisation, bytnode.com, où vous approuvez la connexion. Sinon, la clé passe dans l’en-tête X-API-KEY, ou en Authorization: Bearer. Sans clé, la fiche du serveur https://api.bytnode.com/.well-known/mcp/server-card.json décrit toute la surface (outils, ressources, version, authentification), et /mcp/server.json est son entrée pour le registre officiel MCP.

#Les onze outils de données du marché crypto

Les onze sont en lecture seule, sans effet de bord et idempotents : un agent IA peut les rejouer sans risque. Les cinq outils de données ont chacun leur cible — une paire, un actif, tout le marché, la macro, l’on-chain — et fonctionnent de la même façon : fields (les noms des champs à rendre), limit, since_ms / until_ms, last, columns, detail et max_tokens (détaillés sous get_pair_data) veulent dire la même chose dans chacun, chaque réponse porte server_time et response_tokens, et leurs conventions communes — modes, fenêtres, résumé, unités, budget de taille — sont dans les instructions du serveur, envoyées une fois à la connexion plutôt que répétées dans chaque description. rank_pairs classe toutes les paires sur une métrique, et read_export lit la suite d’une réponse coupée par son budget.

get_system_info

Votre offre et, à la demande, les paires servies, la fraîcheur des données et les catalogues dont un agent IA a besoin pour cibler un champ. Il rend toujours la santé du service et plan : l’offre de votre clé — ses familles, sa profondeur d’historique par timeframe, son débit et le quota restant —, sans décompte dans votre quota. include ajoute la liste vivante des paires et/ou un résumé de fraîcheur, freshness_fields la fraîcheur de champs précis, catalogs les séries qu’attend get_macro_data ou les capacités d’une paire. Chaque partie demandée compte une requête.

ParamètreTypeDéfautDescription
includestring[]—Parmi symbols (la liste vivante des paires servies) et freshness (le résumé de fraîcheur des données : state, stale_fields, stale_feeds). Les deux à la fois.
freshness_fieldsstring[]—Les noms de champs, de n’importe quel outil de données, dont vous voulez la fraîcheur : par champ, age_s et is_stale. Implique freshness.
catalogsstring[]—Parmi macro_series et macro_intraday_series (les séries de get_macro_data, les secondes avec leurs timeframes), symbol_capabilities. Plusieurs à la fois.
symbolstring—Requis par symbol_capabilities : quels flux sont actifs, quelles métriques sont disponibles ou bloquées, avant de les demander.
categorystring—Filtre le catalogue macro_series.

get_pair_brief

L’état d’une paire en un appel, toujours sous la même forme, sans champ à choisir : price_change (le prix et ses variations glissantes), funding_next, le dernier basis, l’oi (avec oi_usd) et le cvd du dernier bucket 1h clos, les liquidations des dernières 24 heures en un objet (liquidations_24h : from et to, le début du premier et du dernier bucket d’1h, long_usd, short_usd, total_usd, bucket_count) et l’indice Fear & Greed (fear_greed). Chaque valeur est un objet à plat : aucune série à lire, aucun total à chercher dans summary. Elle coûte environ une requête de quota par paire, plus une. Pour tout le reste — d’autres champs, un historique, un autre pas —, get_pair_data. Il lit des valeurs courantes : en Free, qui n’a pas la famille snapshot, il est refusé, et get_pair_data avec last: "1h" donne les derniers points.

ParamètreTypeDéfautDescription
symbolstring[]—Requis : une paire, ex. BTCUSDT, ou une liste de 10 paires au plus pour les comparer ; avec plusieurs, chaque clé est précédée de sa paire (BTCUSDT/funding_next), et fear_greed, de tout le marché, vient une fois.

get_pair_data

Les données de marché d’une paire, ou de dix au plus comparées en un appel : prix et bougies, transactions, carnet et flux d’ordres, dérivés (open interest, funding, basis, liquidations) et tokenomics. Un appel, plusieurs champs, valeur courante ou historique daté. Les champs servis par le snapshot REST partagent une seule requête par paire ; les autres (les gros trades, par exemple) partent sur leur propre route, en parallèle. fields liste les champs à rendre, limit le nombre de derniers points de chaque série.

ParamètreTypeDéfautDescription
symbolstring[]—Requis : la paire, ex. BTCUSDT, ou une liste de 10 paires au plus pour les comparer : les requêtes se comptent par paire, chaque clé devient paire/champ (ETHUSDT/funding_next), et une paire refusée n’empêche pas les autres (errors, partial). La liste vivante vient de get_system_info.
fieldsstring[]—Requis : les champs à rendre, plusieurs par appel, parmi les 24 noms de cet outil (listés plus bas). Un champ d’un autre outil est refusé avec le nom de son outil.
limitinteger—Les N derniers points de chaque série ; par défaut, le dernier (avec un timeframe, les N derniers buckets). Un champ en valeur courante seule comme price_change rend un point ; un limit au-delà du maximum propre d’un champ (1000 pour une série, 10000 pour les trades individuels) est plafonné, et warnings le dit. Avec une fenêtre, un plafond de points par série. describe_fields dit ce que compte N.
timeframestring1hPas des champs marqués timeframe. Absent : 1h en valeur courante ; en historique, un pas qui donne environ 200 points. 1w : klines seulement.
livebooleanfalseValeur courante seulement : ajoute la bougie en formation, marquée is_closed: false.
since_ms / until_msstring—Les bornes d’une fenêtre datée : millisecondes epoch, une date ISO 8601 (2026-10-20T00:00:00Z ; sans fuseau, UTC) ou une durée écoulée ('48h', '30d' ; unités m, h, d, w). Présente : chaque champ demandé rend son historique.
laststring—L’historique sur la durée donnée ('48h', '30d') en buckets clos entiers : since_ms recule au début de son bucket, si bien que last: '7d' en 1h rend 168 bougies, contre 167 avec since_ms: '7d'. Il remplace since_ms (les deux ensemble sont refusés) ; until_ms peut en fixer la fin.
min_usdnumber—Seuil USD de trades_large (défaut 100 000, minimum 1 000) et de liquidations_events.
marketstringallMarché de cvd, buy_sell_ratio, trades_avg_size et orderbook : all (spot + futures perpétuels), spot ou futures. L’outil le traduit en la route de ce marché.
columnsstring—Les colonnes à garder dans chaque ligne, en liste (p. ex. ["close", "volume"] ; une chaîne CSV est acceptée aussi), notation pointée pour les champs imbriqués — l’équivalent de ?fields= dans l’API REST (ici, fields nomme les champs de données). Appliquée champ par champ : une colonne présente dans au moins un champ demandé s’applique là où elle existe, et warnings dit où elle a été ignorée ; une colonne inconnue de tous les champs est refusée, avec une suggestion. Prime sur detail.
detailstringcompactcompact : les colonnes principales des lignes lourdes, is_closed retiré quand chaque ligne est close, identifiants de trades retirés ; omitted_columns nomme ce qui a été laissé. full : toutes les colonnes.
max_tokensinteger6000Budget de la réponse en jetons estimés, de 1 500 à 16 000 (défaut 6 000). Le même paramètre sur chaque outil de données, get_market_indicators, rank_pairs et read_export.

get_options_data

Les options et les ETF spot d’un actif : résumé des options, open interest, volume, put/call, volatilité implicite, max pain, grecques, OI par strike, et etf_fundamentals (les déclarations trimestrielles à la SEC des ETF spot par émetteur ; pas de flux quotidiens). expiries: true ajoute les échéances actives avec, par échéance, l’OI des calls et des puts, le put/call, le max pain, les principaux strikes et l’IV ATM ; options_summary et options_put_call_ratio sont des totaux sur toutes les échéances.

ParamètreTypeDéfautDescription
assetstring—Requis : l’actif seul, ex. BTC, jamais une paire.
fieldsstring[]—Les champs à rendre, parmi les 11 noms de cet outil (listés plus bas). Le seul outil de données où il est facultatif : expiries: true peut venir seul.
limitinteger—Les N derniers points de chaque série ; par défaut, le dernier (avec un timeframe, les N derniers buckets). Un champ en valeur courante seule comme price_change rend un point ; un limit au-delà du maximum propre d’un champ (1000 pour une série, 10000 pour les trades individuels) est plafonné, et warnings le dit. Avec une fenêtre, un plafond de points par série. describe_fields dit ce que compte N.
expiriesbooleanfalseAjoute data.expiries : les échéances actives et les chiffres de chacune, en une requête. Leur date est l’expiry des autres champs. Valable seul, sans aucun champ.
timeframestring—Pas de l’historique des options (champs marqués timeframe). Absent, un pas qui donne environ 200 points.
expirystring—Une échéance, AAAA-MM-JJ : options_oi_distribution, et options_max_pain en historique, où elle est requise.
tickerstring—Un émetteur d’ETF, ex. IBIT : filtre facultatif de l’historique d’etf_fundamentals.

get_market_overview

Tout le marché crypto, sans cible : capitalisation totale, volume et dominance BTC/ETH (global_market), deux indices Fear & Greed (fear_greed et celui de CMC, fear_greed_cmc), altcoin_season, et les indices cmc20 et cmc100.

ParamètreTypeDéfautDescription
fieldsstring[]—Requis : les champs à rendre, plusieurs par appel, parmi les 6 noms de cet outil (listés plus bas). Un champ d’un autre outil est refusé avec le nom de son outil.
limitinteger—Les N derniers points de chaque série ; par défaut, le dernier (avec un timeframe, les N derniers buckets). Un champ en valeur courante seule comme price_change rend un point ; un limit au-delà du maximum propre d’un champ (1000 pour une série, 10000 pour les trades individuels) est plafonné, et warnings le dit. Avec une fenêtre, un plafond de points par série. describe_fields dit ce que compte N.
timeframestring—Pas de global_market seulement (1h, 4h, 1d) ; les indices sont quotidiens.

get_macro_data

La macro américaine et mondiale. macro lit une série FRED (DGS10, DCOILWTICO…) — sans series, la dernière valeur de chaque série ; macro_intraday lit un instrument intraday de son catalogue (ex. PAXGUSDT), series requise. Quatre champs calculés ne prennent aucune cible : liquidité nette, corrélations crypto-macro, momentum et un score de risque. Les listes de séries viennent des catalogues de get_system_info.

ParamètreTypeDéfautDescription
fieldsstring[]—Requis : les champs à rendre, plusieurs par appel, parmi les 6 noms de cet outil (listés plus bas). Un champ d’un autre outil est refusé avec le nom de son outil.
limitinteger—Les N derniers points de chaque série ; par défaut, le dernier (avec un timeframe, les N derniers buckets). Un champ en valeur courante seule comme price_change rend un point ; un limit au-delà du maximum propre d’un champ (1000 pour une série, 10000 pour les trades individuels) est plafonné, et warnings le dit. Avec une fenêtre, un plafond de points par série. describe_fields dit ce que compte N.
seriesstring—L’identifiant de série : une série FRED pour macro (ex. DGS10 ; facultative pour sa valeur courante), un instrument pour macro_intraday (ex. PAXGUSDT ; requis).
timeframestring—Pas de macro_intraday seulement (son catalogue donne les pas de chaque instrument).

get_onchain_data

L’on-chain de Bitcoin et d’Ethereum, sans cible : huit champs btc_* (réseau, mempool, frais, minage, MVRV, NVT, adresses actives, revenu par difficulté) et huit champs eth_* (offre, gas, staking, déflation, DeFi, momentum du gas, resserrement de l’offre, prix de l’ETH en BTC).

ParamètreTypeDéfautDescription
fieldsstring[]—Requis : les champs à rendre, plusieurs par appel, parmi les 16 noms de cet outil (listés plus bas). Un champ d’un autre outil est refusé avec le nom de son outil.
limitinteger—Les N derniers points de chaque série ; par défaut, le dernier (avec un timeframe, les N derniers buckets). Un champ en valeur courante seule comme price_change rend un point ; un limit au-delà du maximum propre d’un champ (1000 pour une série, 10000 pour les trades individuels) est plafonné, et warnings le dit. Avec une fenêtre, un plafond de points par série. describe_fields dit ce que compte N.
timeframestring—Pas de btc_fees seulement (1h, 4h, 1d) ; les autres séries gardent la cadence de leur source.
datasetstring—concentration (défaut), rewards, difficulty ou fee_rates, pour l’historique de btc_mining.

get_market_indicators

Les dix-neuf indicateurs techniques, calculés à la demande, pour une à dix paires. symbol (une liste, comme dans les autres outils), timeframe et indicators sont obligatoires ; seul limit a un défaut, à 1. Les paramètres, défauts et bornes de chaque type sont dans le schéma JSON et la description de l’outil.

Appel
await c.call_tool("get_market_indicators", {
    "symbol": "BTCUSDT",
    "timeframe": "1h",
    "limit": 60,
    "indicators": [
        {"id": "rsi_7", "type": "rsi", "period": 7},
        {"id": "rsi_21", "type": "rsi", "period": 21},
        {"id": "macd", "type": "macd", "fast": 12, "slow": 26, "signal": 9},
        {"id": "adx_14", "type": "adx", "period": 14},
    ],
})

Les mêmes règles qu’en REST s’appliquent : un id de votre choix pour chaque indicateur, unique dans l’appel, et un plafond de limit + warm-up ≤ 1000. La réponse a la forme de celle des outils de données : data porte une série par id@timeframe (paire/id@timeframe avec plusieurs paires), indicators le type et les paramètres de chacun ; une paire où les indicateurs ne s’appliquent pas (une stablecoin) a ses clés à null, avec not_applicable dans unavailable, et une paire refusée est signalée dans errors. Une requête de quota par paire.

describe_fields

La définition complète des champs des cinq outils de données : ce que rend chacun (colonnes, conventions, datation des lignes), l’unité de chaque colonne (units), les seuils de chaque libellé (labels), son outil et sa cible, ses timeframes, son maximum de points, son historique, ses paramètres annexes et la prise en charge de live. Il décrit aussi les clés de sortie qui ne sont pas des champs : liquidations_24h, oi_usd, cumulative_net_volume et ranking. Aucun appel à l’API, aucun quota : la description de chaque outil porte une ligne par champ, avec les mêmes étiquettes que l’index, et cet outil donne le reste. Les mêmes définitions sont des ressources MCP : bytnode://fields (l’index, avec l’outil de chaque champ) et bytnode://fields/{name}.

ParamètreTypeDéfautDescription
fieldsstring[]—Les noms à décrire, au moins un : des champs de n’importe quel outil de données, ou les clés de sortie liquidations_24h, oi_usd, cumulative_net_volume et ranking. Un nom inconnu est refusé avec une suggestion.

rank_pairs

Toutes les paires servies classées sur une métrique, les limit premières rendues, pour une requête de quota quel que soit le nombre de paires : oi_usd (open interest en USD), volume_usd_24h (volume spot + futures des 24 dernières heures closes, somme du volume horaire × la clôture), funding_next (le prochain funding estimé : estimated_rate_pct, équivalent 8 h en %, et apr_pct), price_change_pct (la variation glissante sur window) et rsi (RSI 14 sur la dernière bougie close de timeframe). data.ranking donne pour chaque paire son rank, son symbol, sa valeur et son prix. Les valeurs ont au plus 60 secondes (computed_at) ; une paire sans la métrique — paires spot seulement pour oi_usd, funding_next et rsi, flux manquant — est listée dans excluded. La requête de quota est faite avec votre clé sur la route de la famille de la métrique, donc votre offre s’applique : dérivés pour oi_usd et funding_next, prix et volume pour price_change_pct et volume_usd_24h, indicateurs pour rsi. Pour les données complètes d’une paire, get_pair_data.

ParamètreTypeDéfautDescription
metricstring—Requis : oi_usd, volume_usd_24h, funding_next, price_change_pct ou rsi.
orderstringdescdesc (le plus grand d’abord, par défaut) ou asc — le funding le plus négatif, par exemple.
limitinteger10Le nombre de paires rendues, de 1 à 100.
windowstring1dprice_change_pct seulement : 1h, 4h, 1d (défaut) ou 1w.
timeframestring4hrsi seulement : les bougies du RSI, 1h, 4h (défaut) ou 1d.
max_tokensinteger6000Budget de la réponse en jetons estimés, de 1 500 à 16 000 (défaut 6 000). Le même paramètre sur chaque outil de données, get_market_indicators, rank_pairs et read_export.

read_export

La suite d’une réponse coupée par son budget de taille, page par page, dans le même format, sans requête à l’API ni quota. Une réponse coupée porte export.export_id, et le missing de son ranges (ou, pour plusieurs paires, le missing de premier niveau) donne l’appel à faire : read_export(export_id=…, key='klines@1h', offset=N). Chaque page dit row_count, total_row_count et next_offset (null à la fin), et keys liste chaque série de l’export avec son nombre de lignes. Un export vit une heure et se lit avec la clé API qui l’a produit.

ParamètreTypeDéfautDescription
export_idstring—Requis : l’export.export_id de la réponse coupée (son URI bytnode:// est aussi acceptée).
keystring—La série à lire, sous sa clé dans le data de la réponse (klines@1h, par exemple) ; par défaut la première. keys les liste.
offsetinteger0La première ligne à rendre, 0 étant la plus récente ; le row_count du ranges de la réponse coupée la donne.
max_tokensinteger6000Budget de la réponse en jetons estimés, de 1 500 à 16 000 (défaut 6 000). Le même paramètre sur chaque outil de données, get_market_indicators, rank_pairs et read_export.

#Donnée crypto courante ou historique

Le mode ne dépend que d’une chose : la présence d’une fenêtre datée. Sans since_ms, until_ms ni last, un outil de données répond avec la valeur courante ; avec l’un d’eux, chaque champ demandé répond avec son historique sur la fenêtre — plusieurs métriques datées en un seul appel.

RequêteCe que rend chaque champ
fields : [...]Le dernier point de chaque champ ; pour une série par buckets, le dernier bucket clos.
limit : NLes N derniers points de chaque série ; pour un champ marqué timeframe, les N derniers buckets du timeframe (1h par défaut) : basis, oi_change et les autres séries à la minute sont alors agrégées par bucket. Un champ en valeur courante seule en rend un.
since_ms / until_ms, ou lastSa série entière sur la période, jamais coupée en silence. Une ligne est rendue quand son instant (le début de son bucket) est ≥ since_ms et ≤ until_ms ; un bucket inachevé n’est jamais rendu. last recule since_ms au début de son bucket : last: '24h' en 1h rend les 24 buckets clos, since_ms: '24h' au plus 23. Sans timeframe, le serveur choisit un pas qui donne environ 200 points pour tout l’appel et le dit dans ranges.note ; un timeframe imposé qui ne tient pas est refusé avant l’appel, avec le motif exact (hors offre, ou trop de points pour un appel) et le pas qui marcherait.
live : trueLes champs listés ci-dessous gagnent la bougie en formation, provisoire. Refusé avec une fenêtre, et si aucun champ demandé ne la sert.

Champs qui servent la bougie en formation

klinescvdspread_interexchangetrades_klinetrades_kline_spottrades_kline_futures

#Cibler les paires et les marchés crypto

Chaque outil de données a sa cible : une paire pour get_pair_data (symbol, requis), un actif pour get_options_data (asset, requis), une série de catalogue pour get_macro_data (series), aucune pour get_market_overview et get_onchain_data. Chaque champ appartient à un seul outil. Ce qui ne colle pas est refusé avant le premier appel réseau, jamais absorbé, et tous les problèmes sont listés dans le même message.

CasRéponse
Une cible absenteUne erreur qui nomme le paramètre manquant, avec un exemple : symbol et asset sont requis par le schéma de leur outil, series par macro_intraday et par l’historique de macro.
Un champ demandé au mauvais outilErreur : 'fear_greed' is a field of get_market_overview: call that tool. Le message nomme l’outil du champ plutôt qu’un champ voisin.
series qu’aucun champ demandé n’attendErreur : seuls macro et macro_intraday lisent series ; les champs macro calculés n’ont pas de cible.
asset rempli avec une paireErreur : asset attend l’actif seul. Il n’y a aucune dérivation automatique.
Un paramètre que la route choisie n’accepte pasErreur : par exemple expiry sur la valeur courante d’options_max_pain, que seul son historique accepte.
Un timeframe qu’aucun champ n’utiliseErreur : le timeframe ne s’applique à aucun champ demandé (chaque outil dit quels champs le prennent : klines, cvd, trades_kline… pour une paire, global_market, macro_intraday, btc_fees).
Une fenêtre datée sur un champ qui n’en a pasErreur : le champ n’a pas d’historique daté ; demander sa valeur courante, sans fenêtre, ou le champ qui porte son historique, que le message nomme (price_change → klines, funding_next → funding_rate).
last avec since_msErreur : last remplace since_ms, en donner un seul. Une borne qui n’est ni des millisecondes epoch, ni une date ISO 8601, ni une durée est refusée avec les formes acceptées.
Plus de 10 paires dans symbolErreur : 10 paires au plus par appel, avec le nombre reçu.

#Les 64 champs du marché crypto

Les noms sont ceux de l’API, identiques en valeur courante et en historique, avec ces différences : le marché global s’appelle global_market ici et global dans le snapshot REST (global est un mot réservé de Python, la langue du serveur) ; le marché est un paramètre ici (market: "spot") et un suffixe de chemin en REST (/v1/cvd/spot) ; les chiffres de chaque échéance d’options viennent avec expiries: true de get_options_data (REST : /v1/options/expiry) et les capacités d’une paire avec le catalogue symbol_capabilities (REST : /v1/capabilities?symbol=…) ; et un historique dit le pas que l’outil a retenu dans timeframe_applied, puisqu’il peut le choisir. Le détail de chaque champ — son outil, ce qu’il contient, ses unités, ce que compte N, son plafond, son historique — est donné par describe_fields ; la description de chaque outil en porte une ligne par champ, avec ses étiquettes (timeframe, valeur courante seule, live, limit maximal). Voir aussi le catalogue des données.

get_pair_data : vingt-cinq champs par paire (symbol)

klinesprice_changetrades_spottrades_futurestrades_largetrades_kline_futures_secondsoifunding_nextfunding_ratefunding_cumulativebasisoi_changeliquidations_eventsliquidations_cumulativeliquidations_big_small_ratioorderbookcvdspread_interexchangebuy_sell_ratiotrades_avg_sizetrades_klinetrades_kline_spottrades_kline_futurestokenomics

get_options_data : onze champs par actif (asset)

options_summaryoptions_oioptions_oi_changeoptions_oi_distributionoptions_volumeoptions_put_call_ratiooptions_ivoptions_iv_klinesoptions_max_painoptions_greeksetf_fundamentals

Les champs options et etf_fundamentals. Les échéances actives, avec les chiffres de chacune, viennent avec expiries: true. options_max_pain liste chaque échéance active, la plus proche en premier, et limit: N garde les N plus proches, sans fenêtre ; une fenêtre rend l’historique d’une seule expiry, alors requise.

get_market_overview : six champs de tout le marché (aucune cible)

global_marketfear_greedfear_greed_cmcaltcoin_seasoncmc20cmc100

get_macro_data : six champs macro

macromacro_intradaymacro_net_liquiditymacro_correlationsmacro_momentummacro_risk

macro sans series rend la dernière valeur de chaque série FRED ; avec, cette série seule, et son historique l’exige. macro_intraday l’exige toujours et refuse 30m. Les deux ne portent pas les mêmes instruments : ne pas substituer l’un à l’autre. Les quatre champs calculés (macro_net_liquidity, macro_correlations, macro_momentum, macro_risk) ne prennent pas de series.

get_onchain_data : seize champs on-chain (aucune cible)

btc_networkbtc_mempoolbtc_feesbtc_miningbtc_mvrvbtc_nvtbtc_active_addressesbtc_revenue_per_difficultyeth_supplyeth_gaseth_stakingeth_deflationeth_defieth_gas_momentumeth_squeezeeth_price_btc

Seul btc_fees prend un timeframe ; l’historique de btc_mining prend un dataset ; les valorisations (btc_mvrv, btc_nvt…) sont quotidiennes.

Valeur courante seulement

price_changetrades_spottrades_futurestrades_largetrades_kline_futures_secondsfunding_nextliquidations_eventsmacro_correlationsmacro_momentummacro_riskoptions_summaryoptions_oi_distributionoptions_greeks

Ces champs n’ont pas d’historique daté : ils servent leur valeur courante (un point, ou avec limit les N derniers quand le champ compte des lignes — transactions, événements de liquidation). Une fenêtre since_ms ou until_ms sur eux est refusée plutôt qu’ignorée — un agent IA croirait filtrer une période alors qu’il reçoit les derniers points.

#La réponse : des données de marché crypto lisibles par votre agent IA

Les données gardent les noms, unités et conventions de l’API, sous une clé par champ, mais elles sont présentées pour un agent IA plutôt que rendues telles quelles. Un champ à timeframe a pour clé champ@tf ; avec plusieurs paires, chaque clé est précédée de sa paire (ETHUSDT/funding_next, BTCUSDT/cvd@1h). Une réponse porte mode, data, api_requests, server_time (l’heure du serveur, ISO 8601 UTC), mcp_version (la version de la surface MCP) et response_tokens (sa propre taille, en jetons estimés), plus, quand ils s’appliquent, scopes, summary, ranges, freshness, warnings, errors, partial, unavailable, omitted_columns, missing, truncation, export, timeframe_applied et window ; get_market_indicators et rank_pairs répondent dans la même enveloppe. Une série vide ou sans objet vaut null, et unavailable dit pourquoi. unavailable et out_of_plan_fields sont celles du snapshot. Aucun outil ne déclare d’outputSchema : les clés sont décrites ici, et structuredContent porte le même JSON que le texte.

Réponse
{
  "mode": "latest",
  "data": {
    "klines@1h": {
      "first_time": "2026-10-21T13:00:00.000Z",
      "step_s": -3600,
      "columns": ["open", "high", "low", "close", "volume"],
      "rows": [[…], …]
    },
    "oi@1h": { "first_time": …, "step_s": -3600, "columns": ["oi", "oi_usd", … ], "rows": [ … ] },
    "funding_next": { … },
    "price_change": { … }
  },
  "scopes": {
    "symbol:BTCUSDT": ["klines@1h", "oi@1h", "funding_next", "price_change"]
  },
  "summary": {
    "klines@1h": { "column": "close", "latest": …, "min": …, "max": …, "mean": …,
                   "change_pct": …, "high_max": …, "low_min": …, … }
  },
  "freshness": { "age_s": { "klines@1h": 4, "funding_next": 2, … }, "stale": [] },
  "omitted_columns": { "klines@1h": ["is_closed"] },
  "timeframe_applied": "1h",
  "unavailable": { … },
  "api_requests": 1,
  "server_time": "2026-10-21T14:02:31.512Z",
  "response_tokens": 1840
}
  • data : une liste de lignes arrive en {columns, rows}, lignes de la plus récente à la plus ancienne ; un point seul, en objet ; une série vide ou sans objet, en null. Une série à pas régulier n’a pas de colonne time mais first_time et step_s, quel que soit son nombre de lignes, une comprise : la ligne i est datée first_time + i × step_s, step_s étant négatif, de la ligne la plus récente vers le passé ; au moindre trou, la colonne time reste. Les événements (trades, liquidations unitaires) et les tables gardent leur time, et ce que toutes les lignes partagent est dit une fois sur le bloc : date (chaque time est alors l’heure UTC de ce jour, 12:54:30.494Z) ou un seul time (toutes les lignes à cet instant, comme une table d’échéances) ; .000 disparaît quand aucune ligne n’a de millisecondes. Les flottants gardent 6 chiffres significatifs, sauf les offres et les cumuls, qui gardent leurs unités entières. Avec detail: "compact" (le défaut), les lignes lourdes gardent leurs colonnes principales, is_closed disparaît quand chaque ligne est close et les identifiants de trades sont retirés ; omitted_columns nomme ce qui a été laissé, et detail: "full" le rend.
  • scopes : la portée réelle de chaque clé — symbol:X, asset:X, series:X, ou market pour un champ sans cible. macro demandé sans series est étiqueté market, jamais avec une série. Avec plusieurs paires, le préfixe de la clé nomme déjà sa paire : seules restent les portées des autres cibles (market…).
  • mode : latest ou history ; en historique, window rappelle les bornes et ranges dit, par série, ce qui est réellement couvert : timeframe, row_count, from et to (le début du premier et du dernier bucket, comme le time de chaque ligne), note et truncated ; quand une série est coupée, missing dit comment obtenir la suite — un limit plus bas, une fenêtre plus ancienne qui finit à next_until_ms, ou read_export à partir de l’offset qu’il donne.
  • summary : par série, sur sa colonne principale, la dernière et la plus ancienne valeur, le min et le max avec leur instant, et la moyenne ; la somme pour un flux (liquidations, volume net…), avec dans sums celle de ses composantes (long_usd et short_usd, buy_volume et sell_volume), la variation (et change_pct quand elle a un sens) pour un état ; les bougies ajoutent high_max et low_min avec leur instant. Les trades et liquidations unitaires ajoutent by_side (nombre, quantité et USD par côté).
  • freshness (valeur courante) : age_s, les secondes écoulées depuis la dernière livraison du flux source de chaque clé (la date d’une ligne est son time), et stale, les clés dont le flux est en retard, selon le moniteur des flux ; warnings nomme chaque champ en retard — sa valeur n’est pas courante — et chaque colonne de projection qu’un champ a ignorée.
  • Taille : une réponse est bornée à 6 000 jetons estimés par défaut ; le paramètre max_tokens des outils de données, de get_market_indicators, de rank_pairs et de read_export la règle de 1 500 à 16 000, et response_tokens donne la taille de chaque réponse. Au-delà du budget, les séries les plus lourdes gardent leurs lignes les plus récentes, la coupe est dite une fois, dans le ranges de chaque série (row_count lignes servies sur total_row_count, et missing : comment avoir la suite, souvent le max_tokens qui suffit à la réponse entière ; le même champ coupé pour plusieurs paires porte une seule consigne, dans le missing de premier niveau ; truncation seulement pour ce qui n’a pas de ranges), les métadonnées identiques pour plusieurs paires (ranges, omitted_columns, freshness) sont écrites une fois par champ, sous le nom du champ, et export garde les données complètes une heure, pour la même clé : read_export les lit page par page avec export.export_id, au format des réponses, sans requête à l’API ni quota. C’est aussi la ressource MCP bytnode://exports/{id}, pour les clients qui lisent les ressources, d’un seul bloc, avec 8 chiffres significatifs et le time de chaque ligne.
  • timeframe_applied : le pas réellement appliqué, dès qu’un champ l’a utilisé ; live : présent quand la bougie en formation a été demandée.
  • errors et partial : un champ en erreur n’empêche pas les autres, ni une paire refusée les autres paires. Il est signalé sous errors (une paire sous son nom) et la réponse porte partial: true.
  • api_requests : les requêtes que cet appel a décomptées de votre quota — pour chaque paire, une pour les valeurs courantes des champs du snapshot ensemble ; une pour chaque autre champ, chaque historique et expiries.
  • oi_usd : chaque ligne d’oi porte l’open interest en USD, oi × la clôture de la bougie spot de référence du même bucket (null sans elle), en valeur courante aussi, sans requête de plus ; get_pair_brief le porte également. De même, chaque ligne de cvd porte cumulative_net_volume, le cumul de net_volume depuis la ligne la plus ancienne de la série servie : la courbe de CVD sur la période. La valeur courante de liquidations_cumulative est son dernier bucket clos (1h par défaut), daté à son début comme toute ligne.

#Erreurs sur les appels de données de marché crypto

Toute erreur commence par Error (HTTP NNN): message. Quand l’API a répondu, elle se termine par [code: …], l’error.code stable de l’API. Un appel d’outil en échec est signalé comme une erreur MCP (isError), jamais rendu comme une donnée, et porte la même erreur en champs dans structuredContent.error : {status, code, message, param?, hint?, retry_after_s?}. code est celui de l’API quand elle en a donné un (invalid_symbol, plan_family, history_depth, rate_limited, quota_exceeded…), sinon il suit le statut (invalid_request pour un 422, unauthorized pour un 401…) ; un champ demandé au mauvais outil donne wrong_tool, avec le bon outil dans hint (call get_market_overview), un champ ou une colonne inconnus unknown_field, un paramètre inconnu unknown_parameter, avec did you mean … dans hint ; retry_after_s est le délai à attendre quand le message en donne un.

SituationComportement
Requête sans clé valide401, X-Deny-Reason: missing_api_key (ou invalid_api_key), avant qu’un seul outil soit annoncé.
Requête invalideError (HTTP 422) listant chaque problème, avant tout appel réseau.
Famille hors offreError (HTTP 403): The 'options' data family is not included in your plan. GET /v1/limits lists the families of your key; https://bytnode.com/pricing lists the plans that open it. [code: plan_family] — la donnée existe, simplement pas dans votre offre.
Snapshot hors offre (Free)Un refus explicite, Error (HTTP 403), sur les valeurs courantes (les champs du snapshot, get_pair_brief), qui nomme l’offre qui les ouvre ; les autres champs restent servis, et un court historique (last: '1h') donne les derniers points.
Une période au-delà de la profondeur de l’offreRefusée avant l’appel, avec la profondeur de l’offre à ce pas et le pas qui servirait la période ; à la frontière, l’Error (HTTP 403) de l’API [code: history_depth].
Débit ou quotaError (HTTP 429) avec le detail de l’API : débit par minute, ou quota mensuel.
Un champ en erreurSignalé sous errors, les autres servis, partial: true ; une erreur identique sur plusieurs champs n’est écrite qu’une fois (same error as '…'). L’appel n’échoue que si aucun champ n’aboutit.
Une paire refusée parmi plusieursSignalée sous errors avec son nom (un symbol invalide, par exemple), les autres paires servies, partial: true. L’appel n’échoue que si aucune paire n’aboutit.
Un symbol invalideL’Error (HTTP 422) de l’API, terminée par [code: invalid_symbol], qui liste les valeurs acceptées ; la liste vivante vient de get_system_info.
Un export expiré ou inconnuError (HTTP 404) de read_export, terminée par [code: not_found] : un export vit une heure et se lit avec la clé qui l’a produit ; rappeler l’outil.
Amont qui ne répond pasUne relance sur 502, 503, 504 ou panne réseau. Un 500 n’est pas rejoué : chaque requête compte dans votre quota.
Délai dépasséError (HTTP 504) après trente secondes sans réponse.
Erreur interne du serveurError (HTTP 500) avec le seul type de l’erreur ; le détail reste dans le journal du serveur.