Skip to main content
Glama

OpenFinance — Easy Trading: Crypto, Stocks, Perps & Prediction Markets

hyperliquid

Hyperliquid: perps + spot trading, account state, orders, TWAP, leverage, withdrawals, account abstraction, and websocket data. Single-tool dispatch on action. Pass only the params listed below for each action; everything else is ignored.

CHAIN MODEL — read this before describing deposits/withdrawals to a user: Hyperliquid is its OWN L1 trading venue. It is NOT "Hyperliquid on Arbitrum" and there is no "USDC on Hyperliquid (Arbitrum)" ticker. The bridge is the only link to Arbitrum: - FUND: send USDC on Arbitrum → your Hyperliquid deposit address (the address returned by get_deposit_address). That address lives on Arbitrum; Hyperliquid's L1 validators co-sign and credit the funds to your Hyperliquid account. - EXIT: action='withdraw_to_arbitrum' burns Hyperliquid USDC and the validators co-sign a payout to the SAME EOA on Arbitrum (flat $1 fee, ~5 min). Hyperliquid only accepts USDC, not USDT or USDC.e. Funding-from-INR routing is therefore: onramp INR → USDC on Polygon/BSC (Onramp.money supports those for USDC), bridge USDC → Arbitrum via Relay, then deposit USDC on Arbitrum to the Hyperliquid deposit address. Never tell the user to onramp to "USDC on Hyperliquid" or "USDC on Arbitrum (Hyperliquid)" — those phrases are wrong.

PUBLIC DATA (no auth): get_all_mids — {}: map of asset symbol → mid price. get_market_metas — { kind?: 'all'|'perp'|'spot' (default 'all'), dex? }: 'all' returns asset contexts (funding rate, OI, mark/mid/oracle px, 24h vol, prevDayPx); 'perp' returns the perp universe (asset indices, name, szDecimals, maxLeverage, marginTableId, isDelisted) — call this before placing orders to look up indices and szDecimals; 'spot' returns spot universes/pairs and contexts (midPx, markPx, supplies, day volumes). get_perp_categories — {}: returns [[symbol, category], ...] for every HIP-3 (dex-prefixed) perp. Categories: 'crypto', 'stocks', 'commodities', 'indices', 'fx', 'preipo'. Symbols are dex-prefixed (e.g. 'xyz:NVDA', 'vntl:SPACEX', 'km:GOLD', 'flx:BTC', 'para:OTHERS'). Use for discovery — "list HIP-3 stock perps", "what FX HIP-3 perps exist", "show commodities", "what pre-IPO perps are listed" — without walking the whole metas universe. To place an order on one of these symbols, look it up in get_market_metas kind='perp' to get the asset index and szDecimals. get_l2_book — { coin }: L2 orderbook (bids/asks with px, sz, n). get_token_details — { tokenId }: spot token details (full hex hash from spot universe — e.g. "0xc1fb593aeffbeb02f85e0308e9956a90", not a simple number). get_candle_snapshot — { coin, interval, startTime, endTime? }: OHLCV candles. Intervals: 1m,3m,5m,15m,30m,1h,2h,4h,8h,12h,1d,3d,1w,1M. For HIP-3 spot prefix coin like "xyz:XYZ100".

