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.
Files changed (40) hide show
  1. aster_agent_gateway-0.1.0/.github/workflows/release.yml +26 -0
  2. aster_agent_gateway-0.1.0/.github/workflows/tests.yml +27 -0
  3. aster_agent_gateway-0.1.0/.gitignore +7 -0
  4. aster_agent_gateway-0.1.0/CHANGELOG.md +26 -0
  5. aster_agent_gateway-0.1.0/LICENSE +21 -0
  6. aster_agent_gateway-0.1.0/PKG-INFO +189 -0
  7. aster_agent_gateway-0.1.0/README.md +162 -0
  8. aster_agent_gateway-0.1.0/aster_mcp/API_NOTES.md +99 -0
  9. aster_agent_gateway-0.1.0/aster_mcp/__init__.py +14 -0
  10. aster_agent_gateway-0.1.0/aster_mcp/chain.py +287 -0
  11. aster_agent_gateway-0.1.0/aster_mcp/rest.py +438 -0
  12. aster_agent_gateway-0.1.0/aster_mcp/server.py +1171 -0
  13. aster_agent_gateway-0.1.0/deploy/aster-recorder.service +15 -0
  14. aster_agent_gateway-0.1.0/deploy/aster-recorder.timer +15 -0
  15. aster_agent_gateway-0.1.0/pyproject.toml +43 -0
  16. aster_agent_gateway-0.1.0/scripts/recorder.py +94 -0
  17. aster_agent_gateway-0.1.0/scripts/smoke_live.py +245 -0
  18. aster_agent_gateway-0.1.0/scripts/smoke_offline.py +137 -0
  19. aster_agent_gateway-0.1.0/tests/conftest.py +137 -0
  20. aster_agent_gateway-0.1.0/tests/fixtures/fapi_depth_btcusdt.json +184 -0
  21. aster_agent_gateway-0.1.0/tests/fixtures/fapi_exchangeInfo.json +51974 -0
  22. aster_agent_gateway-0.1.0/tests/fixtures/fapi_fundingInfo_all.json +93 -0
  23. aster_agent_gateway-0.1.0/tests/fixtures/fapi_indexPriceKlines_btcusdt_1h.json +314 -0
  24. aster_agent_gateway-0.1.0/tests/fixtures/fapi_klines_btcusdt_1h.json +314 -0
  25. aster_agent_gateway-0.1.0/tests/fixtures/fapi_markPriceKlines_btcusdt_1h.json +314 -0
  26. aster_agent_gateway-0.1.0/tests/fixtures/fapi_openInterest_btcusdt.json +5 -0
  27. aster_agent_gateway-0.1.0/tests/fixtures/fapi_premiumIndex_all.json +7312 -0
  28. aster_agent_gateway-0.1.0/tests/fixtures/fapi_ticker24hr_all.json +10406 -0
  29. aster_agent_gateway-0.1.0/tests/fixtures/fapi_trades_btcusdt.json +162 -0
  30. aster_agent_gateway-0.1.0/tests/fixtures/sapi_depth_btcusdt.json +90 -0
  31. aster_agent_gateway-0.1.0/tests/fixtures/sapi_exchangeInfo.json +50 -0
  32. aster_agent_gateway-0.1.0/tests/fixtures/sapi_klines_btcusdt.json +338 -0
  33. aster_agent_gateway-0.1.0/tests/fixtures/sapi_ticker24hr_all.json +20 -0
  34. aster_agent_gateway-0.1.0/tests/fixtures/sapi_trades_btcusdt.json +162 -0
  35. aster_agent_gateway-0.1.0/tests/fixtures/solana_vault_signatures.json +182 -0
  36. aster_agent_gateway-0.1.0/tests/fixtures/tapi_getBalance_public.json +15 -0
  37. aster_agent_gateway-0.1.0/tests/fixtures/tapi_getBalance_vault.json +4 -0
  38. aster_agent_gateway-0.1.0/tests/test_chain.py +170 -0
  39. aster_agent_gateway-0.1.0/tests/test_rest.py +227 -0
  40. 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,7 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ *.log
5
+ .coverage
6
+ .pytest_cache/
7
+ uv.lock
@@ -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
+ [![CI](https://github.com/alekskram/aster-agent-gateway/actions/workflows/tests.yml/badge.svg)](https://github.com/alekskram/aster-agent-gateway/actions/workflows/tests.yml)
31
+ [![PyPI](https://img.shields.io/pypi/v/aster-agent-gateway.svg)](https://pypi.org/project/aster-agent-gateway/)
32
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
33
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](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
+ [![CI](https://github.com/alekskram/aster-agent-gateway/actions/workflows/tests.yml/badge.svg)](https://github.com/alekskram/aster-agent-gateway/actions/workflows/tests.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/aster-agent-gateway.svg)](https://pypi.org/project/aster-agent-gateway/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](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"