aster-agent-gateway 0.1.0__tar.gz
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.
- aster_agent_gateway-0.1.0/.github/workflows/release.yml +26 -0
- aster_agent_gateway-0.1.0/.github/workflows/tests.yml +27 -0
- aster_agent_gateway-0.1.0/.gitignore +7 -0
- aster_agent_gateway-0.1.0/CHANGELOG.md +26 -0
- aster_agent_gateway-0.1.0/LICENSE +21 -0
- aster_agent_gateway-0.1.0/PKG-INFO +189 -0
- aster_agent_gateway-0.1.0/README.md +162 -0
- aster_agent_gateway-0.1.0/aster_mcp/API_NOTES.md +99 -0
- aster_agent_gateway-0.1.0/aster_mcp/__init__.py +14 -0
- aster_agent_gateway-0.1.0/aster_mcp/chain.py +287 -0
- aster_agent_gateway-0.1.0/aster_mcp/rest.py +438 -0
- aster_agent_gateway-0.1.0/aster_mcp/server.py +1171 -0
- aster_agent_gateway-0.1.0/deploy/aster-recorder.service +15 -0
- aster_agent_gateway-0.1.0/deploy/aster-recorder.timer +15 -0
- aster_agent_gateway-0.1.0/pyproject.toml +43 -0
- aster_agent_gateway-0.1.0/scripts/recorder.py +94 -0
- aster_agent_gateway-0.1.0/scripts/smoke_live.py +245 -0
- aster_agent_gateway-0.1.0/scripts/smoke_offline.py +137 -0
- aster_agent_gateway-0.1.0/tests/conftest.py +137 -0
- aster_agent_gateway-0.1.0/tests/fixtures/fapi_depth_btcusdt.json +184 -0
- aster_agent_gateway-0.1.0/tests/fixtures/fapi_exchangeInfo.json +51974 -0
- aster_agent_gateway-0.1.0/tests/fixtures/fapi_fundingInfo_all.json +93 -0
- aster_agent_gateway-0.1.0/tests/fixtures/fapi_indexPriceKlines_btcusdt_1h.json +314 -0
- aster_agent_gateway-0.1.0/tests/fixtures/fapi_klines_btcusdt_1h.json +314 -0
- aster_agent_gateway-0.1.0/tests/fixtures/fapi_markPriceKlines_btcusdt_1h.json +314 -0
- aster_agent_gateway-0.1.0/tests/fixtures/fapi_openInterest_btcusdt.json +5 -0
- aster_agent_gateway-0.1.0/tests/fixtures/fapi_premiumIndex_all.json +7312 -0
- aster_agent_gateway-0.1.0/tests/fixtures/fapi_ticker24hr_all.json +10406 -0
- aster_agent_gateway-0.1.0/tests/fixtures/fapi_trades_btcusdt.json +162 -0
- aster_agent_gateway-0.1.0/tests/fixtures/sapi_depth_btcusdt.json +90 -0
- aster_agent_gateway-0.1.0/tests/fixtures/sapi_exchangeInfo.json +50 -0
- aster_agent_gateway-0.1.0/tests/fixtures/sapi_klines_btcusdt.json +338 -0
- aster_agent_gateway-0.1.0/tests/fixtures/sapi_ticker24hr_all.json +20 -0
- aster_agent_gateway-0.1.0/tests/fixtures/sapi_trades_btcusdt.json +162 -0
- aster_agent_gateway-0.1.0/tests/fixtures/solana_vault_signatures.json +182 -0
- aster_agent_gateway-0.1.0/tests/fixtures/tapi_getBalance_public.json +15 -0
- aster_agent_gateway-0.1.0/tests/fixtures/tapi_getBalance_vault.json +4 -0
- aster_agent_gateway-0.1.0/tests/test_chain.py +170 -0
- aster_agent_gateway-0.1.0/tests/test_rest.py +227 -0
- aster_agent_gateway-0.1.0/tests/test_server.py +750 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write
|
|
12
|
+
contents: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v5
|
|
15
|
+
- uses: actions/setup-python@v6
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.13"
|
|
18
|
+
- run: pip install build twine
|
|
19
|
+
- run: python -m build
|
|
20
|
+
- run: python -m twine check dist/*
|
|
21
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
22
|
+
- name: GitHub Release
|
|
23
|
+
uses: softprops/action-gh-release@v2
|
|
24
|
+
with:
|
|
25
|
+
files: dist/*
|
|
26
|
+
generate_release_notes: true
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
offline:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python: ["3.11", "3.13"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v5
|
|
16
|
+
- uses: actions/setup-python@v6
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python }}
|
|
19
|
+
- run: pip install -e ".[dev]"
|
|
20
|
+
- name: Run tests
|
|
21
|
+
run: |
|
|
22
|
+
pytest tests/ -q --cov=aster_mcp --tb=short > pytest_output.txt 2>&1 || FAILED=1
|
|
23
|
+
grep -E "^(FAILED|ERROR)|Error|error" pytest_output.txt | head -25 | while IFS= read -r line; do
|
|
24
|
+
echo "::error::${line:0:250}"
|
|
25
|
+
done
|
|
26
|
+
tail -40 pytest_output.txt
|
|
27
|
+
exit ${FAILED:-0}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-09-06)
|
|
4
|
+
|
|
5
|
+
Initial release.
|
|
6
|
+
|
|
7
|
+
- Read-only, keyless MCP gateway to Aster DEX public data.
|
|
8
|
+
- REST client (`aster_mcp/rest.py`): weight-aware (reads
|
|
9
|
+
`X-MBX-USED-WEIGHT-1M`, self-throttles at 80% of 2400/min fapi and
|
|
10
|
+
6000/min sapi, 429 backoff honoring Retry-After, 418 IP-ban cooldown),
|
|
11
|
+
per-endpoint TTL caches, weight-aware depth/kline limit snapping.
|
|
12
|
+
- On-chain client (`aster_mcp/chain.py`): tapi Aster Chain JSON-RPC
|
|
13
|
+
(privacy-aware account views), Solana vault signatures, EVM vault
|
|
14
|
+
Transfer logs gated on `ASTER_EVM_RPC_URL*` env (honest
|
|
15
|
+
"no RPC configured" when unset).
|
|
16
|
+
- 13 MCP tools (`aster_mcp/server.py`): market_overview,
|
|
17
|
+
exchange_symbols, order_book, klines, trades, spot_overview,
|
|
18
|
+
funding_overview, tradfi_markets (with tradfi_crypto_corr),
|
|
19
|
+
funding_screener (with funding_regime headroom), oi_snapshot,
|
|
20
|
+
deposit_flows (with deposit_stats), account_view,
|
|
21
|
+
mark_index_divergence - all annotated read-only with honest
|
|
22
|
+
degradation (error dicts, never tracebacks) and freshness fields.
|
|
23
|
+
- Offline test suite on schema-realistic fixtures (fixtures refreshed
|
|
24
|
+
from live captures by `scripts/smoke_live.py`, budget 10 calls).
|
|
25
|
+
- `scripts/recorder.py` live-fixture recorder + systemd deploy units
|
|
26
|
+
(6h schedule, disabled by default).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 aster-agent-gateway contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: aster-agent-gateway
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP gateway for AI agents to Aster DEX public data: futures and spot market overviews, order books, klines, funding and TradFi-perp screeners, vault deposit flows, public account views. Read-only, keyless.
|
|
5
|
+
Project-URL: Homepage, https://github.com/alekskram/aster-agent-gateway
|
|
6
|
+
Project-URL: Repository, https://github.com/alekskram/aster-agent-gateway
|
|
7
|
+
Project-URL: Issues, https://github.com/alekskram/aster-agent-gateway/issues
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: ai-agents,aster,asterdex,defi,funding,mcp,perps
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: fastmcp>=3.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: hatchling; extra == 'dev'
|
|
23
|
+
Requires-Dist: pip-audit; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# aster-agent-gateway
|
|
29
|
+
|
|
30
|
+
[](https://github.com/alekskram/aster-agent-gateway/actions/workflows/tests.yml)
|
|
31
|
+
[](https://pypi.org/project/aster-agent-gateway/)
|
|
32
|
+
[](LICENSE)
|
|
33
|
+
[](pyproject.toml)
|
|
34
|
+
|
|
35
|
+
An MCP (Model Context Protocol) server that gives AI agents read-only,
|
|
36
|
+
keyless access to **Aster DEX** public data - ~580 futures symbols
|
|
37
|
+
(including 24/7 TradFi perps: metals, equity indices, energy,
|
|
38
|
+
treasuries), ~68 spot pairs, funding, order books, klines, vault
|
|
39
|
+
deposit flows and tapi account views. No API keys, no auth, no
|
|
40
|
+
signing, no writes: every tool reads public endpoints only
|
|
41
|
+
(`fapi.asterdex.com/fapi/v3`, `sapi.asterdex.com/api/v3`,
|
|
42
|
+
`tapi.asterdex.com/info`, `api.mainnet-beta.solana.com`, plus optional
|
|
43
|
+
EVM RPCs), cached and rate-limited so an enthusiastic agent cannot
|
|
44
|
+
hammer the upstream.
|
|
45
|
+
|
|
46
|
+
## Use cases
|
|
47
|
+
|
|
48
|
+
- **Screen 731 funding rates in one call** — ranked by annualized rate with funding regime and mark/index spread; the 793% outliers are visible instantly
|
|
49
|
+
- **Trade TradFi 24/7** — metals, equity indices, energy, treasuries perps next to crypto, one consistent API
|
|
50
|
+
- **Follow the vault money** — deposit flows per vault: who is parking capital where
|
|
51
|
+
- **Spot index dislocations** — mark vs index divergence ranking across the whole board
|
|
52
|
+
- **Morning scan** — market overview + funding overview + OI snapshot, three cheap calls
|
|
53
|
+
|
|
54
|
+
Full walkthroughs: [examples/use-cases.md](examples/use-cases.md).
|
|
55
|
+
|
|
56
|
+
## Quickstart
|
|
57
|
+
|
|
58
|
+
stdio (default, for local agents):
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
uvx aster-agent-gateway
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
or from a checkout:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/alekskram/aster-agent-gateway
|
|
68
|
+
cd aster-agent-gateway
|
|
69
|
+
uv sync
|
|
70
|
+
uv run aster-agent-gateway
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Claude Desktop / Cursor config:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"mcpServers": {
|
|
78
|
+
"aster": {
|
|
79
|
+
"command": "uvx",
|
|
80
|
+
"args": ["--from",
|
|
81
|
+
"git+https://github.com/alekskram/aster-agent-gateway",
|
|
82
|
+
"aster-agent-gateway"]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Hosted form - streamable HTTP on port **8904**:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
uv run aster-agent-gateway --http # 127.0.0.1:8904
|
|
92
|
+
curl http://127.0.0.1:8904/health # -> {"ok": true, "service": "aster-agent-gateway", ...}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
<details>
|
|
96
|
+
<summary><b>Codex</b> (~/.codex/config.toml)</summary>
|
|
97
|
+
|
|
98
|
+
```toml
|
|
99
|
+
[mcp_servers.aster]
|
|
100
|
+
command = "uvx"
|
|
101
|
+
args = ["aster-agent-gateway"]
|
|
102
|
+
```
|
|
103
|
+
</details>
|
|
104
|
+
|
|
105
|
+
<details>
|
|
106
|
+
<summary><b>ZCode</b> — register the server (copy-paste)</summary>
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# 1) start the gateway (keep it running)
|
|
110
|
+
uvx aster-agent-gateway --http --port 8904 &
|
|
111
|
+
|
|
112
|
+
# 2) register it (merges into ~/.zcode/cli/config.json)
|
|
113
|
+
python3 - <<'PY'
|
|
114
|
+
import json, os
|
|
115
|
+
p = os.path.expanduser("~/.zcode/cli/config.json")
|
|
116
|
+
os.makedirs(os.path.dirname(p), exist_ok=True)
|
|
117
|
+
cfg = json.load(open(p)) if os.path.exists(p) else {}
|
|
118
|
+
cfg.setdefault("mcp", {}).setdefault("servers", {})["aster"] = {
|
|
119
|
+
"type": "http", "url": "http://127.0.0.1:8904/mcp"}
|
|
120
|
+
json.dump(cfg, open(p, "w"), indent=2)
|
|
121
|
+
print("aster-agent-gateway registered:", p)
|
|
122
|
+
PY
|
|
123
|
+
```
|
|
124
|
+
</details>
|
|
125
|
+
|
|
126
|
+
Hosted form — streamable HTTP on port **8904**:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
uvx aster-agent-gateway --http
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Tools
|
|
133
|
+
|
|
134
|
+
All 13 tools are read-only (annotated `readOnlyHint: true,
|
|
135
|
+
destructiveHint: false`).
|
|
136
|
+
|
|
137
|
+
| # | Tool | Signature | What it does |
|
|
138
|
+
|---|------|-----------|--------------|
|
|
139
|
+
| 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). |
|
|
140
|
+
| 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. |
|
|
141
|
+
| 3 | `order_book` | `order_book(symbol, venue="futures", depth=10)` | fapi depth / sapi api/v3 depth; limit snapped to a priced tier (weight-aware). |
|
|
142
|
+
| 4 | `klines` | `klines(symbol, interval="1h", limit=100, market="futures", price_type="last")` | last/mark/index klines on fapi; spot via sapi. |
|
|
143
|
+
| 5 | `trades` | `trades(symbol, limit=20, venue="futures")` | Fresh keyless trades; spot path probed live (honest error dict if dead). |
|
|
144
|
+
| 6 | `spot_overview` | `spot_overview(limit=20)` | Spot pairs from sapi ticker/24hr + exchangeInfo; TEST* junk filtered. |
|
|
145
|
+
| 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. |
|
|
146
|
+
| 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. |
|
|
147
|
+
| 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. |
|
|
148
|
+
| 10 | `oi_snapshot` | `oi_snapshot(symbols=None, top=10)` | Per-symbol openInterest (max 10 symbols/call). No keyless OI history (404) - stated honestly. |
|
|
149
|
+
| 11 | `deposit_flows` | `deposit_flows(chain="all", limit=20)` | Solana vault signatures (keyless) + EVM vault Transfers when `ASTER_EVM_RPC_URL*` set + `deposit_stats` hourly/chain buckets. |
|
|
150
|
+
| 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. |
|
|
151
|
+
| 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. |
|
|
152
|
+
|
|
153
|
+
## Rate limits
|
|
154
|
+
|
|
155
|
+
Two REST buckets, locally enforced and weight-aware:
|
|
156
|
+
|
|
157
|
+
- **fapi 2400 weight/min**, **sapi 6000/min** (header
|
|
158
|
+
`X-MBX-USED-WEIGHT-1M` read after every call). Above 80% of a
|
|
159
|
+
bucket the client self-throttles; 429 backs off honoring
|
|
160
|
+
`Retry-After`; a 418 (repeated 429 = IP ban) triggers a 60s refusal
|
|
161
|
+
cooldown. Depth/kline limits snap to priced tiers so callers cannot
|
|
162
|
+
accidentally burn weight.
|
|
163
|
+
- **Solana 10 req/min, tapi 30/min, EVM 20/min** local budgets
|
|
164
|
+
(separate ledgers, fail-fast honest errors).
|
|
165
|
+
|
|
166
|
+
TTL caches: exchangeInfo 3600s, fundingInfo 600s, premiumIndex and
|
|
167
|
+
tickers 15s, depth 5s, klines 60s, trades 10s, openInterest 30s.
|
|
168
|
+
|
|
169
|
+
## Data notes
|
|
170
|
+
|
|
171
|
+
- Every numeric from the API is a STRING upstream; parsed with a
|
|
172
|
+
never-raising helper - `null` always means "not available", never
|
|
173
|
+
zero.
|
|
174
|
+
- Every upstream failure returns an error dict
|
|
175
|
+
`{"error", "source", "reason"}`, never a traceback.
|
|
176
|
+
- **No OI history exists keyless** (`/futures/data/openInterestHist`
|
|
177
|
+
404s) - the gateway says so instead of inventing data.
|
|
178
|
+
- **EVM vault logs** need `ASTER_EVM_RPC_URL` (or per-chain
|
|
179
|
+
`ASTER_EVM_RPC_URL_{BSC,ETH,ARB}`); free public RPCs reject vault
|
|
180
|
+
queries with -32005. Unset -> honest "no RPC configured".
|
|
181
|
+
- **tapi account privacy**: most accounts are private; empty results
|
|
182
|
+
are reported as privacy, not as data.
|
|
183
|
+
- Cached responses carry `age_seconds` / `fetched_at` freshness
|
|
184
|
+
fields.
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# aster-agent-gateway
|
|
2
|
+
|
|
3
|
+
[](https://github.com/alekskram/aster-agent-gateway/actions/workflows/tests.yml)
|
|
4
|
+
[](https://pypi.org/project/aster-agent-gateway/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](pyproject.toml)
|
|
7
|
+
|
|
8
|
+
An MCP (Model Context Protocol) server that gives AI agents read-only,
|
|
9
|
+
keyless access to **Aster DEX** public data - ~580 futures symbols
|
|
10
|
+
(including 24/7 TradFi perps: metals, equity indices, energy,
|
|
11
|
+
treasuries), ~68 spot pairs, funding, order books, klines, vault
|
|
12
|
+
deposit flows and tapi account views. No API keys, no auth, no
|
|
13
|
+
signing, no writes: every tool reads public endpoints only
|
|
14
|
+
(`fapi.asterdex.com/fapi/v3`, `sapi.asterdex.com/api/v3`,
|
|
15
|
+
`tapi.asterdex.com/info`, `api.mainnet-beta.solana.com`, plus optional
|
|
16
|
+
EVM RPCs), cached and rate-limited so an enthusiastic agent cannot
|
|
17
|
+
hammer the upstream.
|
|
18
|
+
|
|
19
|
+
## Use cases
|
|
20
|
+
|
|
21
|
+
- **Screen 731 funding rates in one call** — ranked by annualized rate with funding regime and mark/index spread; the 793% outliers are visible instantly
|
|
22
|
+
- **Trade TradFi 24/7** — metals, equity indices, energy, treasuries perps next to crypto, one consistent API
|
|
23
|
+
- **Follow the vault money** — deposit flows per vault: who is parking capital where
|
|
24
|
+
- **Spot index dislocations** — mark vs index divergence ranking across the whole board
|
|
25
|
+
- **Morning scan** — market overview + funding overview + OI snapshot, three cheap calls
|
|
26
|
+
|
|
27
|
+
Full walkthroughs: [examples/use-cases.md](examples/use-cases.md).
|
|
28
|
+
|
|
29
|
+
## Quickstart
|
|
30
|
+
|
|
31
|
+
stdio (default, for local agents):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
uvx aster-agent-gateway
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
or from a checkout:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/alekskram/aster-agent-gateway
|
|
41
|
+
cd aster-agent-gateway
|
|
42
|
+
uv sync
|
|
43
|
+
uv run aster-agent-gateway
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Claude Desktop / Cursor config:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"mcpServers": {
|
|
51
|
+
"aster": {
|
|
52
|
+
"command": "uvx",
|
|
53
|
+
"args": ["--from",
|
|
54
|
+
"git+https://github.com/alekskram/aster-agent-gateway",
|
|
55
|
+
"aster-agent-gateway"]
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Hosted form - streamable HTTP on port **8904**:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
uv run aster-agent-gateway --http # 127.0.0.1:8904
|
|
65
|
+
curl http://127.0.0.1:8904/health # -> {"ok": true, "service": "aster-agent-gateway", ...}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
<details>
|
|
69
|
+
<summary><b>Codex</b> (~/.codex/config.toml)</summary>
|
|
70
|
+
|
|
71
|
+
```toml
|
|
72
|
+
[mcp_servers.aster]
|
|
73
|
+
command = "uvx"
|
|
74
|
+
args = ["aster-agent-gateway"]
|
|
75
|
+
```
|
|
76
|
+
</details>
|
|
77
|
+
|
|
78
|
+
<details>
|
|
79
|
+
<summary><b>ZCode</b> — register the server (copy-paste)</summary>
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# 1) start the gateway (keep it running)
|
|
83
|
+
uvx aster-agent-gateway --http --port 8904 &
|
|
84
|
+
|
|
85
|
+
# 2) register it (merges into ~/.zcode/cli/config.json)
|
|
86
|
+
python3 - <<'PY'
|
|
87
|
+
import json, os
|
|
88
|
+
p = os.path.expanduser("~/.zcode/cli/config.json")
|
|
89
|
+
os.makedirs(os.path.dirname(p), exist_ok=True)
|
|
90
|
+
cfg = json.load(open(p)) if os.path.exists(p) else {}
|
|
91
|
+
cfg.setdefault("mcp", {}).setdefault("servers", {})["aster"] = {
|
|
92
|
+
"type": "http", "url": "http://127.0.0.1:8904/mcp"}
|
|
93
|
+
json.dump(cfg, open(p, "w"), indent=2)
|
|
94
|
+
print("aster-agent-gateway registered:", p)
|
|
95
|
+
PY
|
|
96
|
+
```
|
|
97
|
+
</details>
|
|
98
|
+
|
|
99
|
+
Hosted form — streamable HTTP on port **8904**:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
uvx aster-agent-gateway --http
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Tools
|
|
106
|
+
|
|
107
|
+
All 13 tools are read-only (annotated `readOnlyHint: true,
|
|
108
|
+
destructiveHint: false`).
|
|
109
|
+
|
|
110
|
+
| # | Tool | Signature | What it does |
|
|
111
|
+
|---|------|-----------|--------------|
|
|
112
|
+
| 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). |
|
|
113
|
+
| 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. |
|
|
114
|
+
| 3 | `order_book` | `order_book(symbol, venue="futures", depth=10)` | fapi depth / sapi api/v3 depth; limit snapped to a priced tier (weight-aware). |
|
|
115
|
+
| 4 | `klines` | `klines(symbol, interval="1h", limit=100, market="futures", price_type="last")` | last/mark/index klines on fapi; spot via sapi. |
|
|
116
|
+
| 5 | `trades` | `trades(symbol, limit=20, venue="futures")` | Fresh keyless trades; spot path probed live (honest error dict if dead). |
|
|
117
|
+
| 6 | `spot_overview` | `spot_overview(limit=20)` | Spot pairs from sapi ticker/24hr + exchangeInfo; TEST* junk filtered. |
|
|
118
|
+
| 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. |
|
|
119
|
+
| 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. |
|
|
120
|
+
| 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. |
|
|
121
|
+
| 10 | `oi_snapshot` | `oi_snapshot(symbols=None, top=10)` | Per-symbol openInterest (max 10 symbols/call). No keyless OI history (404) - stated honestly. |
|
|
122
|
+
| 11 | `deposit_flows` | `deposit_flows(chain="all", limit=20)` | Solana vault signatures (keyless) + EVM vault Transfers when `ASTER_EVM_RPC_URL*` set + `deposit_stats` hourly/chain buckets. |
|
|
123
|
+
| 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. |
|
|
124
|
+
| 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. |
|
|
125
|
+
|
|
126
|
+
## Rate limits
|
|
127
|
+
|
|
128
|
+
Two REST buckets, locally enforced and weight-aware:
|
|
129
|
+
|
|
130
|
+
- **fapi 2400 weight/min**, **sapi 6000/min** (header
|
|
131
|
+
`X-MBX-USED-WEIGHT-1M` read after every call). Above 80% of a
|
|
132
|
+
bucket the client self-throttles; 429 backs off honoring
|
|
133
|
+
`Retry-After`; a 418 (repeated 429 = IP ban) triggers a 60s refusal
|
|
134
|
+
cooldown. Depth/kline limits snap to priced tiers so callers cannot
|
|
135
|
+
accidentally burn weight.
|
|
136
|
+
- **Solana 10 req/min, tapi 30/min, EVM 20/min** local budgets
|
|
137
|
+
(separate ledgers, fail-fast honest errors).
|
|
138
|
+
|
|
139
|
+
TTL caches: exchangeInfo 3600s, fundingInfo 600s, premiumIndex and
|
|
140
|
+
tickers 15s, depth 5s, klines 60s, trades 10s, openInterest 30s.
|
|
141
|
+
|
|
142
|
+
## Data notes
|
|
143
|
+
|
|
144
|
+
- Every numeric from the API is a STRING upstream; parsed with a
|
|
145
|
+
never-raising helper - `null` always means "not available", never
|
|
146
|
+
zero.
|
|
147
|
+
- Every upstream failure returns an error dict
|
|
148
|
+
`{"error", "source", "reason"}`, never a traceback.
|
|
149
|
+
- **No OI history exists keyless** (`/futures/data/openInterestHist`
|
|
150
|
+
404s) - the gateway says so instead of inventing data.
|
|
151
|
+
- **EVM vault logs** need `ASTER_EVM_RPC_URL` (or per-chain
|
|
152
|
+
`ASTER_EVM_RPC_URL_{BSC,ETH,ARB}`); free public RPCs reject vault
|
|
153
|
+
queries with -32005. Unset -> honest "no RPC configured".
|
|
154
|
+
- **tapi account privacy**: most accounts are private; empty results
|
|
155
|
+
are reported as privacy, not as data.
|
|
156
|
+
- Cached responses carry `age_seconds` / `fetched_at` freshness
|
|
157
|
+
fields.
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# API notes - Aster public surfaces (as verified 2026-09-05/06)
|
|
2
|
+
|
|
3
|
+
Facts the gateway depends on. Every claim below was checked against the
|
|
4
|
+
live endpoints before v0.1.0 was coded; fixtures in `tests/fixtures/`
|
|
5
|
+
mirror these shapes.
|
|
6
|
+
|
|
7
|
+
## fapi - futures (https://fapi.asterdex.com/fapi/v3/*)
|
|
8
|
+
|
|
9
|
+
- Binance-compatible v3 REST, keyless for market data. ALL numerics
|
|
10
|
+
arrive as STRINGS ("0.0001"); parse with a never-raising `_f()`.
|
|
11
|
+
- **Rate limits: weight-based per IP, 2400 weight/min** on fapi
|
|
12
|
+
(header `X-MBX-USED-WEIGHT-1M` on every response). 429 -> backoff
|
|
13
|
+
honoring `Retry-After`; repeated 429 -> **418 IP ban** (the client
|
|
14
|
+
cools down 60s and refuses calls).
|
|
15
|
+
- `exchangeInfo` (weight 1): ~580 symbols; statuses ~559 TRADING /
|
|
16
|
+
15 SETTLING / 6 PENDING; quotes USDT 568 / USD1 10; symbol rows
|
|
17
|
+
carry `onboardDate`, `contractType`, `status`, `filters`
|
|
18
|
+
(PRICE_FILTER tickSize, LOT_SIZE stepSize, MIN_NOTIONAL,
|
|
19
|
+
LEVERAGE_FILTER).
|
|
20
|
+
- `ticker/24hr` with NO symbol param (weight ~40): ALL ~574 rows in
|
|
21
|
+
ONE call - symbol, lastPrice, priceChangePercent, quoteVolume,
|
|
22
|
+
volume, highPrice, lowPrice, weightedAvgPrice, count.
|
|
23
|
+
- `premiumIndex` no param (weight ~10): ALL ~730 rows - symbol,
|
|
24
|
+
markPrice, indexPrice, lastFundingRate, nextFundingTime,
|
|
25
|
+
interestRate.
|
|
26
|
+
- `fundingInfo` (weight 1): ~730 rows - fundingIntervalHours MIXED
|
|
27
|
+
(1/2/4/8h histogram ~351/3/103/273), cap 0.003-0.03, floor -0.03,
|
|
28
|
+
interestRate.
|
|
29
|
+
- `depth?symbol=&limit=` - weight by limit: 5/10/20/50 = 2, 100 = 5,
|
|
30
|
+
500 = 10, 1000 = 20 (client snaps requests down to a priced tier).
|
|
31
|
+
- `klines` / `markPriceKlines` / `indexPriceKlines` -
|
|
32
|
+
`?symbol=&interval=&limit=`; weight 1 (limit<=100) .. 5.
|
|
33
|
+
- `/trades?symbol=` - fresh keyless trades.
|
|
34
|
+
- `openInterest?symbol=` - per-symbol snapshot ONLY (weight 1).
|
|
35
|
+
**`/futures/data/openInterestHist` returns 404** - no keyless OI
|
|
36
|
+
history exists; the gateway says so instead of inventing data.
|
|
37
|
+
|
|
38
|
+
## sapi - spot (https://sapi.asterdex.com/api/v3/*)
|
|
39
|
+
|
|
40
|
+
- MIGRATION note: the old `/sapi/v1/*` paths **404**; live base is
|
|
41
|
+
`/api/v3/*`.
|
|
42
|
+
- Rate limit 6000 weight/min (separate bucket; same header).
|
|
43
|
+
- `exchangeInfo`: 68 TRADING pairs plus TEST*-named junk symbols -
|
|
44
|
+
filtered by name in this gateway (flag to include).
|
|
45
|
+
- `klines`, `depth`: live 200, keyless.
|
|
46
|
+
- Spot `/trades`: path was uncertain at recon; probed in the smoke
|
|
47
|
+
script - if it 404s the tool degrades to an honest error dict.
|
|
48
|
+
|
|
49
|
+
## tapi - Aster Chain JSON-RPC (https://tapi.asterdex.com/info)
|
|
50
|
+
|
|
51
|
+
- Body `{"jsonrpc":"2.0","id":1,"method":"aster_getBalance","params":
|
|
52
|
+
["0x...", "latest"]}` (PARAMS IS AN ARRAY: address + blockTag; the
|
|
53
|
+
object form `{"userAddress": ...}` returns HTTP 400 - live-verified)
|
|
54
|
+
- answers KEYLESS, but **account privacy hides most accounts**:
|
|
55
|
+
private accounts return a result with only {address,
|
|
56
|
+
accountPrivacy: "enabled"} and no balances (observed on the BSC vault
|
|
57
|
+
address and a burn address). Empty = privacy, not an API failure -
|
|
58
|
+
the gateway returns an honest error-dict explaining why.
|
|
59
|
+
- `aster_openOrders` on a privacy-hidden account returns JSON-RPC
|
|
60
|
+
-32603 (internal error) - also mapped to the privacy degradation
|
|
61
|
+
path.
|
|
62
|
+
- Methods used (read-only): `aster_getBalance`, `aster_openOrders`,
|
|
63
|
+
`aster_userFills` (+ `aster_spotGetBalance` /
|
|
64
|
+
`aster_spotOpenOrders` / `aster_spotUserFills` variants).
|
|
65
|
+
- `eth_*` NOT supported (eth_chainId -> -32601 method not found): the
|
|
66
|
+
Aster Chain EVM-RPC is closed.
|
|
67
|
+
|
|
68
|
+
## Solana vault (https://api.mainnet-beta.solana.com)
|
|
69
|
+
|
|
70
|
+
- `getSignaturesForAddress` for the Aster vault program
|
|
71
|
+
`EhUtRgu9iEbZXXRpEvDj6n1wnQRjMi2SERDo3c6bmN2c` - live 200 keyless,
|
|
72
|
+
fresh signatures (signature / slot / blockTime / err). Treated
|
|
73
|
+
politely (10 req/min local cap) - it is a free public node.
|
|
74
|
+
|
|
75
|
+
## EVM vaults (BSC / ETH / ARB)
|
|
76
|
+
|
|
77
|
+
- Vaults: BSC `0x128463A60784c4D3f46c23Af3f65Ed859Ba87974`, ETH
|
|
78
|
+
`0x604DD02d620633Ae427888d41bfd15e38483736E`, ARB
|
|
79
|
+
`0x9E36CB86a159d479cEd94Fa05036f235Ac40E1d5`.
|
|
80
|
+
- Deposit flow = ERC-20 `Transfer` (topic0 `0xddf252ad...523b3ef`)
|
|
81
|
+
with `to` = vault, via `eth_getLogs`.
|
|
82
|
+
- Free public RPCs reject even 300-block windows with **-32005
|
|
83
|
+
(limit exceeded)**, so the RPC URL comes from env:
|
|
84
|
+
`ASTER_EVM_RPC_URL` (generic) or `ASTER_EVM_RPC_URL_{BSC,ETH,ARB}`
|
|
85
|
+
(per-chain). Unset -> honest `"no RPC configured"` error dict -
|
|
86
|
+
never a traceback, never invented logs.
|
|
87
|
+
|
|
88
|
+
## Endpoints NOT used, and why
|
|
89
|
+
|
|
90
|
+
- **`/futures/data/*` history endpoints** - 404 on Aster (only
|
|
91
|
+
openInterestHist was probed; the futures/data tree is absent).
|
|
92
|
+
- **WebSocket streams** (`fstream`/`sstream`) - deferred; the MCP
|
|
93
|
+
request/response model gains little from push feeds and the TTL
|
|
94
|
+
caches already cover freshness.
|
|
95
|
+
- **Signed/trading endpoints** - out of scope by design: this gateway
|
|
96
|
+
is strictly read-only and keyless; no API keys ever enter the
|
|
97
|
+
process.
|
|
98
|
+
- **aster-scan.com / asterscan.io explorers** - dead/unreachable at
|
|
99
|
+
recon time; not a dependency.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""aster_mcp - read-only, keyless MCP gateway to Aster DEX public data.
|
|
2
|
+
|
|
3
|
+
Package layout:
|
|
4
|
+
rest.py stdlib-only REST client for fapi.asterdex.com/fapi/v3
|
|
5
|
+
and sapi.asterdex.com/api/v3 (weight-aware, TTL caches)
|
|
6
|
+
chain.py stdlib-only clients for tapi (Aster Chain JSON-RPC),
|
|
7
|
+
Solana vault signatures and EVM vault Transfer logs
|
|
8
|
+
server.py FastMCP server wiring the 13 read-only tools
|
|
9
|
+
|
|
10
|
+
No API keys, no auth headers, no signing, no order placement - public
|
|
11
|
+
data only.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
__version__ = "0.1.0"
|