ACCOUNT (auth). Every user-scoped read below — get_account_summary, get_open_orders, get_historical_orders, get_order_status, get_user_fills, get_user_funding_history, get_twap_fills, get_user_abstraction, get_rate_limit — accepts an OPTIONAL address (0x-prefixed). When set, the call returns that address's data instead of the caller's. Omit it for the caller's own data. Use for watchlists / copy-trading / "show me what wallet X is doing" queries. Note: get_deposit_address is caller-only by design (depositing on someone else's behalf doesn't make sense). get_deposit_address — {}: returns the user's Hyperliquid deposit address. That address LIVES ON ARBITRUM — to fund Hyperliquid the user sends USDC on Arbitrum (not Polygon, not Ethereum, not USDT) to this address, and Hyperliquid validators credit their L1 account within ~minutes. get_account_summary — { view?: 'perp'|'all' (default 'perp') }: 'perp' returns the unified snapshot — clearinghouseState across the native dex AND every HIP-3 dex (xyz, flx, vntl, hyna, km, abcd, cash, para, …) with each dex's marginSummary/withdrawable/assetPositions, plus spotClearinghouseState (token balances) and userAbstraction in one response. So one call gets perp positions on every dex + spot — do NOT loop per-dex, and there is no separate 'spot' view (read spotClearinghouseState from the same response). 'all' is different: it returns the time-series portfolio (equity curve over windows), not a current snapshot. get_batch_portfolio_states — { users: string[] }: portfolio snapshot for ANY list of Hyperliquid addresses — NOT the caller's. Always against ALL_DEXES (native + every HIP-3 dex + spot per address). Use when the user wants to track/compare other traders ("watch wallet X", "compare these 3 addresses", leaderboard, copy-trading dashboard). One round-trip; fans out across dexes server-side. Do NOT loop get_account_summary; do NOT pass the caller's own address (use get_account_summary for that). users must be a non-empty array. Response shape: { successful_states: [[address, { clearinghouseState: { native, xyz, flx, … per dex }, spotClearinghouseState: { balances: [...] }, userAbstraction }], …], failed_wallets: string[] } — successful_states is an array of [address, portfolio] tuples (NOT a dict), so iterate with entry[0] = address, entry[1] = portfolio. Check failed_wallets for any address that couldn't be fetched. get_rate_limit — {}: current API rate-limit window.

ORDERS (auth): get_open_orders — { verbose? }: open orders (verbose=true adds origSz, triggerPx, triggerCondition, cloid, reduceOnly). get_historical_orders — {}: filled/cancelled/rejected orders with statusMsg, filledSz, avgFillPx. get_order_status — { oid }: status of a specific order.

⚠ REQUEST-SHAPE WARNING (most common MCP failure mode) — the request body uses Hyperliquid's SINGLE-LETTER field names. The human-readable shape (coin / is_buy / sz / limit_px / order_type / reduce_only) only appears in GET responses; the REQUEST side REJECTS those names. Sending them produces a confusing 500 ("Cannot read properties of undefined (reading 'limit')") because the validator reads order.t.limit.tif. ❌ WRONG (crashes): { "orders": [{ "coin": "xyz:NVDA", "is_buy": false, "sz": 0.052, "limit_px": 384.96, "order_type": { "limit": { "tif": "FrontendMarket" } }, "reduce_only": false }], "grouping": "na" } ✅ RIGHT: { "orders": [{ "a": 110012, "b": false, "s": "0.052", "p": "384.96", "t": { "limit": { "tif": "FrontendMarket" } }, "r": false, "szDecimals": 4 }], "grouping": "na" }

ASSET INDEX (a) — compute, do NOT pass a coin symbol: • Main-DEX perps: a = index_in_meta (BTC=0, ETH=1, …; get from get_market_metas kind='perp') • HIP-3 perps: a = 100000 + perp_dex_index * 10000 + index_in_meta (xyz:NVDA: perp_dex_index=1, index_in_meta=12 → a=110012) • Spot pairs: a = 10000 + spotInfo.index (PURR/USDC: spotInfo.index=0 → a=10000; from get_market_metas kind='spot') • HIP-4 outcomes: a = 100_000_000 + (10 * outcome + side) (outcome=35 / side=Yes(1) → encoding 351 → a=100000351 — EIGHT zeros after the 1, NOT five — easy to miscount) Reference: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/asset-ids

