Skip to main content
Glama
cli.py7.71 kB
import os from typing import Dict, List, Optional import httpx from mcp.server.fastmcp import FastMCP, Context from mcp.server.fastmcp.prompts import base # Configuration BLOCKNATIVE_API_KEY = os.getenv("BLOCKNATIVE_API_KEY") # Optional for low-frequency access BLOCKNATIVE_GAS_API_URL = "https://api.blocknative.com/gasprices/blockprices" BLOCKNATIVE_CHAINS_API_URL = "https://api.blocknative.com/chains" # Initialize MCP server mcp = FastMCP( name="Blocknative Gas Server", dependencies=["httpx"] ) # Helper function to fetch gas prices from Blocknative async def fetch_gas_prices(chain_id: int = 1) -> Dict: """Fetch gas price predictions from Blocknative API for a given chain.""" try: headers = {"Authorization": BLOCKNATIVE_API_KEY} if BLOCKNATIVE_API_KEY else {} async with httpx.AsyncClient() as client: response = await client.get( BLOCKNATIVE_GAS_API_URL, headers=headers, params={"chainid": chain_id} ) response.raise_for_status() data = response.json() # Extract relevant fields from the response block_prices = data.get("blockPrices", []) if not block_prices: return {"error": "No block prices found in API response"} # Use the first block's data first_block = block_prices[0] return { "baseFeePerGas": first_block.get("baseFeePerGas", 0), "estimatedPrices": first_block.get("estimatedPrices", []), "unit": data.get("unit", "gwei"), "system": data.get("system", "unknown"), "network": data.get("network", "unknown") } except httpx.HTTPError as e: return {"error": f"Failed to fetch gas prices for chain ID {chain_id}: {str(e)}"} # Helper function to fetch supported chains from Blocknative async def fetch_supported_chains() -> Dict: """Fetch the list of supported chains from Blocknative Chains API.""" try: headers = {"Authorization": BLOCKNATIVE_API_KEY} if BLOCKNATIVE_API_KEY else {} async with httpx.AsyncClient() as client: response = await client.get(BLOCKNATIVE_CHAINS_API_URL, headers=headers) response.raise_for_status() data = response.json() return {"chains": data, "error": None} except httpx.HTTPError as e: return {"chains": [], "error": f"Failed to fetch supported chains: {str(e)}"} # Tools @mcp.tool() async def predict_gas_price(chain_id: int = 1, ctx: Optional[Context] = None) -> str: """ Predict gas prices for a specified chain, including base fee and detailed prediction data in a Markdown table. Parameters: - chain_id (int): The ID of the blockchain network (e.g., 1 for Ethereum Mainnet). Default: 1. - ctx (Optional[Context]): The MCP context object. Default: None. """ data = await fetch_gas_prices(chain_id) if "error" in data: return data["error"] # Format base fee and metadata base_fee = data["baseFeePerGas"] output = f"Gas Price Predictions for Chain ID {chain_id} ({data['system']}/{data['network']}):\n" output += f"- Base Fee Per Gas: {base_fee} Gwei\n\n" # Format predictions as a Markdown table predictions = data["estimatedPrices"] if not predictions: output += "No prediction data available." else: output += "| Confidence | Price (Gwei) | Max Priority Fee (Gwei) | Max Fee (Gwei) |\n" output += "|------------|--------------|-------------------------|----------------|\n" for price in predictions: confidence = price.get("confidence", 0) price_value = price.get("price", 0) max_priority_fee = price.get("maxPriorityFeePerGas", 0) max_fee = price.get("maxFeePerGas", 0) output += ( f"| {confidence}% | {price_value} | {max_priority_fee} | {max_fee} |\n" ) return output @mcp.tool() async def estimate_gas_cost(gas_limit: int, confidence: int = 99, chain_id: int = 1, ctx: Optional[Context] = None) -> str: """ Estimate gas cost for a transaction based on gas limit, confidence level, and chain. Parameters: - gas_limit (int): The gas limit for the transaction (e.g., 21000 for a simple transfer). - confidence (int): The confidence level for gas price prediction (0-100). - chain_id (int): The ID of the blockchain network (e.g., 1 for Ethereum Mainnet). Default: 1. - ctx (Optional[Context]): The MCP context object. Default: None. """ if not (0 <= confidence <= 100): return "Error: Confidence must be between 0 and 100" if gas_limit <= 0: return "Error: Gas limit must be positive" data = await fetch_gas_prices(chain_id) if "error" in data: return data["error"] # Find the closest confidence level predictions = data["estimatedPrices"] closest_prediction = min( predictions, key=lambda p: abs(p.get("confidence", 0) - confidence), default={} ) if not closest_prediction: return "Error: No matching gas price prediction found" max_fee = closest_prediction.get("maxFeePerGas", 0) total_cost_gwei = max_fee * gas_limit total_cost_eth = total_cost_gwei / 1e9 # Convert Gwei to ETH return ( f"Estimated Gas Cost (Confidence {confidence}%, Chain ID {chain_id}):\n" f"- Gas Limit: {gas_limit}\n" f"- Max Fee Per Gas: {max_fee} Gwei\n" f"- Total Cost: {total_cost_gwei} Gwei ({total_cost_eth:.6f} ETH)" ) @mcp.tool() async def get_supported_chains(ctx: Optional[Context] = None) -> str: """ List the blockchain networks supported by the Blocknative Gas Platform, formatted as a Markdown table. Parameters: - ctx (Optional[Context]): The MCP context object. Default: None. Returns: - A Markdown table listing supported chains with their chain ID, system, and network. """ data = await fetch_supported_chains() if data["error"]: return data["error"] chains = data["chains"] if not chains: return "No supported chains found." output = "Supported Chains:\n\n" output += "| Chain ID | System | Network |\n" output += "|----------|--------|---------|\n" for chain in chains: chain_id = chain.get("chainId", "Unknown") system = chain.get("system", "Unknown") network = chain.get("network", "Unknown") output += f"| {chain_id} | {system} | {network} |\n" return output # Prompts @mcp.prompt() def gas_price_query(confidence: int, chain_id: int = 1) -> List[base.Message]: """ Prompt template for querying gas prices at a specific confidence level and chain. Parameters: - confidence (int): The confidence level for gas price prediction (0-100). - chain_id (int): The ID of the blockchain network (e.g., 1 for Ethereum Mainnet). Default: 1. """ try: if not (0 <= confidence <= 100): raise ValueError("Confidence must be between 0 and 100") if chain_id <= 0: raise ValueError("Invalid chain ID") except ValueError as e: return [ base.UserMessage(f"Please provide valid inputs: {str(e)}") ] return [ base.UserMessage( f"What is the current gas price for chain ID {chain_id} transactions " f"with {confidence}% confidence?" ), base.AssistantMessage( f"Let me fetch the gas price predictions for chain ID {chain_id}." ) ] # Run the server def main() -> None: mcp.run()

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kukapay/blocknative-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server