unstake_msol
Convert mSOL tokens back to SOL tokens through Marinade Finance's liquid staking protocol. Specify the amount to unstake.
Instructions
Unstake your mSOL tokens with Marinade Finance to receive SOL tokens.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| amount | Yes | The amount of mSOL to unstake |
Implementation Reference
- src/tools.ts:401-467 (handler)The handler callback for the 'unstake_msol' tool. It performs liquid unstaking of mSOL to SOL using the Marinade SDK: creates config and connection, calls liquidUnstake, sends and confirms the transaction, returns success details or error.callback: async ({ amount }: { 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 { associatedMSolTokenAccountAddress, transaction, } = await marinade.liquidUnstake(amountLamports) const signature = await sendAndConfirmTransaction(connection, transaction, [wallet], { commitment: "confirmed", preflightCommitment: "processed", skipPreflight: false, maxRetries: 3, }) return { content: [ { type: "text", text: JSON.stringify({ success: true, signature, mSolTokenAccount: associatedMSolTokenAccountAddress, amountUnstaked: amount, amountUnstakedLamports: 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 stake_msol tool:", String(err)); return { content: [ { type: "text", text: JSON.stringify( { error: isAbort || isTimeout ? "Request timed out" : "Failed to stake SOL", 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 your wallet balance and network connection." }, null, 2 ), }, ], }; } }
- src/tools.ts:398-400 (schema)Zod input schema for 'unstake_msol' tool defining the required 'amount' parameter as a positive number.inputSchema: { amount: z.number().min(0).describe("The amount of mSOL to unstake"), },
- src/server.ts:25-43 (registration)Generic registration loop that registers the 'unstake_msol' tool (and others) with the MCP server using the name, schema, and wrapped callback from tools.ts.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 })) }; } ); }
- src/tools.ts:12-31 (helper)Helper function to create Solana wallet and connection configuration from environment variables, used in the unstake_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 }; }