Runtime API¶
The runtime module provides Web3 client and transaction utilities for generated servers.
Module: abi_to_mcp.runtime¶
Web3Client¶
Managed Web3 connection.
from abi_to_mcp.runtime import Web3Client
client = Web3Client(
rpc_url="https://eth-mainnet.g.alchemy.com/v2/YOUR-KEY",
network="mainnet"
)
Constructor¶
RPC URL priority:
1. Explicit rpc_url parameter
2. RPC_URL environment variable
3. Default from NETWORKS[network]
Properties¶
w3: Web3¶
Get Web3 instance (lazy initialization).
Methods¶
get_contract(address: str, abi: List) -> Contract¶
Create contract instance with checksum address.
contract = client.get_contract(
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
abi
)
# Use contract
balance = await contract.functions.balanceOf(address).call()
is_connected() -> bool¶
Check if connected to network.
get_chain_id() -> int¶
Get current chain ID.
TransactionBuilder¶
Build transactions for contract calls.
from abi_to_mcp.runtime import TransactionBuilder
builder = TransactionBuilder(web3_client)
tx = builder.build_transaction(
contract_function,
from_address="0x..."
)
Methods¶
build_transaction(...) -> Dict[str, Any]¶
Build a transaction dictionary.
tx = builder.build_transaction(
contract.functions.transfer(to, amount),
from_address="0x...",
value=0,
gas_limit=None, # Auto-estimate
gas_price=None, # Use network default
max_fee_per_gas=None, # For EIP-1559
max_priority_fee_per_gas=None
)
Parameters:
| Name | Type | Description |
|---|---|---|
contract_function |
ContractFunction |
Web3 contract function |
from_address |
str |
Sender address |
value |
int |
ETH to send (wei) |
gas_limit |
Optional[int] |
Gas limit |
gas_price |
Optional[int] |
Legacy gas price |
max_fee_per_gas |
Optional[int] |
EIP-1559 max fee |
max_priority_fee_per_gas |
Optional[int] |
EIP-1559 priority fee |
Returns: Transaction dictionary ready for signing
estimate_gas(tx: Dict[str, Any]) -> int¶
Estimate gas for transaction.
TransactionSimulator¶
Simulate transactions without executing.
from abi_to_mcp.runtime import TransactionSimulator
simulator = TransactionSimulator(web3_client)
result = simulator.simulate(
contract_function,
from_address="0x..."
)
Methods¶
simulate(...) -> Dict[str, Any]¶
Simulate a transaction.
result = await simulator.simulate(
contract.functions.transfer(to, amount),
from_address="0x...",
value=0
)
print(result)
# {
# "success": True,
# "would_succeed": True,
# "result": True, # Return value
# "gas_estimate": 65000,
# "gas_price": 25000000000,
# "estimated_cost_eth": "0.001625",
# "error": None
# }
Simulation Failure:
result = await simulator.simulate(...)
# {
# "success": True,
# "would_succeed": False,
# "result": None,
# "error": "execution reverted: ERC20: transfer amount exceeds balance",
# "gas_estimate": None,
# ...
# }
Signer¶
Transaction signing utilities.
from abi_to_mcp.runtime import Signer
signer = Signer(private_key="0x...")
signed_tx = signer.sign_transaction(tx)
Constructor¶
If not provided, reads from PRIVATE_KEY environment variable.
Properties¶
address: str¶
Get signer's address.
Methods¶
sign_transaction(tx: Dict) -> SignedTransaction¶
Sign a transaction.
signed = signer.sign_transaction(tx)
tx_hash = await w3.eth.send_raw_transaction(signed.rawTransaction)
sign_message(message: str) -> SignedMessage¶
Sign a message (EIP-191).
GasEstimator¶
Gas price estimation utilities.
from abi_to_mcp.runtime import GasEstimator
estimator = GasEstimator(web3_client)
prices = await estimator.get_gas_prices()
Methods¶
get_gas_prices() -> GasPrices¶
Get current gas prices.
prices = await estimator.get_gas_prices()
print(f"Base fee: {prices.base_fee} gwei")
print(f"Priority fee: {prices.priority_fee} gwei")
print(f"Max fee: {prices.max_fee} gwei")
estimate_cost(gas_units: int) -> GasCost¶
Estimate transaction cost.
cost = await estimator.estimate_cost(65000)
print(f"ETH: {cost.eth}")
print(f"USD: ${cost.usd}") # If price feed available
Data Classes¶
GasPrices¶
Current gas prices.
@dataclass
class GasPrices:
base_fee: int # Wei
priority_fee: int # Wei
max_fee: int # Wei
legacy_price: int # Wei (for non-EIP-1559)
GasCost¶
Estimated transaction cost.
@dataclass
class GasCost:
gas_units: int
gas_price: int # Wei
eth: float # Total cost in ETH
usd: Optional[float] # USD if price available
Examples¶
Complete Transaction Flow¶
from abi_to_mcp.runtime import (
Web3Client,
TransactionBuilder,
TransactionSimulator,
Signer
)
# Setup
client = Web3Client(network="mainnet")
contract = client.get_contract(address, abi)
builder = TransactionBuilder(client)
simulator = TransactionSimulator(client)
signer = Signer()
# Build function call
func = contract.functions.transfer(to_address, amount)
# Simulate first
sim_result = await simulator.simulate(func, signer.address)
if not sim_result["would_succeed"]:
raise ValueError(f"Would fail: {sim_result['error']}")
print(f"Gas estimate: {sim_result['gas_estimate']}")
print(f"Cost: {sim_result['estimated_cost_eth']} ETH")
# Build and sign
tx = builder.build_transaction(func, signer.address)
signed = signer.sign_transaction(tx)
# Send
tx_hash = await client.w3.eth.send_raw_transaction(signed.rawTransaction)
print(f"Sent: {tx_hash.hex()}")
# Wait for receipt
receipt = await client.w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"Confirmed in block {receipt['blockNumber']}")
Read-Only Usage¶
from abi_to_mcp.runtime import Web3Client
client = Web3Client(
rpc_url="https://eth-mainnet.g.alchemy.com/v2/KEY"
)
contract = client.get_contract(
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
usdc_abi
)
# Read operations - no signer needed
name = await contract.functions.name().call()
symbol = await contract.functions.symbol().call()
balance = await contract.functions.balanceOf(address).call()
print(f"{name} ({symbol}): {balance}")
Error Handling¶
from abi_to_mcp.runtime import TransactionSimulator
from abi_to_mcp.core.exceptions import (
SimulationError,
InsufficientFundsError,
ContractRevertError
)
try:
result = await simulator.simulate(func, address)
if not result["would_succeed"]:
raise SimulationError(result["error"])
except InsufficientFundsError:
print("Not enough ETH for gas")
except ContractRevertError as e:
print(f"Contract reverted: {e}")
except Exception as e:
print(f"Unexpected error: {e}")