Skip to main content
Glama

send_msol

Transfer mSOL tokens to another Solana wallet, automatically creating the recipient's token account if needed.

Instructions

Send mSOL tokens to another Solana wallet address. This tool automatically checks if the recipient's mSOL token account exists and creates it if necessary.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
recipientAddressYesThe Solana wallet address of the recipient
amountYesThe amount of mSOL to send

Implementation Reference

  • The core handler function for the 'send_msol' tool. It validates inputs, sets up Solana connection and wallet, retrieves mSOL mint, checks balances, handles token accounts (creating if needed), executes the SPL token transfer, and returns transaction details or errors.
    callback: async ({ recipientAddress, amount }: { recipientAddress: string; amount: number }) => { try { const amountLamports = MarinadeUtils.solToLamports(amount); const { wallet, connection } = createSolanaConfig() const config = new MarinadeConfig({ connection, publicKey: wallet.publicKey, }) const marinade = new Marinade(config) const marinadeState = await marinade.getMarinadeState(); const mSolMint = marinadeState.mSolMintAddress; let recipientPublicKey: PublicKey; try { recipientPublicKey = new PublicKey(recipientAddress); } catch (err) { return { content: [ { type: "text", text: JSON.stringify({ error: "Invalid recipient address", reason: "The provided recipient address is not a valid Solana public key" }, null, 2), }, ], }; } const senderTokenAccount = await getOrCreateAssociatedTokenAccount( connection, wallet, mSolMint, wallet.publicKey ); const senderBalance = Number(senderTokenAccount.amount); if (senderBalance < amountLamports) { return { content: [ { type: "text", text: JSON.stringify({ error: "Insufficient mSOL balance", reason: `Required: ${amount} mSOL (${amountLamports} lamports), Available: ${senderBalance / LAMPORTS_PER_SOL} mSOL (${senderBalance} lamports)` }, null, 2), }, ], }; } const recipientTokenAccount = await getOrCreateAssociatedTokenAccount( connection, wallet, mSolMint, recipientPublicKey, false ); const accountCreated = recipientTokenAccount.amount === BigInt(0) && senderTokenAccount.address.toString() !== recipientTokenAccount.address.toString(); const signature = await transfer( connection, wallet, senderTokenAccount.address, recipientTokenAccount.address, wallet.publicKey, amountLamports ); return { content: [ { type: "text", text: JSON.stringify({ success: true, signature, recipient: recipientAddress, recipientTokenAccount: recipientTokenAccount.address.toString(), accountCreated: accountCreated ? "A new token account was created for the recipient" : "Used existing token account", amountSent: amount, amountSentLamports: amountLamports.toString(), explorerUrl: `https://solscan.io/tx/${signature}${process.env.ENVIRONMENT === 'MAINNET' ? '' : '?cluster=devnet'}` }, null, 2), }, ], }; } catch (err) { const isAbort = (err as Error)?.name === "AbortError"; const isTimeout = (err as Error)?.message?.includes("timeout"); McpLogger.error("Error in send_msol tool:", String(err)); return { content: [ { type: "text", text: JSON.stringify( { error: isAbort || isTimeout ? "Request timed out" : "Failed to send mSOL", reason: String((err as Error)?.message ?? err), suggestion: isAbort || isTimeout ? "The transaction may still be processing. Check your wallet or try again with a different RPC endpoint." : "Please check the recipient address, your mSOL balance, and network connection." }, null, 2 ), }, ], }; } }
  • Zod input schema defining the parameters for the send_msol tool: recipientAddress (string) and amount (number >= 0).
    inputSchema: { recipientAddress: z.string().describe("The Solana wallet address of the recipient"), amount: z.number().min(0).describe("The amount of mSOL to send"), },
  • src/server.ts:25-43 (registration)
    The registration code in the MCP server setup that dynamically registers the 'send_msol' tool (along with others from marinadeFinanceTools) using server.registerTool, passing the tool's name, metadata, and a wrapper around its callback.
    for (const t of marinadeFinanceTools) { server.registerTool( t.name, { title: t.title, description: t.description, inputSchema: t.inputSchema }, async (args) => { const result = await t.callback(args); return { content: result.content.map(item => ({ ...item, type: "text" as const })) }; } ); }
  • Helper function that initializes the Solana wallet from environment private key and creates a Connection instance based on the network (mainnet/devnet), used by the send_msol handler.
    function createSolanaConfig() { const isMainnet = process.env.ENVIRONMENT === "MAINNET"; const privateKey = process.env.PRIVATE_KEY || ''; const rpcUrlMainnet = process.env.SOLANA_RPC_URL const rpcUrlDevnet = process.env.SOLANA_RPC_URL_DEVNET; const rpcUrl = isMainnet ? rpcUrlMainnet : rpcUrlDevnet; if (!privateKey || !rpcUrlMainnet || !rpcUrlDevnet || !rpcUrl) { throw new Error("PRIVATE_KEY, SOLANA_RPC_URL, SOLANA_RPC_URL_DEVNET environment variables are required"); } const wallet = Keypair.fromSecretKey(bs58.decode(privateKey)); const connection = new Connection(rpcUrl, { commitment: "confirmed", }); return { wallet, connection }; }

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/leandrogavidia/marinade-finance-mcp-server'

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