Skip to main content
Glama

bsc-multisend-mcp

index.js7.72 kB
const { McpServer } = require('@modelcontextprotocol/sdk/server/mcp.js'); const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js'); const { ethers } = require('ethers'); const { z } = require('zod'); require('dotenv').config(); // BSC contract details const CONTRACT_ADDRESS = '0x2e1d30460265bfebedacf5bb6f9a80f0e74b7498'; const CONTRACT_ABI = [ { "constant": false, "inputs": [ { "name": "receivers", "type": "address[]" }, { "name": "amounts", "type": "uint256[]" } ], "name": "transferMulti", "outputs": [], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "tokenAddress", "type": "address" }, { "name": "receivers", "type": "address[]" }, { "name": "amounts", "type": "uint256[]" } ], "name": "transferMultiToken", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "from", "type": "address" }, { "indexed": false, "name": "to", "type": "address" }, { "indexed": false, "name": "amount", "type": "uint256" }, { "indexed": false, "name": "tokenAddress", "type": "address" } ], "name": "transfer", "type": "event" } ]; // ERC20 ABI for decimals, allowance, and approve const ERC20_ABI = [ { "constant": true, "inputs": [], "name": "decimals", "outputs": [{ "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "owner", "type": "address" }, { "name": "spender", "type": "address" } ], "name": "allowance", "outputs": [{ "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "name": "spender", "type": "address" }, { "name": "value", "type": "uint256" } ], "name": "approve", "outputs": [{ "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" } ]; // Initialize ethers provider const provider = new ethers.JsonRpcProvider(process.env.BSC_RPC || 'https://bsc-dataseed.binance.org/'); // Wallet setup const PRIVATE_KEY = process.env.PRIVATE_KEY; if (!PRIVATE_KEY) { throw new Error('PRIVATE_KEY must be set in .env'); } const wallet = new ethers.Wallet(PRIVATE_KEY, provider); const WALLET_ADDRESS = wallet.address; // Initialize C98MultiSend contract const contract = new ethers.Contract(CONTRACT_ADDRESS, CONTRACT_ABI, wallet); // Create MCP server const server = new McpServer({ name: 'BSC-MultiSend-Server', version: '1.0.0' }); // Tool: Distribute native BNB to multiple addresses server.tool( 'distributeNative', 'Send BNB to multiple addresses on BSC using the C98MultiSend contract.', z.object({ receivers: z.array(z.string().refine((val) => ethers.isAddress(val), { message: 'Invalid BSC address' })).describe('Array of BSC addresses to receive BNB.'), amounts: z.array(z.number().positive('Amount must be positive')).describe('Array of BNB amounts (in BNB, e.g., 0.1) to send to each receiver.') }), async ({ receivers, amounts }) => { try { // Validate inputs if (receivers.length !== amounts.length) { return { content: [{ type: 'text', text: 'Receivers and amounts arrays must have the same length' }], isError: true }; } // Convert amounts to wei and calculate total const amountsWei = amounts.map(amount => ethers.parseEther(amount.toString())); const totalAmountWei = amountsWei.reduce((sum, amount) => sum + BigInt(amount), BigInt(0)); // Prepare and send transaction const tx = await contract.transferMulti(receivers, amountsWei, { value: totalAmountWei, gasLimit: await contract.transferMulti.estimateGas(receivers, amountsWei, { value: totalAmountWei }) }); // Wait for transaction confirmation const receipt = await tx.wait(); return { content: [{ type: 'text', text: `BNB distribution successful. Tx Hash: ${receipt.hash}` }], isError: false }; } catch (error) { return { content: [{ type: 'text', text: `Error executing BNB distribution: ${error.message}` }], isError: true }; } } ); // Tool: Distribute ERC20 tokens to multiple addresses server.tool( 'distributeToken', 'Send ERC20 tokens to multiple addresses on BSC using the C98MultiSend contract.', z.object({ tokenAddress: z.string().refine((val) => ethers.isAddress(val), { message: 'Invalid token address' }).describe('Address of the ERC20 token contract to distribute.'), receivers: z.array(z.string().refine((val) => ethers.isAddress(val), { message: 'Invalid BSC address' })).describe('Array of BSC addresses to receive tokens.'), amounts: z.array(z.number().positive('Amount must be positive')).describe('Array of token amounts (in tokens, e.g., 100.5) to send to each receiver.') }), async ({ tokenAddress, receivers, amounts }) => { try { // Validate inputs if (receivers.length !== amounts.length) { return { content: [{ type: 'text', text: 'Receivers and amounts arrays must have the same length' }], isError: true }; } // Initialize token contract const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, wallet); // Query token decimals let decimals; try { decimals = await tokenContract.decimals(); } catch (error) { return { content: [{ type: 'text', text: `Invalid ERC20 token: Unable to fetch decimals (${error.message})` }], isError: true }; } // Convert amounts to token units const amountsUnits = amounts.map(amount => ethers.parseUnits(amount.toString(), decimals)); // Calculate total amount needed const totalAmount = amountsUnits.reduce((sum, amount) => sum + BigInt(amount), BigInt(0)); // Check allowance const allowance = await tokenContract.allowance(WALLET_ADDRESS, CONTRACT_ADDRESS); if (BigInt(allowance) < totalAmount) { // Approve the contract to spend tokens try { const approveTx = await tokenContract.approve(CONTRACT_ADDRESS, totalAmount, { gasLimit: await tokenContract.approve.estimateGas(CONTRACT_ADDRESS, totalAmount) }); await approveTx.wait(); } catch (error) { return { content: [{ type: 'text', text: `Failed to approve token spending: ${error.message}` }], isError: true }; } } // Prepare and send transaction const tx = await contract.transferMultiToken(tokenAddress, receivers, amountsUnits, { gasLimit: await contract.transferMultiToken.estimateGas(tokenAddress, receivers, amountsUnits) }); // Wait for transaction confirmation const receipt = await tx.wait(); return { content: [{ type: 'text', text: `Token distribution successful. Tx Hash: ${receipt.hash}` }], isError: false }; } catch (error) { return { content: [{ type: 'text', text: `Error executing token distribution: ${error.message}` }], isError: true }; } } ); // Start server with stdio transport async function startServer() { const transport = new StdioServerTransport(); await server.connect(transport); } startServer().catch(console.error);

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/bsc-multisend-mcp'

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