UNPKG

@sei-js/mcp-server

Version:

Model Context Protocol (MCP) server for interacting with EVM-compatible networks

601 lines (600 loc) 22.3 kB
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; import { DEFAULT_NETWORK, getRpcUrl, getSupportedNetworks } from './chains.js'; import * as services from './services/index.js'; /** * Register all EVM-related resources * @param server The MCP server instance */ export function registerEVMResources(server) { // Get EVM info for a specific network server.resource('chain_info_by_network', new ResourceTemplate('evm://{network}/chain', { list: undefined }), async (uri, params) => { try { const network = params.network; const chainId = await services.getChainId(network); const blockNumber = await services.getBlockNumber(network); const rpcUrl = getRpcUrl(network); return { contents: [ { uri: uri.href, text: JSON.stringify({ network, chainId, blockNumber: blockNumber.toString(), rpcUrl }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching chain info: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Default chain info (Sei mainnet) server.resource('sei_chain_info', 'evm://chain', async (uri) => { try { const network = DEFAULT_NETWORK; const chainId = await services.getChainId(network); const blockNumber = await services.getBlockNumber(network); const rpcUrl = getRpcUrl(network); return { contents: [ { uri: uri.href, text: JSON.stringify({ network, chainId, blockNumber: blockNumber.toString(), rpcUrl }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching chain info: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Get block by number for a specific network server.resource('evm_block_by_number', new ResourceTemplate('evm://{network}/block/{blockNumber}', { list: undefined }), async (uri, params) => { try { const network = params.network; const blockNumber = params.blockNumber; const block = await services.getBlockByNumber(Number.parseInt(blockNumber), network); return { contents: [ { uri: uri.href, text: services.helpers.formatJson(block) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching block: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Get block by hash for a specific network server.resource('block_by_hash', new ResourceTemplate('evm://{network}/block/hash/{blockHash}', { list: undefined }), async (uri, params) => { try { const network = params.network; const blockHash = params.blockHash; const block = await services.getBlockByHash(blockHash, network); return { contents: [ { uri: uri.href, text: services.helpers.formatJson(block) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching block with hash: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Get latest block for a specific network server.resource('evm_latest_block', new ResourceTemplate('evm://{network}/block/latest', { list: undefined }), async (uri, params) => { try { const network = params.network; const block = await services.getLatestBlock(network); return { contents: [ { uri: uri.href, text: services.helpers.formatJson(block) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching latest block: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Default latest block (Sei mainnet) server.resource('default_latest_block', 'evm://block/latest', async (uri) => { try { const network = DEFAULT_NETWORK; const block = await services.getLatestBlock(network); return { contents: [ { uri: uri.href, text: services.helpers.formatJson(block) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching latest block: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Get native token balance for a specific network server.resource('evm_address_native_balance', new ResourceTemplate('evm://{network}/address/{address}/balance', { list: undefined }), async (uri, params) => { try { const network = params.network; const address = params.address; const balance = await services.getBalance(address, network); return { contents: [ { uri: uri.href, text: JSON.stringify({ network, address, balance: { wei: balance.wei.toString(), ether: balance.sei } }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching Sei balance: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Default Sei balance (Sei mainnet) server.resource('default_sei_balance', new ResourceTemplate('evm://address/{address}/sei-balance', { list: undefined }), async (uri, params) => { try { const network = DEFAULT_NETWORK; const address = params.address; const balance = await services.getBalance(address, network); return { contents: [ { uri: uri.href, text: JSON.stringify({ network, address, balance: { wei: balance.wei.toString(), ether: balance.sei } }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching Sei balance: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Get ERC20 balance for a specific network server.resource('erc20_balance', new ResourceTemplate('evm://{network}/address/{address}/token/{tokenAddress}/balance', { list: undefined }), async (uri, params) => { try { const network = params.network; const address = params.address; const tokenAddress = params.tokenAddress; const balance = await services.getERC20Balance(tokenAddress, address, network); return { contents: [ { uri: uri.href, text: JSON.stringify({ network, address, tokenAddress, balance: { raw: balance.raw.toString(), formatted: balance.formatted, decimals: balance.token.decimals } }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching ERC20 balance: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Default ERC20 balance (Sei mainnet) server.resource('default_erc20_balance', new ResourceTemplate('evm://address/{address}/token/{tokenAddress}/balance', { list: undefined }), async (uri, params) => { try { const network = DEFAULT_NETWORK; const address = params.address; const tokenAddress = params.tokenAddress; const balance = await services.getERC20Balance(tokenAddress, address, network); return { contents: [ { uri: uri.href, text: JSON.stringify({ network, address, tokenAddress, balance: { raw: balance.raw.toString(), formatted: balance.formatted, decimals: balance.token.decimals } }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching ERC20 balance: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Get transaction by hash for a specific network server.resource('evm_transaction_details', new ResourceTemplate('evm://{network}/tx/{txHash}', { list: undefined }), async (uri, params) => { try { const network = params.network; const txHash = params.txHash; const tx = await services.getTransaction(txHash, network); return { contents: [ { uri: uri.href, text: services.helpers.formatJson(tx) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching transaction: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Default transaction by hash (Sei mainnet) server.resource('default_transaction_by_hash', new ResourceTemplate('evm://tx/{txHash}', { list: undefined }), async (uri, params) => { try { const network = DEFAULT_NETWORK; const txHash = params.txHash; const tx = await services.getTransaction(txHash, network); return { contents: [ { uri: uri.href, text: services.helpers.formatJson(tx) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching transaction: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Get supported networks server.resource('supported_networks', 'evm://networks', async (uri) => { try { const networks = getSupportedNetworks(); return { contents: [ { uri: uri.href, text: JSON.stringify({ supportedNetworks: networks }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching supported networks: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Add ERC20 token info resource server.resource('erc20_token_details', new ResourceTemplate('evm://{network}/token/{tokenAddress}', { list: undefined }), async (uri, params) => { try { const network = params.network; const tokenAddress = params.tokenAddress; const tokenInfo = await services.getERC20TokenInfo(tokenAddress, network); return { contents: [ { uri: uri.href, text: JSON.stringify({ address: tokenAddress, network, ...tokenInfo }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching ERC20 token info: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Add ERC20 token balance resource server.resource('erc20_token_address_balance', new ResourceTemplate('evm://{network}/token/{tokenAddress}/balanceOf/{address}', { list: undefined }), async (uri, params) => { try { const network = params.network; const tokenAddress = params.tokenAddress; const address = params.address; const balance = await services.getERC20Balance(tokenAddress, address, network); return { contents: [ { uri: uri.href, text: JSON.stringify({ tokenAddress, owner: address, network, raw: balance.raw.toString(), formatted: balance.formatted, symbol: balance.token.symbol, decimals: balance.token.decimals }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching ERC20 token balance: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Add NFT (ERC721) token info resource server.resource('erc721_nft_token_details', new ResourceTemplate('evm://{network}/nft/{tokenAddress}/{tokenId}', { list: undefined }), async (uri, params) => { try { const network = params.network; const tokenAddress = params.tokenAddress; const tokenId = BigInt(params.tokenId); const nftInfo = await services.getERC721TokenMetadata(tokenAddress, tokenId, network); // Get owner separately let owner = 'Unknown'; try { const isOwner = await services.isNFTOwner(tokenAddress, params.address, tokenId, network); if (isOwner) { owner = params.address; } } catch (e) { // Owner info not available } return { contents: [ { uri: uri.href, text: JSON.stringify({ contract: tokenAddress, tokenId: tokenId.toString(), network, ...nftInfo, owner }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching NFT info: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Add NFT ownership check resource server.resource('erc721_nft_ownership_check', new ResourceTemplate('evm://{network}/nft/{tokenAddress}/{tokenId}/isOwnedBy/{address}', { list: undefined }), async (uri, params) => { try { const network = params.network; const tokenAddress = params.tokenAddress; const tokenId = BigInt(params.tokenId); const address = params.address; const isOwner = await services.isNFTOwner(tokenAddress, address, tokenId, network); return { contents: [ { uri: uri.href, text: JSON.stringify({ contract: tokenAddress, tokenId: tokenId.toString(), owner: address, network, isOwner }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error checking NFT ownership: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Add ERC1155 token URI resource server.resource('erc1155_token_metadata_uri', new ResourceTemplate('evm://{network}/erc1155/{tokenAddress}/{tokenId}/uri', { list: undefined }), async (uri, params) => { try { const network = params.network; const tokenAddress = params.tokenAddress; const tokenId = BigInt(params.tokenId); const tokenURI = await services.getERC1155TokenURI(tokenAddress, tokenId, network); return { contents: [ { uri: uri.href, text: JSON.stringify({ contract: tokenAddress, tokenId: tokenId.toString(), network, uri: tokenURI }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching ERC1155 token URI: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); // Add ERC1155 token balance resource server.resource('erc1155_token_address_balance', new ResourceTemplate('evm://{network}/erc1155/{tokenAddress}/{tokenId}/balanceOf/{address}', { list: undefined }), async (uri, params) => { try { const network = params.network; const tokenAddress = params.tokenAddress; const tokenId = BigInt(params.tokenId); const address = params.address; const balance = await services.getERC1155Balance(tokenAddress, address, tokenId, network); return { contents: [ { uri: uri.href, text: JSON.stringify({ contract: tokenAddress, tokenId: tokenId.toString(), owner: address, network, balance: balance.toString() }, null, 2) } ] }; } catch (error) { return { contents: [ { uri: uri.href, text: `Error fetching ERC1155 token balance: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); }