Skip to content

Commit 3ecde72

Browse files
authored
Merge pull request #5 from lukewwww/main
Get latest block height
2 parents aa35d75 + 77bd47f commit 3ecde72

File tree

6 files changed

+63
-0
lines changed

6 files changed

+63
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Crynux MCP Server
22

3+
[![](https://dcbadge.limes.pink/api/server/https://discord.gg/zmU9GRwU6f)](https://discord.gg/zmU9GRwU6f)
4+
[![PyPI - Version](https://img.shields.io/pypi/v/crynux-mcp?style=for-the-badge)](https://pypi.org/project/crynux-mcp/)
5+
36
MCP server for Crynux Network operations, designed for LLM clients (such as Cursor, VS Code, and Claude Desktop) to perform most Crynux Network/Crynux Portal actions through standardized MCP tools.
47

58
## Features
@@ -11,6 +14,7 @@ MCP server for Crynux Network operations, designed for LLM clients (such as Curs
1114
### Blockchain
1215

1316
- Native CNX balance query on Crynux L2 networks
17+
- Latest block height query on Crynux L2 networks
1418
- Native CNX transfer
1519
- Beneficial address query and on-chain update
1620
- Node staking query

docs/tools.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ This document contains detailed input and output fields for each MCP tool.
1919
| Action | Description |
2020
|---|---|
2121
| [`get_balance`](#get_balance) | Query native CNX balance for an address. |
22+
| [`get_latest_block_number`](#get_latest_block_number) | Query latest on-chain block height for a network. |
2223
| [`transfer_native`](#transfer_native) | Send native CNX with local signer key. |
2324
| [`get_beneficial_address`](#get_beneficial_address) | Query node beneficial address. |
2425
| [`set_beneficial_address`](#set_beneficial_address) | Submit transaction to set beneficial address. |
@@ -56,6 +57,14 @@ Output fields:
5657
- `balance_wei`
5758
- `symbol` (`CNX`)
5859

60+
## get_latest_block_number
61+
62+
Inputs:
63+
- `network`: optional (`dymension` or `near`). Defaults to configured default network.
64+
65+
Output fields:
66+
- `block_number`: latest finalized block number returned by RPC.
67+
5968
## transfer_native
6069

6170
Inputs:

src/crynux_mcp/blockchain/evm_client.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from crynux_mcp.blockchain.schemas import (
1111
BalanceResult,
1212
BeneficialAddressResult,
13+
LatestBlockNumberResult,
1314
NodeCreditsResult,
1415
NodeStakingInfoResult,
1516
SetBeneficialAddressResult,
@@ -85,6 +86,9 @@ def get_balance(self, address: str) -> BalanceResult:
8586
symbol=self.chain.native_currency.symbol,
8687
)
8788

89+
def get_latest_block_number(self) -> LatestBlockNumberResult:
90+
return LatestBlockNumberResult(block_number=int(self.w3.eth.block_number))
91+
8892
def transfer_native(
8993
self,
9094
private_key: str,

src/crynux_mcp/blockchain/schemas.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ class BalanceResult:
1414
symbol: str
1515

1616

17+
@dataclass(frozen=True)
18+
class LatestBlockNumberResult:
19+
block_number: int
20+
21+
1722
@dataclass(frozen=True)
1823
class TransferResult:
1924
from_address: str

src/crynux_mcp/server.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ def handle_get_balance(
8888
raise _execution_error(exc, {"network": network, "address": address, "key_name": key_name}) from exc
8989

9090

91+
def handle_get_latest_block_number(network: str | None) -> dict[str, Any]:
92+
try:
93+
chain = registry.resolve(network)
94+
client = EvmClient(chain)
95+
return _to_response_payload(client.get_latest_block_number())
96+
except Exception as exc: # noqa: BLE001
97+
raise _execution_error(exc, {"network": network}) from exc
98+
99+
91100
def handle_transfer_native(
92101
network: str | None,
93102
to: str,
@@ -550,6 +559,12 @@ def get_balance(
550559
return handle_get_balance(network=network, address=address, key_name=key_name)
551560

552561

562+
@mcp.tool()
563+
def get_latest_block_number(network: str | None) -> dict[str, Any]:
564+
"""Get latest block number on a selected Crynux EVM network."""
565+
return handle_get_latest_block_number(network=network)
566+
567+
553568
@mcp.tool()
554569
def transfer_native(
555570
network: str | None,

tests/test_tools_contract.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from crynux_mcp.server import (
44
handle_get_balance,
55
handle_get_beneficial_address,
6+
handle_get_latest_block_number,
67
handle_get_node_credits,
78
handle_get_node_staking_info,
89
handle_set_beneficial_address,
@@ -38,6 +39,31 @@ def resolve(self, _network):
3839
assert "chain_id" not in payload
3940

4041

42+
def test_handle_get_latest_block_number_shape(monkeypatch) -> None: # type: ignore[no-untyped-def]
43+
@dataclass(frozen=True)
44+
class FakeResult:
45+
block_number: int = 123456
46+
47+
class FakeClient:
48+
def __init__(self, _chain) -> None:
49+
pass
50+
51+
def get_latest_block_number(self):
52+
return FakeResult()
53+
54+
class FakeRegistry:
55+
def resolve(self, _network):
56+
return object()
57+
58+
monkeypatch.setattr("crynux_mcp.server.EvmClient", FakeClient)
59+
monkeypatch.setattr("crynux_mcp.server.registry", FakeRegistry())
60+
61+
payload = handle_get_latest_block_number(network="dymension")
62+
assert payload["block_number"] == 123456
63+
assert "network" not in payload
64+
assert "chain_id" not in payload
65+
66+
4167
def test_handle_transfer_sanitizes_private_key_error(monkeypatch) -> None: # type: ignore[no-untyped-def]
4268
class FakeClient:
4369
def __init__(self, _chain) -> None:

0 commit comments

Comments
 (0)