place_order — { orders: [{ a, b, p, s, r, t, c?, szDecimals }], grouping?: 'na'|'normalTpsl'|'positionTpsl' }: a = numeric asset index (see formula above). b = true(buy)/false(sell). p = price STRING ("65000"). s = size STRING in base-asset units. r = reduceOnly bool. c = optional cloid. szDecimals = size precision from get_market_metas — STRONGLY RECOMMENDED: when provided, the backend lot-rounds price/size to HL's rules before signing (matches the canonical form HL recovers the signer from). When omitted, the backend strips trailing zeros from the raw string; for whole-number sizes that's fine, but fractional sizes that don't already match HL's lot rules will sign at the rounded value, not what you intended. Pass szDecimals whenever you've read it from market metas. t = order type, EXACTLY ONE branch: • { "limit": { "tif": "Gtc" | "Ioc" | "Alo" | "FrontendMarket" } } — Gtc=resting, Ioc=cross-book (buy-now), Alo=post-only, FrontendMarket=stock-perp default for HIP-3 • { "trigger": { "isMarket": bool, "triggerPx": "string-or-number", "tpsl": "tp" | "sl" } } grouping = "na" (default) | "normalTpsl" (group TP/SL with primary) | "positionTpsl" (attach TP/SL to existing position).

On "insufficient" errors the response carries `insufficientCollateral: [{ requiredAsset, dex, context, message }]` — the collateral asset is NOT always the same: native perps = USDC, HIP-4 outcomes = USDC, HIP-3 perps use the dex's `collateralToken` (per dex `meta`, usually USDC, occasionally USDH for a few dexes). Relay requiredAsset + message verbatim — if a HIP-3 dex asks for USDH, swap USDC → USDH on Hyperliquid spot (see "USDH SWAP" below) before retrying. HIP-4 outcome trades just need USDC.

cancel_order — { cancels: [{ a, o }] }: a=numeric asset index (same formula), o=order id. modify_order — { oid, order: { a, b, p, s, r, t, c?, szDecimals } }: same shape as place_order order.

USDH SWAP (USDC → USDH) — only for HIP-3 dexes whose collateralToken is USDH (NOT needed for HIP-4 outcomes, which use USDC): 1. get_market_metas kind='spot' → find the universe entry whose tokens reference USDH (commonly name 'USDH/USDC') → note its index AND the pair's szDecimals. 2. Compute a = 10000 + spotInfo.index. 3. place_order with { a, b: true, p: <USDH price ≈ "1.00">, s: <USDC amount as a decimal STRING, rounded to szDecimals>, r: false, t: { "limit": { "tif": "Ioc" } }, szDecimals }. Ioc fills immediately at or better than the limit. 4. Confirm: get_account_summary → look for coin='USDH' in spotClearinghouseState.balances. Same flow for any spot swap (USDC→HYPE, USDC→PURR, …) — only the pair differs.

PRE-ORDER CHECKLIST (run BEFORE every place_order — especially HIP-3 / HIP-4): 1. get_account_summary to read unifiedFreeUSDC = clearinghouseState.withdrawable + spotClearinghouseState.balances.USDC.total and userAbstraction. 2. If userAbstraction ∈ {"default", "disabled"} AND clearinghouseState.withdrawable > 0, call set_user_abstraction { abstraction: "u" } first (one-shot, idempotent — surface as a notice, not a confirmation prompt). 3. HIP-3 perp: check the dex's collateralToken. If USDH and user has no USDH balance → run USDH SWAP first. 4. HIP-4 outcome: settles in USDC — same unifiedFreeUSDC check as native perps. No USDH, no swap. 5. Pull szDecimals from get_market_metas — required in the order payload for signature recovery.

TWAP (auth): get_twap_fills — {}: per-slice executions. place_twap_order — { a, b, s, m, r?, t?, szDecimals? }: a=asset index, b=true/false, s=total size, m=duration minutes, r=reduceOnly, t=randomize-timing boolean (NOT the order-type object), szDecimals=optional size precision from get_market_metas (when passed the backend lot-rounds s). terminate_twap_order — { twapId, asset }.

FILLS / FUNDING (auth): get_user_fills — { startTime?, endTime?, aggregateByTime? }: pass startTime to filter by time range; otherwise returns latest. get_user_funding_history — {}: funding payments (fundingRate, usdc amount, timestamp, position size).

LEVERAGE / MARGIN (auth): update_leverage — { asset, leverage, isCross? }. update_isolated_margin — { asset, amount, isBuy }: positive amount adds, negative removes.

