Skip to main content
Glama
smithery-server.ts35.2 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import * as dotenv from 'dotenv'; import { HyperionClient } from './hyperion-client.js'; import { WalletManager } from './wallet-manager.js'; import { HyperionConfig, } from './types.js'; // Load environment variables dotenv.config(); // Configuration schema for Smithery export const configSchema = z.object({ privateKey: z.string().optional().describe("Your funded private key for Hyperion testnet"), rpcUrl: z.string().default('https://hyperion-testnet.metisdevops.link').describe("Hyperion RPC URL"), chainId: z.number().default(133717).describe("Hyperion Chain ID"), networkName: z.string().default('Hyperion Testnet').describe("Network name"), explorerUrl: z.string().default('https://hyperion-testnet-explorer.metisdevops.link').describe("Block explorer URL"), currencySymbol: z.string().default('tMETIS').describe("Currency symbol"), debug: z.boolean().default(false).describe("Enable debug logging"), }); export default function createStatelessServer({ config, }: { config: z.infer<typeof configSchema>; }) { const server = new McpServer({ name: "Hyperion Blockchain MCP Server", version: "1.1.0", }); // Initialize configuration const hyperionConfig: HyperionConfig = { rpcUrl: config.rpcUrl, chainId: config.chainId, networkName: config.networkName, explorerUrl: config.explorerUrl, currencySymbol: config.currencySymbol, }; // Initialize clients const hyperionClient = new HyperionClient(hyperionConfig); const walletManager = new WalletManager(); // Import wallet from config if privateKey is provided if (config.privateKey) { try { walletManager.importWallet(config.privateKey, undefined, 'Smithery Wallet'); } catch (error) { console.error('Failed to import wallet from config:', error); } } // Create Wallet Tool server.tool( "create_wallet", "Create a new Hyperion wallet with a generated mnemonic phrase", { name: z.string().optional().describe("Optional name for the wallet"), }, async ({ name }) => { try { const walletInfo = walletManager.createWallet(name); return { content: [ { type: "text", text: `Wallet created successfully!\n\nAddress: ${walletInfo.address}\nMnemonic: ${walletInfo.mnemonic}\n\n⚠️ IMPORTANT: Save your mnemonic phrase securely. It's the only way to recover your wallet!`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error creating wallet: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Import Wallet Tool server.tool( "import_wallet", "Import an existing wallet using private key or mnemonic phrase", { privateKey: z.string().optional().describe("Private key to import (alternative to mnemonic)"), mnemonic: z.string().optional().describe("Mnemonic phrase to import (alternative to private key)"), name: z.string().optional().describe("Optional name for the wallet"), }, async ({ privateKey, mnemonic, name }) => { try { const walletInfo = walletManager.importWallet(privateKey, mnemonic, name); return { content: [ { type: "text", text: `Wallet imported successfully!\n\nAddress: ${walletInfo.address}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error importing wallet: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // List Wallets Tool server.tool( "list_wallets", "List all available wallets", {}, async () => { try { const wallets = walletManager.listWallets(); const currentAddress = walletManager.getCurrentAddress(); let response = `Available Wallets (${wallets.length}):\n\n`; for (const wallet of wallets) { const isCurrent = wallet.address.toLowerCase() === currentAddress.toLowerCase(); response += `${isCurrent ? '→ ' : ' '}${wallet.address}${isCurrent ? ' (current)' : ''}\n`; } return { content: [ { type: "text", text: response, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error listing wallets: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Get Balance Tool server.tool( "get_balance", "Get the balance of a wallet address (native tokens or ERC20 tokens)", { address: z.string().describe("Wallet address to check balance for"), tokenAddress: z.string().optional().describe("Optional ERC20 token contract address"), }, async ({ address, tokenAddress }) => { try { if (tokenAddress) { const tokenBalance = await hyperionClient.getTokenBalance(address, tokenAddress); return { content: [ { type: "text", text: `Token Balance:\n\nAddress: ${address}\nToken: ${tokenBalance.name} (${tokenBalance.symbol})\nBalance: ${tokenBalance.balance} ${tokenBalance.symbol}`, }, ], }; } else { const balance = await hyperionClient.getBalance(address); return { content: [ { type: "text", text: `Native Balance:\n\nAddress: ${address}\nBalance: ${balance} ${hyperionClient.getCurrencySymbol()}`, }, ], }; } } catch (error) { return { content: [ { type: "text", text: `Error getting balance: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Get Native Balance Tool (dedicated for tMETIS) server.tool( "get_native_balance", "Get the native tMETIS balance of a wallet address on Hyperion testnet", { address: z.string().describe("Wallet address to check native balance for"), }, async ({ address }) => { try { const balance = await hyperionClient.getBalance(address); const networkInfo = await hyperionClient.getNetworkInfo(); return { content: [ { type: "text", text: `Native tMETIS Balance:\n\nAddress: ${address}\nBalance: ${balance} ${hyperionClient.getCurrencySymbol()}\nNetwork: ${networkInfo.networkName} (Chain ID: ${networkInfo.chainId})\nBlock: ${networkInfo.blockNumber}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error getting native balance: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Send Transaction Tool server.tool( "send_transaction", "Send native tokens or ERC20 tokens to another address", { to: z.string().describe("Recipient address"), amount: z.union([z.string(), z.number()]).describe("Amount to send (in token units, not wei)"), tokenAddress: z.string().optional().describe("Optional ERC20 token contract address (for token transfers)"), gasLimit: z.string().optional().describe("Optional gas limit"), gasPrice: z.string().optional().describe("Optional gas price"), }, async ({ to, amount, tokenAddress, gasLimit, gasPrice }) => { try { // Check if wallet is configured let wallet; try { wallet = walletManager.getCurrentWallet(); } catch (error) { return { content: [ { type: "text", text: `❌ No wallet configured for transactions!\n\n` + `To send transactions, you need to configure your private key:\n\n` + `🔧 **Via Smithery Interface (Recommended):**\n` + `1. Click "Save & Connect" below\n` + `2. Enter your funded private key for Hyperion testnet (64 hex chars without 0x prefix)\n` + `3. Example format: abc123def456...xyz (your actual private key here)\n\n` + `🔧 **Alternative Methods:**\n` + `• Use 'import_wallet' tool to add your private key\n` + `• Set HYPERION_PRIVATE_KEYS environment variable\n\n` + `Original error: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } // Convert amount to string if it's a number const amountStr = typeof amount === 'number' ? amount.toString() : amount; let result; if (tokenAddress) { result = await hyperionClient.sendTokenTransaction( wallet, tokenAddress, to, amountStr, gasLimit, gasPrice ); } else { result = await hyperionClient.sendTransaction( wallet, to, amountStr, gasLimit, gasPrice ); } return { content: [ { type: "text", text: `Transaction sent successfully!\n\nHash: ${result.hash}\nFrom: ${result.from}\nTo: ${result.to}\nAmount: ${result.value}\nStatus: ${result.status}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error sending transaction: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Get Network Info Tool server.tool( "get_network_info", "Get current network information and status", {}, async () => { try { const networkInfo = await hyperionClient.getNetworkInfo(); return { content: [ { type: "text", text: `Network Information:\n\nChain ID: ${networkInfo.chainId}\nNetwork: ${networkInfo.networkName}\nLatest Block: ${networkInfo.blockNumber}\nGas Price: ${networkInfo.gasPrice}\nConnected: ${networkInfo.isConnected}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error getting network info: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Get Transaction Tool server.tool( "get_transaction", "Get details of a transaction by hash", { hash: z.string().describe("Transaction hash"), }, async ({ hash }) => { try { const transaction = await hyperionClient.getTransaction(hash); return { content: [ { type: "text", text: `Transaction Details:\n\nHash: ${transaction.hash}\nFrom: ${transaction.from}\nTo: ${transaction.to}\nValue: ${transaction.value}\nGas Used: ${transaction.gasUsed}\nStatus: ${transaction.status}\nBlock: ${transaction.blockNumber}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error getting transaction: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Get Block Tool server.tool( "get_block", "Get block information by number or hash", { blockNumber: z.number().optional().describe("Block number (alternative to blockHash)"), blockHash: z.string().optional().describe("Block hash (alternative to blockNumber)"), }, async ({ blockNumber, blockHash }) => { try { const block = await hyperionClient.getBlock(blockNumber, blockHash); return { content: [ { type: "text", text: `Block Information:\n\nNumber: ${block.number}\nHash: ${block.hash}\nTimestamp: ${new Date(block.timestamp * 1000).toISOString()}\nTransaction Count: ${block.transactionCount}\nGas Used: ${block.gasUsed}\nGas Limit: ${block.gasLimit}\nMiner: ${block.miner}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error getting block: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Estimate Gas Tool server.tool( "estimate_gas", "Estimate gas cost for a transaction", { to: z.string().describe("Recipient address"), value: z.string().optional().describe("Optional value to send (in ether)"), data: z.string().optional().describe("Optional transaction data"), }, async ({ to, value, data }) => { try { const gasEstimate = await hyperionClient.estimateGas(to, value, data); return { content: [ { type: "text", text: `Gas Estimation:\n\nEstimated Gas: ${gasEstimate.gasLimit}\nGas Price: ${gasEstimate.gasPrice}\nEstimated Cost: ${gasEstimate.estimatedCost} ${hyperionClient.getCurrencySymbol()}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error estimating gas: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Set Current Wallet Tool server.tool( "set_current_wallet", "Set the current active wallet for transactions", { address: z.string().describe("Wallet address to set as current"), }, async ({ address }) => { try { // Note: WalletManager doesn't have setCurrentAddress method, // this would need to be implemented or use a different approach return { content: [ { type: "text", text: `Note: Setting current wallet functionality needs to be implemented in WalletManager. Address: ${address}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error setting current wallet: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Get Current Wallet Tool server.tool( "get_current_wallet", "Get the current active wallet information", {}, async () => { try { const currentAddress = walletManager.getCurrentAddress(); const wallet = walletManager.getCurrentWallet(); return { content: [ { type: "text", text: `Current Wallet:\n\nAddress: ${currentAddress}\nWallet Type: ${wallet.constructor.name}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error getting current wallet: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Deploy ERC20 Token Tool server.tool( "deploy_erc20_token", "Deploy a new ERC20 token contract", { name: z.string().describe("Token name (e.g., 'My Token')"), symbol: z.string().describe("Token symbol (e.g., 'MTK')"), decimals: z.number().optional().describe("Token decimals (default: 18)"), initialSupply: z.string().optional().describe("Initial token supply (default: 0)"), mintable: z.boolean().optional().describe("Whether token should be mintable (default: true)"), gasLimit: z.string().optional().describe("Gas limit for deployment"), gasPrice: z.string().optional().describe("Gas price for deployment"), }, async ({ name, symbol, decimals, initialSupply, mintable, gasLimit, gasPrice }) => { try { // Check if wallet is configured let wallet; try { wallet = walletManager.getCurrentWallet(); } catch (error) { return { content: [ { type: "text", text: `❌ No wallet configured for ERC20 deployment!\n\n` + `To deploy ERC20 tokens, you need to configure your private key:\n\n` + `🔧 **Via Smithery Interface (Recommended):**\n` + `1. Click "Save & Connect" below\n` + `2. Enter your funded private key for Hyperion testnet (64 hex chars without 0x prefix)\n` + `3. Example format: abc123def456...xyz (your actual private key here)\n\n` + `🔧 **Alternative Methods:**\n` + `• Use 'import_wallet' tool to add your private key\n` + `• Set HYPERION_PRIVATE_KEYS environment variable\n\n` + `Original error: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } const result = await hyperionClient.deployERC20Token( wallet, name, symbol, decimals || 18, initialSupply || "0", mintable ?? true, gasLimit, gasPrice ); const explorerUrl = hyperionClient.getExplorerUrl(); return { content: [ { type: "text", text: `ERC20 Token Deployed Successfully!\n\n` + `Contract Address: ${result.contractAddress}\n` + `Transaction Hash: ${result.transactionHash}\n` + `Token Name: ${result.name}\n` + `Token Symbol: ${result.symbol}\n` + `Decimals: ${result.decimals}\n` + `Initial Supply: ${result.initialSupply}\n` + `Deployer: ${result.deployer}\n` + `Gas Used: ${result.gasUsed || 'N/A'}\n` + `Block Number: ${result.blockNumber || 'Pending'}\n\n` + `Transaction Explorer: ${explorerUrl}/tx/${result.transactionHash}\n` + `Contract Explorer: ${explorerUrl}/address/${result.contractAddress}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error deploying ERC20 token: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Deploy ERC721 Token Tool server.tool( "deploy_erc721_token", "Deploy a new ERC721 token contract (NFT)", { name: z.string().describe("Token name (e.g., 'My NFT')"), symbol: z.string().describe("Token symbol (e.g., 'NFT')"), mintable: z.boolean().optional().describe("Whether the token should be mintable (default: false)"), gasLimit: z.string().optional().describe("Gas limit for deployment"), gasPrice: z.string().optional().describe("Gas price for deployment"), }, async ({ name, symbol, mintable, gasLimit, gasPrice }) => { try { let wallet; try { wallet = walletManager.getCurrentWallet(); } catch (error) { return { content: [ { type: "text", text: `❌ No wallet configured for ERC721 deployment!\n\nTo deploy ERC721 tokens, you need to configure your private key.\n\nOriginal error: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } const result = await hyperionClient.deployERC721Token( wallet, name, symbol, mintable || false, gasLimit, gasPrice ); const explorerUrl = hyperionClient.getExplorerUrl(); return { content: [ { type: "text", text: `ERC721 Token Deployed Successfully!\n\n` + `Contract Address: ${result.contractAddress}\n` + `Transaction Hash: ${result.transactionHash}\n` + `Token Name: ${result.name}\n` + `Token Symbol: ${result.symbol}\n` + `Deployer: ${result.deployer}\n` + `Gas Used: ${result.gasUsed || 'N/A'}\n` + `Block Number: ${result.blockNumber || 'Pending'}\n\n` + `Transaction Explorer: ${explorerUrl}/tx/${result.transactionHash}\n` + `Contract Explorer: ${explorerUrl}/address/${result.contractAddress}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error deploying ERC721 token: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Get Token Info Tool server.tool( "get_token_info", "Get comprehensive ERC20 token information including name, symbol, decimals, supply, and owner", { tokenAddress: z.string().describe("ERC20 token contract address"), }, async ({ tokenAddress }) => { try { const result = await hyperionClient.getTokenInfo(tokenAddress); const explorerUrl = hyperionClient.getExplorerUrl(); return { content: [ { type: "text", text: `ERC20 Token Information:\n\n` + `Contract Address: ${result.address}\n` + `Name: ${result.name}\n` + `Symbol: ${result.symbol}\n` + `Decimals: ${result.decimals}\n` + `Total Supply: ${result.totalSupply}\n` + `Owner: ${result.owner || 'N/A'}\n\n` + `Contract Explorer: ${explorerUrl}/address/${result.address}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error getting token info: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Mint Tokens Tool server.tool( "mint_tokens", "Mint additional tokens for mintable ERC20 contracts (owner only)", { tokenAddress: z.string().describe("ERC20 token contract address"), to: z.string().describe("Address to mint tokens to"), amount: z.union([z.string(), z.number()]).describe("Amount of tokens to mint"), gasLimit: z.string().optional().describe("Gas limit for minting"), gasPrice: z.string().optional().describe("Gas price for minting"), }, async ({ tokenAddress, to, amount, gasLimit, gasPrice }) => { try { // Check if wallet is configured let wallet; try { wallet = walletManager.getCurrentWallet(); } catch (error) { return { content: [ { type: "text", text: `❌ No wallet configured for token minting!\n\n` + `To mint tokens, you need to configure your private key:\n\n` + `🔧 **Via Smithery Interface (Recommended):**\n` + `1. Click "Save & Connect" below\n` + `2. Enter your funded private key for Hyperion testnet (64 hex chars without 0x prefix)\n` + `3. Example format: abc123def456...xyz (your actual private key here)\n\n` + `🔧 **Alternative Methods:**\n` + `• Use 'import_wallet' tool to add your private key\n` + `• Set HYPERION_PRIVATE_KEYS environment variable\n\n` + `Original error: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } // Convert amount to string if it's a number const amountStr = typeof amount === 'number' ? amount.toString() : amount; const result = await hyperionClient.mintTokens( wallet, tokenAddress, to, amountStr, gasLimit, gasPrice ); const explorerUrl = hyperionClient.getExplorerUrl(); return { content: [ { type: "text", text: `Tokens Minted Successfully!\n\n` + `Transaction Hash: ${result.hash}\n` + `Token Contract: ${tokenAddress}\n` + `Recipient: ${to}\n` + `Amount Minted: ${amount}\n` + `From: ${result.from}\n` + `Gas Used: ${result.gasUsed || 'N/A'}\n` + `Block Number: ${result.blockNumber || 'Pending'}\n\n` + `Transaction Explorer: ${explorerUrl}/tx/${result.hash}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error minting tokens: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Deploy ERC721 NFT Token Tool server.tool( "deploy_erc721_token", "Deploy a new ERC721 (NFT) token contract", { name: z.string().describe("NFT collection name (e.g., 'My NFT Collection')"), symbol: z.string().describe("NFT collection symbol (e.g., 'MYNFT')"), mintable: z.boolean().optional().describe("Whether NFT should be mintable (default: false)"), gasOptimized: z.boolean().optional().describe("Use gas-optimized minimal contract (default: true, saves ~40% gas)"), gasLimit: z.string().optional().describe("Gas limit for deployment (default: 3000000)"), gasPrice: z.string().optional().describe("Gas price for deployment"), }, async ({ name, symbol, mintable, gasOptimized, gasLimit, gasPrice }) => { try { // Check if wallet is configured let wallet; try { wallet = walletManager.getCurrentWallet(); } catch (error) { return { content: [ { type: "text", text: `❌ No wallet configured for ERC721 deployment!\n\n` + `To deploy ERC721 NFTs, you need to configure your private key:\n\n` + `🔧 **Via Smithery Interface (Recommended):**\n` + `1. Click "Save & Connect" below\n` + `2. Enter your funded private key for Hyperion testnet (64 hex chars without 0x prefix)\n` + `3. Example format: abc123def456...xyz (your actual private key here)\n\n` + `🔧 **Alternative Methods:**\n` + `• Use 'import_wallet' tool to add your private key\n` + `• Set HYPERION_PRIVATE_KEYS environment variable\n\n` + `Original error: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } const result = await hyperionClient.deployERC721Token( wallet, name, symbol, mintable || false, gasLimit || "3000000", gasPrice, gasOptimized ?? true ); const explorerUrl = hyperionClient.getExplorerUrl(); return { content: [ { type: "text", text: `ERC721 NFT Contract Deployed Successfully!\n\n` + `Contract Address: ${result.contractAddress}\n` + `Transaction Hash: ${result.transactionHash}\n` + `NFT Collection Name: ${result.name}\n` + `NFT Collection Symbol: ${result.symbol}\n` + `Deployer: ${result.deployer}\n` + `Gas Used: ${result.gasUsed || 'N/A'}\n` + `Block Number: ${result.blockNumber || 'Pending'}\n\n` + `Transaction Explorer: ${explorerUrl}/tx/${result.transactionHash}\n` + `Contract Explorer: ${explorerUrl}/address/${result.contractAddress}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error deploying ERC721 token: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Get NFT Info Tool server.tool( "get_nft_info", "Get comprehensive ERC721 NFT information including collection details and specific token info", { tokenAddress: z.string().describe("ERC721 NFT contract address"), tokenId: z.string().optional().describe("Optional token ID to get specific token info"), }, async ({ tokenAddress, tokenId }) => { try { const result = await hyperionClient.getNFTInfo(tokenAddress, tokenId); const explorerUrl = hyperionClient.getExplorerUrl(); return { content: [ { type: "text", text: `ERC721 NFT Information:\n\n` + `Contract Address: ${result.address}\n` + `Collection Name: ${result.name}\n` + `Collection Symbol: ${result.symbol}\n` + `Total Supply: ${result.totalSupply}\n` + `${result.tokenId ? `Token ID: ${result.tokenId}\n` : ''}` + `${result.tokenURI ? `Token URI: ${result.tokenURI}\n` : ''}` + `${result.owner ? `Token Owner: ${result.owner}\n` : ''}\n` + `Contract Explorer: ${explorerUrl}/address/${result.address}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error getting NFT info: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Mint NFT Tool server.tool( "mint_nft", "Mint a new NFT for mintable ERC721 contracts (owner only)", { tokenAddress: z.string().describe("ERC721 NFT contract address"), to: z.string().describe("Address to mint NFT to"), tokenId: z.string().describe("Unique token ID for the new NFT"), tokenURI: z.string().optional().describe("Metadata URI for the NFT (optional)"), gasLimit: z.string().optional().describe("Gas limit for minting"), gasPrice: z.string().optional().describe("Gas price for minting"), }, async ({ tokenAddress, to, tokenId, tokenURI, gasLimit, gasPrice }) => { try { // Check if wallet is configured let wallet; try { wallet = walletManager.getCurrentWallet(); } catch (error) { return { content: [ { type: "text", text: `❌ No wallet configured for NFT minting!\n\n` + `To mint NFTs, you need to configure your private key:\n\n` + `🔧 **Via Smithery Interface (Recommended):**\n` + `1. Click "Save & Connect" below\n` + `2. Enter your funded private key for Hyperion testnet (64 hex chars without 0x prefix)\n` + `3. Example format: abc123def456...xyz (your actual private key here)\n\n` + `🔧 **Alternative Methods:**\n` + `• Use 'import_wallet' tool to add your private key\n` + `• Set HYPERION_PRIVATE_KEYS environment variable\n\n` + `Original error: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } const result = await hyperionClient.mintNFT( wallet, tokenAddress, to, tokenId, tokenURI || '', gasLimit, gasPrice ); const explorerUrl = hyperionClient.getExplorerUrl(); return { content: [ { type: "text", text: `NFT Minted Successfully!\n\n` + `Transaction Hash: ${result.transactionHash}\n` + `NFT Contract: ${tokenAddress}\n` + `Recipient: ${result.to}\n` + `Token ID: ${result.tokenId}\n` + `${result.tokenURI ? `Token URI: ${result.tokenURI}\n` : ''}` + `Gas Used: ${result.gasUsed || 'N/A'}\n` + `Block Number: ${result.blockNumber || 'Pending'}\n\n` + `Transaction Explorer: ${explorerUrl}/tx/${result.transactionHash}\n` + `Contract Explorer: ${explorerUrl}/address/${tokenAddress}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error minting NFT: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); return server.server; } // For Smithery deployment - create and start the server // Check if this file is being run directly (works in both ESM and CommonJS) const isDirectExecution = process.argv[1] && ( process.argv[1].endsWith('smithery-server.js') || process.argv[1].endsWith('smithery-server.ts') || process.argv[1].includes('smithery-server') ); if (isDirectExecution) { const defaultConfig = { rpcUrl: process.env.HYPERION_RPC_URL || 'https://hyperion-testnet.metisdevops.link', chainId: parseInt(process.env.HYPERION_CHAIN_ID || '133717'), networkName: process.env.HYPERION_NETWORK_NAME || 'Hyperion Testnet', explorerUrl: process.env.HYPERION_EXPLORER_URL || 'https://hyperion-testnet-explorer.metisdevops.link', currencySymbol: process.env.HYPERION_CURRENCY_SYMBOL || 'tMETIS', debug: process.env.DEBUG === 'true' || false, }; const server = createStatelessServer({ config: defaultConfig }); // Start the server with stdio transport const transport = new StdioServerTransport(); server.connect(transport).catch((error) => { console.error("Failed to start Hyperion MCP Server:", error); process.exit(1); }); }

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/cuongpo/hyperion-mcp-server'

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