Pump.fun MCP Server

  • src
import { LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js"; import { initializeSDK, createMcpResponse } from "./get-token-info.js"; import { getOrCreateKeypair, getSPLBalance, rootDir } from "./utils.js"; import path from "path"; import fs from "fs"; import dotenv from "dotenv"; dotenv.config({ path: path.join(rootDir, ".env") }); const DEFAULT_PRIORITY_FEES = { unitLimit: 250000, unitPrice: 250000, }; export async function sellToken( tokenAddress: string, sellAmount: number = 0, accountName: string = "default", slippageBasisPoints: number = 100 ) { try { console.error("Starting sellToken function"); const { sdk, connection } = initializeSDK(); console.error("SDK initialized"); const keysFolder = path.resolve(rootDir, ".keys"); console.error(`Using keys folder path relative to script: ${keysFolder}`); console.error( `Checking if keys folder exists: ${fs.existsSync(keysFolder)}` ); if (!fs.existsSync(keysFolder)) { console.error(`Creating keys folder: ${keysFolder}`); try { fs.mkdirSync(keysFolder, { recursive: true }); console.error(`Keys folder created successfully`); } catch (mkdirError: any) { console.error(`Error creating keys folder:`, mkdirError); return { success: false, error: `Error creating keys folder: ${ mkdirError.message || JSON.stringify(mkdirError) }`, }; } } console.error(`Getting or creating keypair from folder: ${keysFolder}`); const account = getOrCreateKeypair(keysFolder, accountName); console.log(`Using account: ${account.publicKey.toString()}`); const mintPublicKey = new PublicKey(tokenAddress); console.log(`Token address: ${tokenAddress}`); const tokenBalance = await getSPLBalance( connection, mintPublicKey, account.publicKey ); console.log(`Current token balance: ${tokenBalance}`); if (!tokenBalance || tokenBalance === 0) { const errorMessage = `No tokens to sell. Account ${account.publicKey.toString()} has 0 tokens of ${tokenAddress}.`; console.error(errorMessage); return { success: false, error: errorMessage }; } const amountToSell = sellAmount === 0 ? tokenBalance : Math.min(sellAmount, tokenBalance); console.log(`Amount to sell: ${amountToSell}`); const initialSolBalance = await connection.getBalance(account.publicKey); console.log( `Initial SOL balance: ${initialSolBalance / LAMPORTS_PER_SOL} SOL` ); console.log(`Selling ${amountToSell} tokens...`); const result = await sdk.sell( account, mintPublicKey, BigInt(amountToSell * Math.pow(10, 6)), BigInt(slippageBasisPoints), DEFAULT_PRIORITY_FEES ); if (!result.success) { console.error(`Failed to sell token:`, result.error); return { success: false, error: result.error ? typeof result.error === "object" ? JSON.stringify(result.error) : result.error : "Unknown error", }; } console.log(`Transaction successful: ${result.signature}`); const newSolBalance = await connection.getBalance(account.publicKey); console.log(`New SOL balance: ${newSolBalance / LAMPORTS_PER_SOL} SOL`); const solReceived = (newSolBalance - initialSolBalance) / LAMPORTS_PER_SOL; console.log(`SOL received: ${solReceived} SOL`); const newTokenBalance = (await getSPLBalance(connection, mintPublicKey, account.publicKey)) || 0; console.log(`New token balance: ${newTokenBalance}`); return { success: true, tokenAddress, tokensSold: amountToSell, solReceived, newTokenBalance, signature: result.signature, pumpfunUrl: `https://pump.fun/${tokenAddress}`, }; } catch (error: any) { console.error("Error selling token:", error); console.error("Error stack:", error.stack); let errorMessage = "Unknown error"; if (error) { if (typeof error === "object") { if (error.message) { errorMessage = error.message; } else { try { errorMessage = JSON.stringify(error); } catch (e) { errorMessage = "Error object could not be stringified"; } } } else { errorMessage = String(error); } } return { success: false, error: errorMessage }; } } export function formatSellResult( result: ReturnType<typeof sellToken> extends Promise<infer T> ? T : never ) { if (!result.success) { return `Error selling token: ${result.error}`; } return [ `Successfully sold token!`, `Token Address: ${result.tokenAddress}`, `Tokens Sold: ${result.tokensSold}`, `SOL Received: ${result.solReceived} SOL`, `Remaining Token Balance: ${result.newTokenBalance}`, `Transaction Signature: ${result.signature}`, `Pump.fun URL: ${result.pumpfunUrl}`, ].join("\n"); } async function main() { const args = process.argv.slice(2); if (args.length < 1) { console.error( "Usage: node sell-token.js <token_address> [sell_amount] [account_name] [slippage_basis_points]" ); console.error( "Example: node sell-token.js G5e2XonmccmdKc98g3eNQe5oBYGw9m8xdMUvVtcZpump 1000 default 100" ); console.error( "Note: If sell_amount is 0 or not provided, all tokens will be sold." ); process.exit(1); } const tokenAddress = args[0]; const sellAmount = args[1] ? parseFloat(args[1]) : 0; const accountName = args[2] || "default"; const slippageBasisPoints = args[3] ? parseInt(args[3]) : 100; if (isNaN(sellAmount) || sellAmount < 0) { console.error("Sell amount must be a non-negative number"); process.exit(1); } if (isNaN(slippageBasisPoints) || slippageBasisPoints < 0) { console.error("Slippage basis points must be a non-negative integer"); process.exit(1); } const sellAmountText = sellAmount === 0 ? "ALL" : sellAmount; console.log( `Selling ${sellAmountText} tokens of ${tokenAddress} with account ${accountName} and slippage ${slippageBasisPoints} basis points` ); try { const result = await sellToken( tokenAddress, sellAmount, accountName, slippageBasisPoints ); console.log("\nResult:"); const formattedResult = formatSellResult(result); console.log(formattedResult); const mcpResponse = createMcpResponse(formattedResult); console.log("\nMCP Response (for reference):"); console.log(JSON.stringify(mcpResponse, null, 2)); } catch (error: any) { console.error("Error in main:", error); } } const isMainModule = import.meta.url === `file://${process.argv[1]}`; if (isMainModule) { main().catch(console.error); } export default { sellToken, formatSellResult, };