WITHDRAWAL (auth): withdraw_to_arbitrum — { amount }: USDC to caller's own EVM address on Arbitrum (flat $1 fee, ~5 min finality).

ACCOUNT ABSTRACTION (auth): get_user_abstraction — {}: returns 'unifiedAccount' | 'portfolioMargin' | 'disabled' | 'default' | 'dexAbstraction'. set_user_abstraction — { abstraction: 'u' }: switches to unifiedAccount (only supported mode; one-shot per wallet).

WEBSOCKET: set_all_dexs_asset_ctxs_subscription — { subscribe }: toggle live allDexsAssetCtxs stream. get_all_dexs_asset_ctxs — {}: latest cached snapshot. Returns array indexed by asset position from get_market_metas — call that to map indices to names. get_ws_status — {}: { connected: boolean }.

OUTCOMES (HIP-4 — Hyperliquid's prediction-market-style binary outcomes): Each outcome has two sides (No=0, Yes=1). Outcomes are grouped under questions; a question carries a fallbackOutcome plus a list of namedOutcomes. Collateral: HIP-4 outcomes settle in USDC — same as native perps. split/merge/negate burn or mint USDC, and buying/selling outcome share tokens via place_order debits/credits USDC. No USDH and no spot swap is needed (this changed — HIP-4 used to require USDH; it no longer does). On "insufficient" errors the response carries insufficientCollateral: { requiredAsset: 'USDC', ... } — relay that to the user. Asset-ID encoding (used by place_order, modify_order, cancel_order for outcome tokens): encoding = 10 * outcome + side (side ∈ {0, 1}) spot coin: "#" token name: "+" asset ID: 100_000_000 + encoding Example: outcome=1, side=1 (Yes) → encoding 11 → spot "#11" → asset ID 100000011. Actions: get_outcome_meta — {} (no auth): returns BOTH the raw upstream payload AND a partitioned, metadata-enriched presentation view — • outcomes / questions — raw arrays from HL (backward-compat). • binaryMarkets — standalone Yes/No outcomes NOT grouped under any question. Simple "Will X happen?" bets. Each carries { outcome, name, description, sideSpecs, metadata }. Trade via place_order with the outcome's asset ID; resolve via split / merge. • questionMarkets — questions that group N named outcomes sharing one quote pool, resolving mutually exclusively. Each entry expands { question, name, description, metadata, fallbackOutcome, fallbackOutcomeDetail, namedOutcomes, namedOutcomeDetails (each with its own metadata), settledNamedOutcomes, settledNamedOutcomeDetails } so you can render the question's children without re-joining. Resolve via merge_question / negate_outcome. • counts — { binary, question, totalOutcomes, totalQuestions }.

  ⚠ DISPLAY NAMES ARE RECYCLED — every BTC daily market is named "Recurring", every named outcome inside one is "Recurring Named Outcome", the fallback is "Recurring Fallback". DO NOT use `name` alone to render — it tells the user nothing. The real semantics live in `metadata` (parsed from the description's "key:value|key:value" form):
    • Binary: `metadata.class === 'priceBinary'` with { underlying, expiry: "YYYYMMDD-HHmm" UTC, targetPrice, period } → render as "Will <underlying> hit $<targetPrice> by <expiry formatted>? (<period>)".
    • Question: `metadata.class === 'priceBucket'` with { underlying, expiry, priceThresholds: "T1,T2,…", period }. The named outcomes have `metadata.index = "0"|"1"|…` which maps to bucket ranges defined by the parent's thresholds:
        index=0 → <underlying> < T1
        index=k → T_k ≤ <underlying> < T_{k+1}
        index=N (last) → <underlying> ≥ T_N
        fallback (metadata.tag = "other") → settlement source unavailable / other
    • Other classes may exist (sports, elections, etc.) — surface metadata.class verbatim and any keys you recognize; fall back to raw `description` if nothing parses.
  Always present binaryMarkets and questionMarkets as TWO DISTINCT SECTIONS so a Yes/No bet isn't confused with a one-of-N question. Don't dump the flat outcomes array; route through the partitioned view.
split_outcome — { outcome, outcomeAmount }: burn outcomeAmount quote tokens, mint outcomeAmount Yes + outcomeAmount No shares. outcomeAmount is a decimal string (e.g. "123.0").
merge_outcome — { outcome, outcomeAmount? }: burn outcomeAmount Yes + outcomeAmount No → mint outcomeAmount quote. Omit outcomeAmount (or pass null) for max.
merge_question — { question, outcomeAmount? }: burn outcomeAmount Yes shares of every named outcome of the question → mint outcomeAmount quote. Omit/null for max.
negate_outcome — { question, outcome, outcomeAmount }: burn outcomeAmount No shares of one outcome → mint outcomeAmount Yes shares of every OTHER outcome of the same question.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "action": "<action>"
    },
    "name": "hyperliquid"
  }
}

