@ironflowsh/mcp 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -22
- package/build/api.d.ts +35 -9
- package/build/api.d.ts.map +1 -1
- package/build/api.js +107 -48
- package/build/api.js.map +1 -1
- package/build/http.js +28 -5
- package/build/http.js.map +1 -1
- package/build/index.js +4 -3
- package/build/index.js.map +1 -1
- package/build/notice.d.ts +10 -0
- package/build/notice.d.ts.map +1 -0
- package/build/notice.js +82 -0
- package/build/notice.js.map +1 -0
- package/build/query.d.ts +3 -0
- package/build/query.d.ts.map +1 -1
- package/build/query.js +24 -0
- package/build/query.js.map +1 -1
- package/build/schemas.d.ts.map +1 -1
- package/build/schemas.js +26 -5
- package/build/schemas.js.map +1 -1
- package/build/server.d.ts +9 -1
- package/build/server.d.ts.map +1 -1
- package/build/server.js +29 -10
- package/build/server.js.map +1 -1
- package/build/shape.d.ts +14 -3
- package/build/shape.d.ts.map +1 -1
- package/build/shape.js +28 -12
- package/build/shape.js.map +1 -1
- package/build/tools.d.ts +1 -0
- package/build/tools.d.ts.map +1 -1
- package/build/tools.js +180 -74
- package/build/tools.js.map +1 -1
- package/build/usage.d.ts +15 -0
- package/build/usage.d.ts.map +1 -0
- package/build/usage.js +66 -0
- package/build/usage.js.map +1 -0
- package/package.json +1 -1
package/build/tools.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// MCP tool definitions for Ironflow market data.
|
|
2
2
|
import { MAX_SUMMARY_MINUTES, summarizeLiquidations } from "./liquidations.js";
|
|
3
3
|
import { MAX_LIMIT, rankSnapshot, SORT_KEYS } from "./snapshot.js";
|
|
4
|
-
import { BEHAVIOR_LABELS, BEHAVIOR_SORT_KEYS, behaviorSQL, MAX_BEHAVIOR_LIMIT, rowsToObjects, runQuery } from "./query.js";
|
|
5
|
-
import { DEFAULT_FUNDING_ROWS, DEFAULT_MARKETS_LIMIT, shapeMarkets, shapeUserFunding, shapeWalletLabels } from "./shape.js";
|
|
4
|
+
import { BEHAVIOR_LABELS, BEHAVIOR_SORT_KEYS, behaviorSQL, MAX_BEHAVIOR_LIMIT, MAX_VAULT_LEADERBOARD_LIMIT, rowsToObjects, runQuery, VAULT_LEADERBOARD_DAYS, vaultLeaderboardSQL, } from "./query.js";
|
|
5
|
+
import { DEFAULT_FUNDING_ROWS, DEFAULT_MARKETS_LIMIT, MAX_MARKETS_LIMIT, shapeMarkets, shapeUserFunding, shapeWalletLabels } from "./shape.js";
|
|
6
6
|
// ─── Arg validation helpers ──────────────────────────────────────────────────
|
|
7
7
|
function requireString(args, key) {
|
|
8
8
|
const val = args[key];
|
|
@@ -30,16 +30,55 @@ function optionalString(args, key, defaultVal) {
|
|
|
30
30
|
}
|
|
31
31
|
return val;
|
|
32
32
|
}
|
|
33
|
+
function optionalBoolean(args, key) {
|
|
34
|
+
const val = args[key];
|
|
35
|
+
if (val === undefined || val === null)
|
|
36
|
+
return false;
|
|
37
|
+
if (typeof val === "boolean")
|
|
38
|
+
return val;
|
|
39
|
+
if (val === "true" || val === "false")
|
|
40
|
+
return val === "true";
|
|
41
|
+
throw new Error(`"${key}" must be true or false`);
|
|
42
|
+
}
|
|
43
|
+
// optionalTime reads a window bound and passes it on as the caller wrote it:
|
|
44
|
+
// the API takes Unix ms, Unix seconds and ISO 8601 (UTC when no zone is
|
|
45
|
+
// given), so nothing is converted here. "" means not set.
|
|
46
|
+
function optionalTime(args, key) {
|
|
47
|
+
const val = args[key];
|
|
48
|
+
if (val === undefined || val === null || val === 0)
|
|
49
|
+
return "";
|
|
50
|
+
const invalid = new Error(`"${key}" must be Unix ms, Unix seconds or an ISO 8601 date such as 2026-10-01T00:00:00Z`);
|
|
51
|
+
if (typeof val === "number") {
|
|
52
|
+
if (!Number.isFinite(val) || val < 0)
|
|
53
|
+
throw invalid;
|
|
54
|
+
return String(Math.floor(val));
|
|
55
|
+
}
|
|
56
|
+
if (typeof val !== "string")
|
|
57
|
+
throw invalid;
|
|
58
|
+
const text = val.trim();
|
|
59
|
+
if (/^\d*$/.test(text))
|
|
60
|
+
return Number(text) > 0 ? text : "";
|
|
61
|
+
// The API reads 2026-10-01, 2026-10-01T12:00 and RFC 3339 date-times.
|
|
62
|
+
if (!/^\d{4}-\d{2}-\d{2}(T|$)/.test(text) || Number.isNaN(Date.parse(text)))
|
|
63
|
+
throw invalid;
|
|
64
|
+
return text;
|
|
65
|
+
}
|
|
66
|
+
// Shared parameter descriptions. The API resolves Hyperliquid names itself.
|
|
67
|
+
const MARKET = "Market: BTC-PERP, xyz:NVDA-PERP, HYPE/USDC, or a Hyperliquid name (BTC, @107, xyz:NVDA)";
|
|
68
|
+
const MARKET_FILTER = "Optional market filter: BTC-PERP or a Hyperliquid name (BTC, xyz:NVDA)";
|
|
69
|
+
const time = (bound, extra = "") => `Window ${bound}: Unix ms or seconds, or ISO 8601 (2026-10-01T00:00:00Z)${extra ? `. ${extra}` : ""}`;
|
|
33
70
|
// ─── Tools ──────────────────────────────────────────────────────────────────
|
|
34
71
|
export const tools = [
|
|
35
72
|
{
|
|
36
73
|
name: "describe_data",
|
|
74
|
+
title: "Describe SQL tables",
|
|
37
75
|
description: "Start here for any Hyperliquid question the other tools do not answer directly. Returns the SQL tables you can query with run_query (every fill, per-wallet daily totals, wallet behaviour labels, funding, mark and oracle prices, open interest, liquidations, builder-code fills, transfers, vault flows), their columns, how far back each goes, query tips, worked examples and your own limits.",
|
|
38
76
|
inputSchema: { type: "object", properties: {}, required: [] },
|
|
39
77
|
handler: async (_args, api) => JSON.stringify(await api.get("/v1/query/schema")),
|
|
40
78
|
},
|
|
41
79
|
{
|
|
42
80
|
name: "run_query",
|
|
81
|
+
title: "Run SQL query",
|
|
43
82
|
description: "Run one read-only ClickHouse SELECT over Ironflow's Hyperliquid tables (hl.fills, hl.wallet_daily, hl.wallet_behavior, hl.funding, hl.mark_prices, hl.oracle_prices, hl.open_interest, hl.liquidations, hl.builder_fills, hl.transfers, hl.vault_operations). Call describe_data first for columns and examples. Aggregate in SQL: results are capped (1,000 rows keyless). Keyless: last 24 hours, 5 s per query, 60 query seconds per hour per IP; a free key from https://ironflow.sh/key gives 30 days of history.",
|
|
44
83
|
inputSchema: {
|
|
45
84
|
type: "object",
|
|
@@ -57,6 +96,7 @@ export const tools = [
|
|
|
57
96
|
},
|
|
58
97
|
{
|
|
59
98
|
name: "get_wallet_behavior",
|
|
99
|
+
title: "Wallet behavior labels",
|
|
60
100
|
description: "How Hyperliquid wallets trade, from their last 30 days: labels (market_maker, high_frequency, whale, directional, consistent_winner, big_loser, revenge_sizing, often_liquidated, hip3_trader, spot_trader, prediction_trader) and the numbers behind them (maker share, buy/sell imbalance, fills per day, green-day share, profit factor, liquidations). Look up specific addresses, or list wallets with one label.",
|
|
61
101
|
inputSchema: {
|
|
62
102
|
type: "object",
|
|
@@ -89,11 +129,12 @@ export const tools = [
|
|
|
89
129
|
},
|
|
90
130
|
{
|
|
91
131
|
name: "get_price",
|
|
132
|
+
title: "Market price",
|
|
92
133
|
description: "Latest mark price of a Hyperliquid market: native perps, HIP-3 builder perps (e.g. xyz:NVDA-PERP) and spot.",
|
|
93
134
|
inputSchema: {
|
|
94
135
|
type: "object",
|
|
95
136
|
properties: {
|
|
96
|
-
market: { type: "string", description:
|
|
137
|
+
market: { type: "string", description: MARKET },
|
|
97
138
|
},
|
|
98
139
|
required: ["market"],
|
|
99
140
|
},
|
|
@@ -105,11 +146,12 @@ export const tools = [
|
|
|
105
146
|
},
|
|
106
147
|
{
|
|
107
148
|
name: "get_recent_trades",
|
|
149
|
+
title: "Recent trades",
|
|
108
150
|
description: "Latest tick-level trades on a Hyperliquid market from our own nodes: price, size, side and block time. Covers native perps, HIP-3 builder markets, HIP-4 outcomes and spot.",
|
|
109
151
|
inputSchema: {
|
|
110
152
|
type: "object",
|
|
111
153
|
properties: {
|
|
112
|
-
market: { type: "string", description:
|
|
154
|
+
market: { type: "string", description: MARKET },
|
|
113
155
|
limit: { type: "number", description: "Number of trades to return (1-100, default 20)" },
|
|
114
156
|
},
|
|
115
157
|
required: ["market"],
|
|
@@ -123,11 +165,12 @@ export const tools = [
|
|
|
123
165
|
},
|
|
124
166
|
{
|
|
125
167
|
name: "get_candles",
|
|
168
|
+
title: "Candles (OHLCV)",
|
|
126
169
|
description: "OHLCV candles for a Hyperliquid market, computed from tick-level trades.",
|
|
127
170
|
inputSchema: {
|
|
128
171
|
type: "object",
|
|
129
172
|
properties: {
|
|
130
|
-
market: { type: "string", description:
|
|
173
|
+
market: { type: "string", description: MARKET },
|
|
131
174
|
interval: { type: "string", description: "Candle interval (1m, 5m, 15m, 1h, 4h, 1d). Default: 1h", enum: ["1m", "5m", "15m", "1h", "4h", "1d"] },
|
|
132
175
|
limit: { type: "number", description: "Number of candles to return (1-500, default 24)" },
|
|
133
176
|
},
|
|
@@ -143,11 +186,12 @@ export const tools = [
|
|
|
143
186
|
},
|
|
144
187
|
{
|
|
145
188
|
name: "get_funding_rates",
|
|
189
|
+
title: "Funding rate history",
|
|
146
190
|
description: "Hourly funding rate history for a Hyperliquid perp, including HIP-3 builder perps. A positive rate means longs pay shorts.",
|
|
147
191
|
inputSchema: {
|
|
148
192
|
type: "object",
|
|
149
193
|
properties: {
|
|
150
|
-
market: { type: "string", description:
|
|
194
|
+
market: { type: "string", description: MARKET },
|
|
151
195
|
limit: { type: "number", description: "Number of funding rate entries (1-100, default 10)" },
|
|
152
196
|
},
|
|
153
197
|
required: ["market"],
|
|
@@ -161,11 +205,12 @@ export const tools = [
|
|
|
161
205
|
},
|
|
162
206
|
{
|
|
163
207
|
name: "get_open_interest",
|
|
164
|
-
|
|
208
|
+
title: "Open interest",
|
|
209
|
+
description: "Latest open interest of a Hyperliquid perp, in base units, with its 24h volume in USD.",
|
|
165
210
|
inputSchema: {
|
|
166
211
|
type: "object",
|
|
167
212
|
properties: {
|
|
168
|
-
market: { type: "string", description:
|
|
213
|
+
market: { type: "string", description: MARKET },
|
|
169
214
|
},
|
|
170
215
|
required: ["market"],
|
|
171
216
|
},
|
|
@@ -177,11 +222,12 @@ export const tools = [
|
|
|
177
222
|
},
|
|
178
223
|
{
|
|
179
224
|
name: "get_liquidations",
|
|
225
|
+
title: "Liquidations",
|
|
180
226
|
description: "Liquidations on a Hyperliquid perp, read from our own nodes: price, size, side and the liquidated wallet. Hyperliquid's public API has no liquidation feed.",
|
|
181
227
|
inputSchema: {
|
|
182
228
|
type: "object",
|
|
183
229
|
properties: {
|
|
184
|
-
market: { type: "string", description:
|
|
230
|
+
market: { type: "string", description: MARKET },
|
|
185
231
|
limit: { type: "number", description: "Number of liquidation events (1-100, default 20)" },
|
|
186
232
|
},
|
|
187
233
|
required: ["market"],
|
|
@@ -196,12 +242,13 @@ export const tools = [
|
|
|
196
242
|
// ─── Additional Market Data ──────────────────────────────────────────
|
|
197
243
|
{
|
|
198
244
|
name: "get_liquidation_summary",
|
|
245
|
+
title: "Liquidation summary",
|
|
199
246
|
description: "Liquidations across every Hyperliquid market (or one market) over the last N minutes, totalled: count, notional, longs vs shorts liquidated, the top markets and the largest single liquidation. Use it for 'who got liquidated in the last hour?'. Keyless calls can look back 60 minutes, keyed calls up to 240.",
|
|
200
247
|
inputSchema: {
|
|
201
248
|
type: "object",
|
|
202
249
|
properties: {
|
|
203
250
|
minutes: { type: "number", description: "Lookback in minutes (default 60, max 240)" },
|
|
204
|
-
market: { type: "string", description:
|
|
251
|
+
market: { type: "string", description: MARKET_FILTER },
|
|
205
252
|
},
|
|
206
253
|
required: [],
|
|
207
254
|
},
|
|
@@ -216,12 +263,13 @@ export const tools = [
|
|
|
216
263
|
},
|
|
217
264
|
{
|
|
218
265
|
name: "get_fills",
|
|
266
|
+
title: "Wallet fills",
|
|
219
267
|
description: "Every fill for one Hyperliquid wallet, optionally for one market, from indexed history: price, size, side, fee and realized PnL. Hyperliquid's own userFills endpoints stop at the 10,000 most recent fills.",
|
|
220
268
|
inputSchema: {
|
|
221
269
|
type: "object",
|
|
222
270
|
properties: {
|
|
223
271
|
address: { type: "string", description: "Wallet address (e.g. 0x...)" },
|
|
224
|
-
market: { type: "string", description:
|
|
272
|
+
market: { type: "string", description: MARKET_FILTER },
|
|
225
273
|
limit: { type: "number", description: "Number of fills (1-100, default 20)" },
|
|
226
274
|
},
|
|
227
275
|
required: ["address"],
|
|
@@ -236,11 +284,12 @@ export const tools = [
|
|
|
236
284
|
},
|
|
237
285
|
{
|
|
238
286
|
name: "get_mark_prices",
|
|
239
|
-
|
|
287
|
+
title: "Mark and oracle price",
|
|
288
|
+
description: "Latest mark price, oracle price and hourly funding rate of a Hyperliquid perp.",
|
|
240
289
|
inputSchema: {
|
|
241
290
|
type: "object",
|
|
242
291
|
properties: {
|
|
243
|
-
market: { type: "string", description:
|
|
292
|
+
market: { type: "string", description: MARKET },
|
|
244
293
|
},
|
|
245
294
|
required: ["market"],
|
|
246
295
|
},
|
|
@@ -252,19 +301,25 @@ export const tools = [
|
|
|
252
301
|
},
|
|
253
302
|
{
|
|
254
303
|
name: "get_vault_operations",
|
|
255
|
-
|
|
304
|
+
title: "Vault deposits and withdrawals",
|
|
305
|
+
description: "Deposits into and withdrawals from one Hyperliquid vault or one depositor. Pass vault, address, or both; at least one is required (HLP is 0xdfc24b077bc1425ad1dea75bcb6f8158e10df303). For flows across all vaults use get_vault_leaderboard.",
|
|
256
306
|
inputSchema: {
|
|
257
307
|
type: "object",
|
|
258
308
|
properties: {
|
|
259
|
-
vault: { type: "string", description: "Vault address" },
|
|
260
|
-
address: { type: "string", description: "
|
|
309
|
+
vault: { type: "string", description: "Vault address (vault or address is required)" },
|
|
310
|
+
address: { type: "string", description: "Depositor address (vault or address is required)" },
|
|
261
311
|
limit: { type: "number", description: "Number of events (1-100, default 20)" },
|
|
262
312
|
},
|
|
263
313
|
required: [],
|
|
264
314
|
},
|
|
265
315
|
handler: async (args, api) => {
|
|
266
|
-
|
|
267
|
-
|
|
316
|
+
// The API stores addresses lowercase and answers 400 when neither
|
|
317
|
+
// filter is set, so check here and say what to pass.
|
|
318
|
+
const vault = optionalString(args, "vault", "").trim().toLowerCase();
|
|
319
|
+
const address = optionalString(args, "address", "").trim().toLowerCase();
|
|
320
|
+
if (!vault && !address) {
|
|
321
|
+
throw new Error('Pass "vault" (a vault address, e.g. HLP 0xdfc24b077bc1425ad1dea75bcb6f8158e10df303) or "address" (a depositor), or both. For flows across all vaults use get_vault_leaderboard.');
|
|
322
|
+
}
|
|
268
323
|
const limit = optionalNumber(args, "limit", 20);
|
|
269
324
|
const data = await api.getVaultOperations(vault, address, String(limit));
|
|
270
325
|
return JSON.stringify(data, null, 2);
|
|
@@ -273,11 +328,12 @@ export const tools = [
|
|
|
273
328
|
// ─── Analytics ───────────────────────────────────────────────────────
|
|
274
329
|
{
|
|
275
330
|
name: "get_liquidation_levels",
|
|
331
|
+
title: "Liquidation levels",
|
|
276
332
|
description: "Liquidated notional on a Hyperliquid perp bucketed by price: where longs and shorts were wiped out. Needs a Builder or Enterprise key; keyless and free-key calls return 403.",
|
|
277
333
|
inputSchema: {
|
|
278
334
|
type: "object",
|
|
279
335
|
properties: {
|
|
280
|
-
market: { type: "string", description:
|
|
336
|
+
market: { type: "string", description: MARKET },
|
|
281
337
|
bucket_size: { type: "string", description: "Price bucket size (1, 5, 10, 50, 100, 500, 1000, 5000). Default: 100" },
|
|
282
338
|
},
|
|
283
339
|
required: ["market"],
|
|
@@ -291,27 +347,45 @@ export const tools = [
|
|
|
291
347
|
},
|
|
292
348
|
{
|
|
293
349
|
name: "get_vault_leaderboard",
|
|
294
|
-
|
|
350
|
+
title: "Vault leaderboard",
|
|
351
|
+
description: `Hyperliquid vaults ranked by net deposits (deposits minus withdrawals) over the last ${VAULT_LEADERBOARD_DAYS} days, with depositor counts. Keyless calls see the last 24 hours; a free key from https://ironflow.sh/key gives the full ${VAULT_LEADERBOARD_DAYS} days.`,
|
|
295
352
|
inputSchema: {
|
|
296
353
|
type: "object",
|
|
297
354
|
properties: {
|
|
298
|
-
limit: { type: "number", description:
|
|
355
|
+
limit: { type: "number", description: `Number of vaults (default 10, max ${MAX_VAULT_LEADERBOARD_LIMIT})` },
|
|
299
356
|
},
|
|
300
357
|
required: [],
|
|
301
358
|
},
|
|
302
359
|
handler: async (args, api) => {
|
|
303
360
|
const limit = optionalNumber(args, "limit", 10);
|
|
304
|
-
|
|
305
|
-
|
|
361
|
+
// GET /v1/analytics/vault-leaderboard is Builder and Enterprise only
|
|
362
|
+
// (403 TIER_FORBIDDEN otherwise). Keyed callers try it first; everyone
|
|
363
|
+
// else, and keys below Builder, get the same ranking from SQL.
|
|
364
|
+
if (api.hasKey()) {
|
|
365
|
+
try {
|
|
366
|
+
return JSON.stringify(await api.getVaultLeaderboard(String(limit)), null, 2);
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
if (!(err instanceof Error && err.message.includes("TIER_FORBIDDEN")))
|
|
370
|
+
throw err;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
const res = (await runQuery(api, vaultLeaderboardSQL(limit), MAX_VAULT_LEADERBOARD_LIMIT));
|
|
374
|
+
const historyDays = res.limits?.history_days;
|
|
375
|
+
return JSON.stringify({
|
|
376
|
+
window_days: historyDays ? Math.min(historyDays, VAULT_LEADERBOARD_DAYS) : VAULT_LEADERBOARD_DAYS,
|
|
377
|
+
data: rowsToObjects(res).map((row) => ({ source: "hyperliquid", ...row })),
|
|
378
|
+
});
|
|
306
379
|
},
|
|
307
380
|
},
|
|
308
381
|
{
|
|
309
382
|
name: "get_funding_stats",
|
|
383
|
+
title: "Funding statistics",
|
|
310
384
|
description: "Funding statistics per time bucket for a Hyperliquid perp: average, minimum, maximum and annualized rate.",
|
|
311
385
|
inputSchema: {
|
|
312
386
|
type: "object",
|
|
313
387
|
properties: {
|
|
314
|
-
market: { type: "string", description:
|
|
388
|
+
market: { type: "string", description: MARKET },
|
|
315
389
|
interval: { type: "string", description: "Time interval (1h, 4h, 8h, 1d, 7d). Default: 1d", enum: ["1h", "4h", "8h", "1d", "7d"] },
|
|
316
390
|
limit: { type: "number", description: "Number of data points (default 7)" },
|
|
317
391
|
},
|
|
@@ -334,6 +408,7 @@ export const tools = [
|
|
|
334
408
|
// JSON object the agent can reason over.
|
|
335
409
|
{
|
|
336
410
|
name: "get_user_state",
|
|
411
|
+
title: "Wallet positions",
|
|
337
412
|
description: "Open positions and unrealized PnL for a Hyperliquid wallet right now, across native and HIP-3 perps. Use it for questions like 'is this wallet long or short?'",
|
|
338
413
|
inputSchema: {
|
|
339
414
|
type: "object",
|
|
@@ -350,14 +425,15 @@ export const tools = [
|
|
|
350
425
|
},
|
|
351
426
|
{
|
|
352
427
|
name: "get_user_funding",
|
|
428
|
+
title: "Wallet funding payments",
|
|
353
429
|
description: "Funding a Hyperliquid wallet paid or received, per market per bucket. Positive means received, negative means paid. bucket=1d gives daily totals, 1h the raw hourly payments.",
|
|
354
430
|
inputSchema: {
|
|
355
431
|
type: "object",
|
|
356
432
|
properties: {
|
|
357
433
|
address: { type: "string", description: "0x-prefixed 20-byte hex address" },
|
|
358
|
-
market: { type: "string", description:
|
|
359
|
-
from: { type: "
|
|
360
|
-
to: { type: "
|
|
434
|
+
market: { type: "string", description: MARKET_FILTER },
|
|
435
|
+
from: { type: "string", description: time("start") },
|
|
436
|
+
to: { type: "string", description: time("end") },
|
|
361
437
|
bucket: { type: "string", enum: ["1h", "1d", "raw"], description: "Aggregation bucket; default 1d" },
|
|
362
438
|
limit: { type: "number", description: `Most recent rows to return (default ${DEFAULT_FUNDING_ROWS})` },
|
|
363
439
|
},
|
|
@@ -366,8 +442,8 @@ export const tools = [
|
|
|
366
442
|
handler: async (args, api) => {
|
|
367
443
|
const address = requireString(args, "address");
|
|
368
444
|
const market = optionalString(args, "market", "");
|
|
369
|
-
const from =
|
|
370
|
-
const to =
|
|
445
|
+
const from = optionalTime(args, "from");
|
|
446
|
+
const to = optionalTime(args, "to");
|
|
371
447
|
const bucket = optionalString(args, "bucket", "1d");
|
|
372
448
|
const data = (await api.getUserFunding(address, market, from, to, bucket));
|
|
373
449
|
return JSON.stringify(shapeUserFunding(data, optionalNumber(args, "limit", DEFAULT_FUNDING_ROWS)));
|
|
@@ -375,35 +451,37 @@ export const tools = [
|
|
|
375
451
|
},
|
|
376
452
|
{
|
|
377
453
|
name: "get_user_maker_taker",
|
|
454
|
+
title: "Wallet maker/taker split",
|
|
378
455
|
description: "Maker vs taker breakdown of a Hyperliquid wallet's fills per market: volume, fees and rebates. A high maker share with negative maker fees marks a market maker.",
|
|
379
456
|
inputSchema: {
|
|
380
457
|
type: "object",
|
|
381
458
|
properties: {
|
|
382
459
|
address: { type: "string", description: "0x-prefixed 20-byte hex address" },
|
|
383
|
-
market: { type: "string", description:
|
|
384
|
-
from: { type: "
|
|
385
|
-
to: { type: "
|
|
460
|
+
market: { type: "string", description: MARKET_FILTER },
|
|
461
|
+
from: { type: "string", description: time("start") },
|
|
462
|
+
to: { type: "string", description: time("end") },
|
|
386
463
|
},
|
|
387
464
|
required: ["address"],
|
|
388
465
|
},
|
|
389
466
|
handler: async (args, api) => {
|
|
390
467
|
const address = requireString(args, "address");
|
|
391
468
|
const market = optionalString(args, "market", "");
|
|
392
|
-
const from =
|
|
393
|
-
const to =
|
|
469
|
+
const from = optionalTime(args, "from");
|
|
470
|
+
const to = optionalTime(args, "to");
|
|
394
471
|
const data = await api.getUserMakerTaker(address, market, from, to);
|
|
395
472
|
return JSON.stringify(data, null, 2);
|
|
396
473
|
},
|
|
397
474
|
},
|
|
398
475
|
{
|
|
399
476
|
name: "get_user_ledger",
|
|
477
|
+
title: "Wallet ledger",
|
|
400
478
|
description: "Vault deposits, withdrawals and transfers for a Hyperliquid wallet. Positive amounts go into the account. Account deposits and withdrawals are recorded only up to 2026-06-06.",
|
|
401
479
|
inputSchema: {
|
|
402
480
|
type: "object",
|
|
403
481
|
properties: {
|
|
404
482
|
address: { type: "string", description: "0x-prefixed 20-byte hex address" },
|
|
405
|
-
from: { type: "
|
|
406
|
-
to: { type: "
|
|
483
|
+
from: { type: "string", description: time("start") },
|
|
484
|
+
to: { type: "string", description: time("end") },
|
|
407
485
|
event_types: { type: "string", description: "Comma-separated type filter (deposit,withdrawal,vault_deposit,vault_withdraw,vault_transfer_in,vault_transfer_out)" },
|
|
408
486
|
limit: { type: "number", description: "Max entries, default 1000, cap 10000" },
|
|
409
487
|
},
|
|
@@ -411,8 +489,8 @@ export const tools = [
|
|
|
411
489
|
},
|
|
412
490
|
handler: async (args, api) => {
|
|
413
491
|
const address = requireString(args, "address");
|
|
414
|
-
const from =
|
|
415
|
-
const to =
|
|
492
|
+
const from = optionalTime(args, "from");
|
|
493
|
+
const to = optionalTime(args, "to");
|
|
416
494
|
const eventTypes = optionalString(args, "event_types", "");
|
|
417
495
|
const limit = optionalNumber(args, "limit", 1000);
|
|
418
496
|
const data = await api.getUserLedger(address, from, to, eventTypes, limit);
|
|
@@ -422,12 +500,13 @@ export const tools = [
|
|
|
422
500
|
// ─── Cross-wallet ranking (v0.34+) ─────────────────────────────────────
|
|
423
501
|
{
|
|
424
502
|
name: "get_pnl_leaderboard",
|
|
503
|
+
title: "PnL leaderboard",
|
|
425
504
|
description: "Every Hyperliquid wallet ranked by realized PnL, biggest losses or volume over a window. Wallets with fewer than 5 fills in the window are left out.",
|
|
426
505
|
inputSchema: {
|
|
427
506
|
type: "object",
|
|
428
507
|
properties: {
|
|
429
|
-
from: { type: "
|
|
430
|
-
to: { type: "
|
|
508
|
+
from: { type: "string", description: time("start", "Default 30 days ago") },
|
|
509
|
+
to: { type: "string", description: time("end", "Default now") },
|
|
431
510
|
limit: { type: "number", description: "Number of rows, max 200, default 50" },
|
|
432
511
|
sort_by: {
|
|
433
512
|
type: "string",
|
|
@@ -438,8 +517,8 @@ export const tools = [
|
|
|
438
517
|
required: [],
|
|
439
518
|
},
|
|
440
519
|
handler: async (args, api) => {
|
|
441
|
-
const from =
|
|
442
|
-
const to =
|
|
520
|
+
const from = optionalTime(args, "from");
|
|
521
|
+
const to = optionalTime(args, "to");
|
|
443
522
|
const limit = optionalNumber(args, "limit", 50);
|
|
444
523
|
const sortBy = optionalString(args, "sort_by", "realized_pnl");
|
|
445
524
|
const data = await api.getPnLLeaderboard(from, to, limit, sortBy);
|
|
@@ -448,13 +527,14 @@ export const tools = [
|
|
|
448
527
|
},
|
|
449
528
|
{
|
|
450
529
|
name: "get_market_top_wallets",
|
|
530
|
+
title: "Top wallets in a market",
|
|
451
531
|
description: "Top wallets on one Hyperliquid market by volume or realized PnL, up to 200 rows.",
|
|
452
532
|
inputSchema: {
|
|
453
533
|
type: "object",
|
|
454
534
|
properties: {
|
|
455
|
-
market: { type: "string", description:
|
|
456
|
-
from: { type: "
|
|
457
|
-
to: { type: "
|
|
535
|
+
market: { type: "string", description: MARKET },
|
|
536
|
+
from: { type: "string", description: time("start", "Default 24 hours ago") },
|
|
537
|
+
to: { type: "string", description: time("end", "Default now") },
|
|
458
538
|
limit: { type: "number", description: "Number of rows, max 200, default 25" },
|
|
459
539
|
sort_by: {
|
|
460
540
|
type: "string",
|
|
@@ -466,8 +546,8 @@ export const tools = [
|
|
|
466
546
|
},
|
|
467
547
|
handler: async (args, api) => {
|
|
468
548
|
const market = requireString(args, "market");
|
|
469
|
-
const from =
|
|
470
|
-
const to =
|
|
549
|
+
const from = optionalTime(args, "from");
|
|
550
|
+
const to = optionalTime(args, "to");
|
|
471
551
|
const limit = optionalNumber(args, "limit", 25);
|
|
472
552
|
const sortBy = optionalString(args, "sort_by", "volume");
|
|
473
553
|
const data = await api.getMarketTopWallets(market, from, to, limit, sortBy);
|
|
@@ -476,6 +556,7 @@ export const tools = [
|
|
|
476
556
|
},
|
|
477
557
|
{
|
|
478
558
|
name: "get_markets_snapshot",
|
|
559
|
+
title: "Markets snapshot",
|
|
479
560
|
description: "Active Hyperliquid markets ranked in one call: mark price, 24h change, 24h volume, open interest and current hourly funding. Sort by abs_funding for the most extreme funding, abs_change_24h for the biggest movers, or volume (default). Use min_volume_usd to skip illiquid markets. Returns the top 25 unless limit is set.",
|
|
480
561
|
inputSchema: {
|
|
481
562
|
type: "object",
|
|
@@ -515,26 +596,28 @@ export const tools = [
|
|
|
515
596
|
},
|
|
516
597
|
{
|
|
517
598
|
name: "get_user_summary",
|
|
599
|
+
title: "Wallet summary",
|
|
518
600
|
description: "One Hyperliquid wallet's stats over a window: volume, realized PnL, fill count, win rate, maker share and markets traded.",
|
|
519
601
|
inputSchema: {
|
|
520
602
|
type: "object",
|
|
521
603
|
properties: {
|
|
522
604
|
address: { type: "string", description: "0x-prefixed 20-byte hex address" },
|
|
523
|
-
from: { type: "
|
|
524
|
-
to: { type: "
|
|
605
|
+
from: { type: "string", description: time("start", "Default 24 hours ago") },
|
|
606
|
+
to: { type: "string", description: time("end", "Default now") },
|
|
525
607
|
},
|
|
526
608
|
required: ["address"],
|
|
527
609
|
},
|
|
528
610
|
handler: async (args, api) => {
|
|
529
611
|
const address = requireString(args, "address");
|
|
530
|
-
const from =
|
|
531
|
-
const to =
|
|
612
|
+
const from = optionalTime(args, "from");
|
|
613
|
+
const to = optionalTime(args, "to");
|
|
532
614
|
const data = await api.getUserSummary(address, from, to);
|
|
533
615
|
return JSON.stringify(data, null, 2);
|
|
534
616
|
},
|
|
535
617
|
},
|
|
536
618
|
{
|
|
537
619
|
name: "get_wallet_labels",
|
|
620
|
+
title: "Wallet labels",
|
|
538
621
|
description: "Labels for notable Hyperliquid wallets: top whales by 24h volume, top traders by 30-day realized PnL, vaults and vault leaders. Pass addresses to check specific wallets; without them it lists the whales and smart money.",
|
|
539
622
|
inputSchema: {
|
|
540
623
|
type: "object",
|
|
@@ -558,21 +641,22 @@ export const tools = [
|
|
|
558
641
|
},
|
|
559
642
|
{
|
|
560
643
|
name: "get_user_pnl_series",
|
|
644
|
+
title: "Wallet PnL curve",
|
|
561
645
|
description: "Realized PnL curve of a Hyperliquid wallet over time, bucketed (for example hourly or daily).",
|
|
562
646
|
inputSchema: {
|
|
563
647
|
type: "object",
|
|
564
648
|
properties: {
|
|
565
649
|
address: { type: "string", description: "0x-prefixed 20-byte hex address" },
|
|
566
|
-
from: { type: "
|
|
567
|
-
to: { type: "
|
|
650
|
+
from: { type: "string", description: time("start") },
|
|
651
|
+
to: { type: "string", description: time("end", "Default now") },
|
|
568
652
|
bucket_ms: { type: "number", description: "Bucket size in ms (e.g. 3600000 for 1h)" },
|
|
569
653
|
},
|
|
570
654
|
required: ["address"],
|
|
571
655
|
},
|
|
572
656
|
handler: async (args, api) => {
|
|
573
657
|
const address = requireString(args, "address");
|
|
574
|
-
const from =
|
|
575
|
-
const to =
|
|
658
|
+
const from = optionalTime(args, "from");
|
|
659
|
+
const to = optionalTime(args, "to");
|
|
576
660
|
const bucketMs = optionalNumber(args, "bucket_ms", 0);
|
|
577
661
|
const data = await api.getUserPnLSeries(address, from, to, bucketMs);
|
|
578
662
|
return JSON.stringify(data, null, 2);
|
|
@@ -581,6 +665,7 @@ export const tools = [
|
|
|
581
665
|
// ─── Signals (public endpoints: 60 requests per minute per IP, no key) ──
|
|
582
666
|
{
|
|
583
667
|
name: "get_top_traders",
|
|
668
|
+
title: "Top traders",
|
|
584
669
|
description: "Hyperliquid traders ranked across all markets by results over 7, 30 or 90 days: win rate, profit factor, realized PnL, max drawdown and best markets. sort=top ranks by realized PnL, lowrisk by smallest max drawdown, new by most recently first seen.",
|
|
585
670
|
inputSchema: {
|
|
586
671
|
type: "object",
|
|
@@ -602,11 +687,12 @@ export const tools = [
|
|
|
602
687
|
},
|
|
603
688
|
{
|
|
604
689
|
name: "get_market_leaders",
|
|
690
|
+
title: "Market leaders",
|
|
605
691
|
description: "The best traders on one Hyperliquid market, ranked by profit factor then win rate, among wallets with at least 5 closed trades there.",
|
|
606
692
|
inputSchema: {
|
|
607
693
|
type: "object",
|
|
608
694
|
properties: {
|
|
609
|
-
market: { type: "string", description:
|
|
695
|
+
market: { type: "string", description: MARKET },
|
|
610
696
|
window: { type: "string", description: "Lookback window. Default 30d", enum: ["7d", "30d", "90d"] },
|
|
611
697
|
limit: { type: "number", description: "Number of traders (1-50, default 20)" },
|
|
612
698
|
},
|
|
@@ -623,11 +709,12 @@ export const tools = [
|
|
|
623
709
|
},
|
|
624
710
|
{
|
|
625
711
|
name: "get_early_movers",
|
|
712
|
+
title: "Early movers",
|
|
626
713
|
description: "Wallets whose large orders (at least $10k) on a Hyperliquid market were followed by a price move in their direction within 30 minutes. Returns a lead score in basis points and a hit rate per wallet. Past activity does not predict future results.",
|
|
627
714
|
inputSchema: {
|
|
628
715
|
type: "object",
|
|
629
716
|
properties: {
|
|
630
|
-
market: { type: "string", description:
|
|
717
|
+
market: { type: "string", description: MARKET },
|
|
631
718
|
window: { type: "string", description: "Lookback window. Default 30d", enum: ["7d", "30d"] },
|
|
632
719
|
limit: { type: "number", description: "Number of wallets (1-25, default 10)" },
|
|
633
720
|
},
|
|
@@ -644,6 +731,7 @@ export const tools = [
|
|
|
644
731
|
},
|
|
645
732
|
{
|
|
646
733
|
name: "get_trader_profile",
|
|
734
|
+
title: "Trader profile",
|
|
647
735
|
description: "A Hyperliquid wallet's trading record over 7, 30 or 90 days: win rate, profit factor, realized PnL, max drawdown and its best markets.",
|
|
648
736
|
inputSchema: {
|
|
649
737
|
type: "object",
|
|
@@ -664,6 +752,7 @@ export const tools = [
|
|
|
664
752
|
// ─── Cohorts ─────────────────────────────────────────────────────────
|
|
665
753
|
{
|
|
666
754
|
name: "list_cohorts",
|
|
755
|
+
title: "List cohorts",
|
|
667
756
|
description: "List available address cohorts: six predefined groups (top_pnl_30d, high_volume_30d, whale_fills, net_withdrawers_7d, liquidation_prone, vault_whales) plus any custom cohorts the caller has created",
|
|
668
757
|
inputSchema: { type: "object", properties: {}, required: [] },
|
|
669
758
|
handler: async (_args, api) => {
|
|
@@ -673,7 +762,8 @@ export const tools = [
|
|
|
673
762
|
},
|
|
674
763
|
{
|
|
675
764
|
name: "get_cohort_addresses",
|
|
676
|
-
|
|
765
|
+
title: "Cohort addresses",
|
|
766
|
+
description: "Wallet addresses in one cohort; list_cohorts gives the names.",
|
|
677
767
|
inputSchema: {
|
|
678
768
|
type: "object",
|
|
679
769
|
properties: {
|
|
@@ -690,7 +780,8 @@ export const tools = [
|
|
|
690
780
|
// ─── Account & Status ────────────────────────────────────────────────
|
|
691
781
|
{
|
|
692
782
|
name: "get_status",
|
|
693
|
-
|
|
783
|
+
title: "API status",
|
|
784
|
+
description: "Ironflow service status right now: overall state, data freshness per venue and component health.",
|
|
694
785
|
inputSchema: { type: "object", properties: {}, required: [] },
|
|
695
786
|
handler: async (_args, api) => {
|
|
696
787
|
const data = await api.getStatus();
|
|
@@ -699,7 +790,8 @@ export const tools = [
|
|
|
699
790
|
},
|
|
700
791
|
{
|
|
701
792
|
name: "get_status_metrics",
|
|
702
|
-
|
|
793
|
+
title: "API performance metrics",
|
|
794
|
+
description: "Ironflow performance over rolling windows: API latency and error rate, ingestion lag and synthetic probe timings.",
|
|
703
795
|
inputSchema: { type: "object", properties: {}, required: [] },
|
|
704
796
|
handler: async (_args, api) => {
|
|
705
797
|
const data = await api.getStatusMetrics();
|
|
@@ -708,7 +800,8 @@ export const tools = [
|
|
|
708
800
|
},
|
|
709
801
|
{
|
|
710
802
|
name: "get_status_history",
|
|
711
|
-
|
|
803
|
+
title: "API uptime history",
|
|
804
|
+
description: "Ironflow uptime and data freshness per hour over the last 24 hours (default) or 7 days.",
|
|
712
805
|
inputSchema: {
|
|
713
806
|
type: "object",
|
|
714
807
|
properties: {
|
|
@@ -728,34 +821,47 @@ export const tools = [
|
|
|
728
821
|
},
|
|
729
822
|
{
|
|
730
823
|
name: "list_markets",
|
|
731
|
-
|
|
824
|
+
title: "List markets",
|
|
825
|
+
description: "Find how a Hyperliquid market is named: perps (native and HIP-3), spot and live HIP-4 outcomes, with symbol, class, issuer, base asset and Hyperliquid coin. Search with q (q=nvda finds xyz:NVDA-PERP and the other NVDA perps). Pages of up to 100 rows; pass pagination.next_cursor as cursor for the next page.",
|
|
732
826
|
inputSchema: {
|
|
733
827
|
type: "object",
|
|
734
828
|
properties: {
|
|
735
|
-
|
|
829
|
+
q: { type: "string", description: "Case-insensitive search over symbol, base asset, Hyperliquid coin and issuer" },
|
|
736
830
|
market_class: {
|
|
737
831
|
type: "string",
|
|
738
|
-
description: "
|
|
832
|
+
description: "Only this class. 'prediction' is HIP-4 outcomes. Omit for all.",
|
|
739
833
|
enum: ["perp", "spot", "prediction", "option"],
|
|
740
834
|
},
|
|
741
835
|
issuer: {
|
|
742
836
|
type: "string",
|
|
743
|
-
description: "HIP-3 issuer code (e.g. '
|
|
837
|
+
description: "HIP-3 issuer code (e.g. 'xyz'). '' returns native markets only. Omit for every issuer.",
|
|
838
|
+
},
|
|
839
|
+
include_inactive: {
|
|
840
|
+
type: "boolean",
|
|
841
|
+
description: "Also return closed markets (delisted, settled HIP-4 outcomes), which carry active_to_ms. Default false.",
|
|
744
842
|
},
|
|
745
|
-
|
|
746
|
-
|
|
843
|
+
limit: { type: "number", description: `Rows per page (default ${DEFAULT_MARKETS_LIMIT}, max ${MAX_MARKETS_LIMIT})` },
|
|
844
|
+
cursor: { type: "string", description: "pagination.next_cursor from the previous page, with the same filters" },
|
|
845
|
+
source: { type: "string", description: "Venue. Default 'hyperliquid'." },
|
|
747
846
|
},
|
|
748
847
|
required: [],
|
|
749
848
|
},
|
|
750
849
|
handler: async (args, api) => {
|
|
751
|
-
const source = optionalString(args, "source", "");
|
|
752
|
-
const market_class = optionalString(args, "market_class", "");
|
|
753
850
|
// Tri-state: present-with-empty-string means "native only".
|
|
754
|
-
const issuer = Object.prototype.hasOwnProperty.call(args, "issuer")
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const
|
|
758
|
-
|
|
851
|
+
const issuer = Object.prototype.hasOwnProperty.call(args, "issuer") ? optionalString(args, "issuer", "") : undefined;
|
|
852
|
+
// search was this tool's name for q before 0.11.0; still accepted.
|
|
853
|
+
const q = optionalString(args, "q", "").trim() || optionalString(args, "search", "").trim();
|
|
854
|
+
const limit = Math.min(optionalNumber(args, "limit", DEFAULT_MARKETS_LIMIT), MAX_MARKETS_LIMIT);
|
|
855
|
+
const data = (await api.listMarkets({
|
|
856
|
+
source: optionalString(args, "source", ""),
|
|
857
|
+
marketClass: optionalString(args, "market_class", ""),
|
|
858
|
+
issuer,
|
|
859
|
+
q,
|
|
860
|
+
includeInactive: optionalBoolean(args, "include_inactive"),
|
|
861
|
+
limit,
|
|
862
|
+
cursor: optionalString(args, "cursor", "").trim(),
|
|
863
|
+
}));
|
|
864
|
+
return JSON.stringify(shapeMarkets(data, { search: q, limit }));
|
|
759
865
|
},
|
|
760
866
|
},
|
|
761
867
|
];
|