Skip to content

Commit 1ff80dd

Browse files
committed
Add Python unified parity and MCP server
1 parent 97fc33e commit 1ff80dd

13 files changed

Lines changed: 962 additions & 20 deletions
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Python SDK Unified Parity And MCP
2+
3+
This document tracks the Python SDK additions required to keep pace with the Hypernode unified-sidecar rollout completed on March 12, 2026.
4+
5+
## Added Unified Client Coverage
6+
7+
The Python `UnifiedStreamClient` now exposes the browser-safe Hypernode surfaces:
8+
9+
- `consensus_pulse()`
10+
- `all_mids(dex="")`
11+
- `l2_book(coin, dex="", depth=None)`
12+
- `asset_contexts(coin=None, dex="")`
13+
- `sse_all_mids(dex="", max_events=20)`
14+
- `sse_l2_book(coin, dex="", depth=None, max_events=20)`
15+
- `sse_asset_contexts(coin=None, dex="", max_events=20)`
16+
17+
These map to:
18+
19+
- `GET /api/v1/unified/consensus-pulse`
20+
- `GET /api/v1/unified/all-mids`
21+
- `GET /api/v1/unified/l2-book`
22+
- `GET /api/v1/unified/asset-contexts`
23+
- and their SSE `/stream` variants
24+
25+
## Added Status Client
26+
27+
The Python SDK now ships `StatusClient` for:
28+
29+
- `health()`
30+
- `public_status()`
31+
- `private_status()`
32+
- `admin_tokens()`
33+
34+
Private/admin calls use `HYPER_STATUS_TOKEN`.
35+
36+
## Added Python MCP
37+
38+
The SDK now ships a stdio MCP server and console entrypoint:
39+
40+
- module: `hypercore_sdk.mcp`
41+
- entrypoint: `hypercore-sdk-mcp`
42+
43+
Current MCP tools:
44+
45+
- `catalog_interfaces`
46+
- `grpc_get_mid_price`
47+
- `grpc_stream_mids_sample`
48+
- `grpc_get_block_number`
49+
- `grpc_stream_liquidations_sample`
50+
- `unified_get_stats`
51+
- `unified_get_events`
52+
- `unified_get_consensus_pulse`
53+
- `unified_get_all_mids`
54+
- `unified_get_l2_book`
55+
- `unified_get_asset_contexts`
56+
- `status_get_public`
57+
- `status_get_private`
58+
- `rpc_call`
59+
60+
## Validation
61+
62+
Validated in this repo with:
63+
64+
- `pytest`
65+
- `mypy -p hypercore_sdk`
66+
- `python -m build`
67+
- `python -m twine check dist/*`
68+
69+
The parity and MCP additions keep the Python SDK aligned with the TypeScript SDK for the Hypernode-local browser-safe market-data surfaces.

hypercore_sdk/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@
33
from .api import HyperCoreAPI
44
from .config import SDKConfig
55
from .grpc_client import GrpcClient
6+
from .mcp import HypercoreMCPServer
67
from .speed import run_grpc_health_speed_test, run_rpc_speed_test, run_ws_speed_test
8+
from .status import StatusClient
79
from .unified_stream import UnifiedStreamClient
810
from .ws import get_price_from_ws
911