Input Schema

NameRequiredDescriptionDefault
aNo
bNo
mNo
rNo
sNo
tNoTWAP randomize-timing flag (NOT the order-type object — that lives inside orders[].t)
dexNo
oidNo
coinNo
kindNo
viewNo
assetNo
isBuyNo
orderNoSingle order object for modify_order
usersNoHyperliquid addresses for get_batch_portfolio_states
actionYesWhich Hyperliquid action to perform — see tool description
amountNo
ordersNoArray of orders for place_order — see description for per-order shape
twapIdNo
addressNoOptional 0x-prefixed Hyperliquid address. When set, every user-scoped read (account, orders, fills, funding, abstraction, twap-fills, …) targets THAT address instead of the caller. Omit for the caller's own data.
cancelsNoArray of {a, o} for cancel_order
endTimeNo
isCrossNo
outcomeNoOutcome id (HIP-4)
tokenIdNo
verboseNo
groupingNo
intervalNo
leverageNo
questionNoQuestion id (HIP-4)
startTimeNo
subscribeNo
szDecimalsNoOptional TWAP size precision (from get_market_metas) — when present the backend lot-rounds `s`.
abstractionNo
outcomeAmountNoHIP-4 split/merge/negate amount as a decimal string ("123.0"). Pass null for "max" on merge_outcome / merge_question.
aggregateByTimeNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observed

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden; it does so with auth requirements, a prominent request-shape crash warning, asset-ID formulas, collateral-token differences, withdrawal fee/finality details, and outcome burn/mint semantics. It also discloses display-name recycling and pre-order prerequisites, which are exactly the kind of behavioral context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The sectioned layout and front-loaded chain model make a very large surface navigable, and most warnings earn their place by preventing concrete failure modes. However, the document is extremely long, with repeated chain-model and outcome-collateral explanations that could be tightened without losing correctness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 36 parameters, no annotations, no output schema, and partial schema coverage, the description supplies the missing auth model, request shape, asset-ID derivation, pre-order checklist, response snippets such as the `get_batch_portfolio_states` tuple shape, and HIP-4 outcome behavior. That is sufficient for an agent to invoke the dispatch surface correctly across both public and authenticated actions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With schema description coverage only 31% and 36 parameters, the description compensates by defining the single-letter order fields (`a`, `b`, `s`, `p`, `t`, `r`, `c`, `szDecimals`), the asset-index formulas for main-DEX, HIP-3, spot, and HIP-4, and per-action parameters like `view`, `kind`, `verbose`, `outcomeAmount`, and `question`/`outcome`. The empty nested `orders` and `cancels` item schemas are also fully specified in prose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names the venue and enumerates concrete domains — perps + spot trading, account state, orders, TWAP, leverage, withdrawals, account abstraction, and websocket data — and states that dispatch is on `action`. This is specific enough to separate it from sibling venue/platform tools without needing to open the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description routes the agent to specific actions for each task and names alternatives within the tool: `get_batch_portfolio_states` versus `get_account_summary`, `get_perp_categories` for discovery, `get_market_metas` before placing orders, and explicit 'do NOT loop' guidance. It does not explicitly state when to choose this tool over sibling tools such as `polymarket` for prediction-market queries, which leaves one usage boundary unaddressed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.