aster-agent-gateway

An MCP (Model Context Protocol) server that gives AI agents read-only,
keyless access to Aster DEX public data - ~580 futures symbols
(including 24/7 TradFi perps: metals, equity indices, energy,
treasuries), ~68 spot pairs, funding, order books, klines, vault
deposit flows and tapi account views. No API keys, no auth, no
signing, no writes: every tool reads public endpoints only
(fapi.asterdex.com/fapi/v3, sapi.asterdex.com/api/v3,
tapi.asterdex.com/info, api.mainnet-beta.solana.com, plus optional
EVM RPCs), cached and rate-limited so an enthusiastic agent cannot
hammer the upstream.
Use cases
- Screen 731 funding rates in one call — ranked by annualized rate with funding regime and mark/index spread; the 793% outliers are visible instantly
- Trade TradFi 24/7 — metals, equity indices, energy, treasuries perps next to crypto, one consistent API
- Follow the vault money — deposit flows per vault: who is parking capital where
- Spot index dislocations — mark vs index divergence ranking across the whole board
- Morning scan — market overview + funding overview + OI snapshot, three cheap calls
Full walkthroughs: examples/use-cases.md.
Quickstart
Claude Code:
claude mcp add aster -- uvx aster-agent-gateway
stdio (default, for local agents):
uvx aster-agent-gateway
or from a checkout:
git clone https://github.com/alekskram/aster-agent-gateway
cd aster-agent-gateway
uv sync
uv run aster-agent-gateway
Claude Desktop / Cursor config:
{
"mcpServers": {
"aster": {
"command": "uvx",
"args": ["aster-agent-gateway"]
}
}
}
Hosted form — streamable HTTP on port 8904:
uvx aster-agent-gateway --http
curl http://127.0.0.1:8904/health
Codex (~/.codex/config.toml)
[mcp_servers.aster]
command = "uvx"
args = ["aster-agent-gateway"]
ZCode — register the server (copy-paste)
uvx aster-agent-gateway --http --port 8904 &
python3 - <<'PY'
import json, os
p = os.path.expanduser("~/.zcode/cli/config.json")
os.makedirs(os.path.dirname(p), exist_ok=True)
cfg = json.load(open(p)) if os.path.exists(p) else {}
cfg.setdefault("mcp", {}).setdefault("servers", {})["aster"] = {
"type": "http", "url": "http://127.0.0.1:8904/mcp"}
json.dump(cfg, open(p, "w"), indent=2)
print("aster-agent-gateway registered:", p)
PY
Tools
All 13 tools are read-only (annotated readOnlyHint: true, destructiveHint: false).
| 1 | market_overview | market_overview(limit=20, sort="volume") | Futures panel from ONE ticker/24hr ALL call joined with exchangeInfo: TRADING markets, top volumes, status counts, fresh listings (onboardDate). |
| 2 | exchange_symbols | exchange_symbols(venue="futures", symbol=None, include_junk=False) | Symbol universe with filters/precisions incl. MIN_NOTIONAL, stepSize, leverageFilter; TEST*/SETTLING junk filtered by default. |
| 3 | order_book | order_book(symbol, venue="futures", depth=10) | fapi depth / sapi api/v3 depth; limit snapped to a priced tier (weight-aware). |
| 4 | klines | klines(symbol, interval="1h", limit=100, market="futures", price_type="last") | last/mark/index klines on fapi; spot via sapi. |
| 5 | trades | trades(symbol, limit=20, venue="futures") | Fresh keyless trades; spot path probed live (honest error dict if dead). |
| 6 | spot_overview | spot_overview(limit=20) | Spot pairs from sapi ticker/24hr + exchangeInfo; TEST* junk filtered. |
| 7 | funding_overview | funding_overview(limit=20, sort="rate") | All ~730 rates from premiumIndex + fundingInfo: mixed 1/2/4/8h intervals (flagged), cap/floor, interestRate, nextFundingTime. |
| 8 | tradfi_markets | tradfi_markets(limit=20, window=None) | TradFi-perp screener by asset class (metals/equity/energy/treasuries/forex) + tradfi_crypto_corr sub-block: local TradFi-vs-BTC correlation from klines. |
| 9 | funding_screener | funding_screener(top=10, direction="both") | One-call ranking by annualized funding, premium, mark-index spread + funding_regime headroom to cap/floor. |
| 10 | oi_snapshot | oi_snapshot(symbols=None, top=10) | Per-symbol openInterest (max 10 symbols/call). No keyless OI history (404) - stated honestly. |
| 11 | deposit_flows | deposit_flows(chain_filter="all", limit=20) | Solana vault signatures (keyless) + EVM vault Transfers when ASTER_EVM_RPC_URL* set + deposit_stats hourly/chain buckets. |
| 12 | account_view | account_view(address, data="balance") | tapi aster_getBalance/openOrders/userFills keyless for any address; privacy-empty returns an honest error dict explaining why. |
| 13 | mark_index_divergence | mark_index_divergence(limit=20) | mark vs index spread screener from ONE premiumIndex call + markPriceKlines-vs-klines crosscheck on the top 3. |
Why a gateway and not the raw API?
Aster's fapi/sapi/tapi endpoints are plain REST — the traps are in the semantics:
| per-market funding intervals that differ (1h to 8h) | correct annualization per symbol — a naive ×24×365 overstates 8h markets by 8× |
| funding cap/floor fields under live vs legacy names | name negotiation with fallback (this gateway reads fundingFeeCap/FundingFeeFloor and degrades honestly) |
| ~580 symbols mixing crypto, TradFi 24/7 perps and spot | chain/asset-class filtering, spot index dislocation ranking, capacity filtering where OI is not published |
| three separate API surfaces (futures/spot/tapi) + Solana | one tool surface with consistent symbol handling and per-field source tags |
Rate limits
Two REST buckets, locally enforced and weight-aware:
- fapi 2400 weight/min, sapi 6000/min (header
X-MBX-USED-WEIGHT-1M read after every call). Above 80% of a
bucket the client self-throttles; 429 backs off honoring
Retry-After; a 418 (repeated 429 = IP ban) triggers a 60s refusal
cooldown. Depth/kline limits snap to priced tiers so callers cannot
accidentally burn weight.
- Solana 10 req/min, tapi 30/min, EVM 20/min local budgets
(separate ledgers, fail-fast honest errors).
TTL caches: exchangeInfo 3600s, fundingInfo 600s, premiumIndex and
tickers 15s, depth 5s, klines 60s, trades 10s, openInterest 30s.
Data notes
- Every numeric from the API is a STRING upstream; parsed with a
never-raising helper -
null always means "not available", never
zero.
- Every upstream failure returns an error dict
{"error", "source", "reason"}, never a traceback.
- No OI history exists keyless (
/futures/data/openInterestHist
404s) - the gateway says so instead of inventing data.
- EVM vault logs need
ASTER_EVM_RPC_URL (or per-chain
ASTER_EVM_RPC_URL_{BSC,ETH,ARB}); free public RPCs reject vault
queries with -32005. Unset -> honest "no RPC configured".
- tapi account privacy: most accounts are private; empty results
are reported as privacy, not as data.
- Cached responses carry
age_seconds / fetched_at freshness
fields.
Part of the suite
Four sibling read-only MCP gateways, one style — keyless, cached, honest degradation:
| dydx-agent-gateway | dYdX v4: verified trader PnL, funding/OI anomaly detectors, leaderboard |
| arcus-agent-gateway | 194 tokenized US equities on Robinhood Chain: quotes, holders, whale transfers |
| hyperliquid-agent-gateway | Hyperliquid: 233 perps + spot, funding carry, account risk, HyperEVM |
| aster-agent-gateway (you are here) | Aster DEX: ~580 futures incl. 24/7 TradFi perps, funding caps/floors |
All four are on glama.ai and PyPI — install any of them with uvx <name>.
License
MIT.