1012
__all__ = [
1113
"GrpcClient",
1214
"HyperCoreAPI",
15+
"HypercoreMCPServer",
1316
"SDKConfig",
17+
"StatusClient",
1418
"UnifiedStreamClient",
1519
"get_price_from_ws",
1620
"run_grpc_health_speed_test",

hypercore_sdk/cli.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,28 @@ def _build_parser() -> argparse.ArgumentParser:
137137
stream_sse.add_argument("--max-events", type=int, default=20)
138138
_add_common_network_args(stream_sse)
139139

140+
stream_pulse = stream_sub.add_parser("consensus-pulse", help="Get unified consensus pulse metrics.")
141+
stream_pulse.add_argument("--stream-url", default=DEFAULT_CFG.unified_stream_url)
142+
_add_common_network_args(stream_pulse)
143+
144+
stream_all_mids = stream_sub.add_parser("all-mids", help="Get browser-safe allMids snapshot from unified stream.")
145+
stream_all_mids.add_argument("--stream-url", default=DEFAULT_CFG.unified_stream_url)
146+
stream_all_mids.add_argument("--dex", default="")
147+
_add_common_network_args(stream_all_mids)
148+
149+
stream_l2_book = stream_sub.add_parser("l2-book", help="Get browser-safe canonical L2 book snapshot from unified stream.")
150+
stream_l2_book.add_argument("--stream-url", default=DEFAULT_CFG.unified_stream_url)
151+
stream_l2_book.add_argument("--coin", required=True)
152+
stream_l2_book.add_argument("--dex", default="")
153+
stream_l2_book.add_argument("--depth", type=int, default=None)
154+
_add_common_network_args(stream_l2_book)
155+
156+
stream_asset_contexts = stream_sub.add_parser("asset-contexts", help="Get funding/OI/24h volume asset contexts from unified stream.")
157+
stream_asset_contexts.add_argument("--stream-url", default=DEFAULT_CFG.unified_stream_url)
158+
stream_asset_contexts.add_argument("--coin", default=None)
159+
stream_asset_contexts.add_argument("--dex", default="")
160+
_add_common_network_args(stream_asset_contexts)
161+
140162
grpc = sub.add_parser("grpc", help="gRPC setup and diagnostics.")
141163
grpc_sub = grpc.add_subparsers(dest="grpc_cmd", required=True)
142164

@@ -358,6 +380,30 @@ def main(argv: list[str] | None = None) -> int:
358380
_print_json({"events": list(stream_client.sse_events(max_events=args.max_events))})
359381
return 0
360382

383+
if args.command == "stream" and args.stream_cmd == "consensus-pulse":
384+
cfg = _sdk_cfg_from_args(args, unified_stream_url=args.stream_url)
385+
with UnifiedStreamClient(cfg) as stream_client:
386+
_print_json(stream_client.consensus_pulse())
387+
return 0
388+
389+
if args.command == "stream" and args.stream_cmd == "all-mids":
390+
cfg = _sdk_cfg_from_args(args, unified_stream_url=args.stream_url)
391+
with UnifiedStreamClient(cfg) as stream_client:
392+
_print_json(stream_client.all_mids(dex=args.dex))
393+
return 0
394+
395+
if args.command == "stream" and args.stream_cmd == "l2-book":
396+
cfg = _sdk_cfg_from_args(args, unified_stream_url=args.stream_url)
397+
with UnifiedStreamClient(cfg) as stream_client:
398+
_print_json(stream_client.l2_book(args.coin, dex=args.dex, depth=args.depth))
399+
return 0
400+
401+
if args.command == "stream" and args.stream_cmd == "asset-contexts":
402+
cfg = _sdk_cfg_from_args(args, unified_stream_url=args.stream_url)
403+
with UnifiedStreamClient(cfg) as stream_client:
404+
_print_json(stream_client.asset_contexts(coin=args.coin, dex=args.dex))
405+
return 0
406+
361407
if args.command == "grpc" and args.grpc_cmd == "health":
362408
grpc_client = GrpcClient(_grpc_cfg_from_args(args))
363409
_print_json(grpc_client.health_check(service=args.service))

hypercore_sdk/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,12 @@ class SDKConfig:
1717
ws_url: str = os.getenv("HYPER_WS_URL", "wss://disk.grpc.aleatoric.systems/")
1818
info_url: str = os.getenv("HYPER_INFO_URL", "https://api.hyperliquid.xyz/info")
1919
unified_stream_url: str = os.getenv("HYPER_UNIFIED_STREAM_URL", "https://unified.grpc.aleatoric.systems")
20+
status_url: str = os.getenv("HYPER_STATUS_URL", "http://127.0.0.1:8090")
2021
grpc_target: str = os.getenv("HYPER_GRPC_TARGET", "hl.grpc.aleatoric.systems:443")
2122
api_key: str | None = os.getenv("HYPER_API_KEY")
23+
unified_stream_api_key: str | None = os.getenv("UNIFIED_STREAM_KEY") or os.getenv("HYPER_UNIFIED_STREAM_API_KEY")
24+
grpc_api_key: str | None = os.getenv("ALEATORIC_GRPC_KEY") or os.getenv("HYPER_GRPC_API_KEY")
25+
status_token: str | None = os.getenv("HYPER_STATUS_TOKEN")
2226
timeout_s: float = float(os.getenv("HYPER_TIMEOUT_S", "10"))
2327
verify_tls: bool = _env_bool("HYPER_VERIFY_TLS", True)
2428
grpc_tls: bool = _env_bool("HYPER_GRPC_TLS", True)

0 commit comments

Comments
 (0)