agentpump-mcp 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +42 -7
  2. package/package.json +2 -2
package/index.js CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  } from "@solana/spl-token";
14
14
  import { Raydium, TxVersion, CurveCalculator, CREATE_CPMM_POOL_PROGRAM } from "@raydium-io/raydium-sdk-v2";
15
15
  import BN from "bn.js";
16
+ import bs58 from "bs58";
16
17
  import { homedir } from "os";
17
18
  import { join } from "path";
18
19
  import { mkdirSync, readFileSync, writeFileSync, existsSync, chmodSync } from "fs";
@@ -25,7 +26,17 @@ const rpcFetch = async (u, o) => { let err; for (const url of RPCS) { try { cons
25
26
  const conn = new Connection(RPC, { commitment: "confirmed", fetch: rpcFetch });
26
27
  const [CONFIG] = PublicKey.findProgramAddressSync([Buffer.from("config")], PROGRAM);
27
28
  const V_SOL = 2500000000n, SUPPLY = 1000000000n * 1000000n;
29
+ const META = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
28
30
  const u64 = (n) => { const b = Buffer.alloc(8); b.writeBigUInt64LE(BigInt(n)); return b; };
31
+ const mstr = (s) => { const b = Buffer.from(s, "utf8"); const l = Buffer.alloc(4); l.writeUInt32LE(b.length); return Buffer.concat([l, b]); };
32
+ function metaIx(mint, auth, payer, name, sym) {
33
+ const [md] = PublicKey.findProgramAddressSync([Buffer.from("metadata"), META.toBuffer(), mint.toBuffer()], META);
34
+ const data = Buffer.concat([Buffer.from([33]), mstr(name), mstr(sym), mstr(""), Buffer.from([0, 0]), Buffer.from([0]), Buffer.from([0]), Buffer.from([0]), Buffer.from([1]), Buffer.from([0])]);
35
+ return new TransactionInstruction({ programId: META, keys: [
36
+ { pubkey: md, isSigner: false, isWritable: true }, { pubkey: mint, isSigner: false, isWritable: false }, { pubkey: auth, isSigner: true, isWritable: false },
37
+ { pubkey: payer, isSigner: true, isWritable: true }, { pubkey: auth, isSigner: false, isWritable: false }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
38
+ ], data });
39
+ }
29
40
  const WDIR = join(homedir(), ".agentpump"), WFILE = join(WDIR, "wallet.json");
30
41
  const curveOf = (m) => PublicKey.findProgramAddressSync([Buffer.from("curve"), m.toBuffer()], PROGRAM)[0];
31
42
  const ataOf = (m, o) => getAssociatedTokenAddressSync(m, o, true);
@@ -40,6 +51,15 @@ function tradeKeys(mint, curve, cAta, uAta, user) {
40
51
  ];
41
52
  }
42
53
  const ok = (t) => ({ content: [{ type: "text", text: t }] });
54
+ // retry once on transient RPC/simulation flaps (stale blockhash, rate-limit, node hiccup) — the tx didn't land, so it's safe
55
+ async function retryTransient(fn) {
56
+ try { return await fn(); }
57
+ catch (e) { const m = ((e && e.message) || "") + "";
58
+ if (/custom program error/i.test(m)) throw e; // deterministic on-chain rejection — a retry can't fix it
59
+ if (/simulat|blockhash|not found|expired|timed out|timeout|429|too many|fetch failed|ECONN|socket|rate limit/i.test(m)) { await new Promise((r) => setTimeout(r, 1000)); return await fn(); }
60
+ throw e; }
61
+ }
62
+ const send = (tx, signers) => retryTransient(() => sendAndConfirmTransaction(conn, tx, signers));
43
63
 
44
64
  // --- Raydium CPMM helpers (trade graduated/listed tokens; 1% fee to treasury) ---
45
65
  let _ray;
@@ -55,7 +75,7 @@ function estimate(inAmt, inRes, outRes, ci) {
55
75
  return CurveCalculator.swapBaseInput(inAmt, inRes, outRes, ci.tradeFeeRate, ci.creatorFeeRate, ci.protocolFeeRate, ci.fundFeeRate, false);
56
76
  }
57
77
 
58
- const s = new McpServer({ name: "agentpump", version: "1.1.0" });
78
+ const s = new McpServer({ name: "agentpump", version: "1.1.4" });
59
79
 
60
80
  s.tool("sol_create_wallet", "Create the agent's Solana wallet (saved locally, hidden). Returns the address to fund.", {}, { title: "Create wallet", readOnlyHint: false }, async () => {
61
81
  if (existsSync(WFILE)) return ok("Wallet already exists: " + loadKp().publicKey.toBase58());
@@ -68,29 +88,30 @@ s.tool("sol_balance", "Check the wallet's SOL balance.", {}, { title: "Balance",
68
88
  const kp = loadKp(); const b = await conn.getBalance(kp.publicKey); return ok((b / LAMPORTS_PER_SOL).toFixed(4) + " SOL\n" + kp.publicKey.toBase58());
69
89
  });
70
90
  s.tool("sol_launch", "Launch a new token on AgentPump (bonding curve). Costs ~0.02 SOL in rent.", { name: z.string(), symbol: z.string() }, { title: "Launch token", readOnlyHint: false, openWorldHint: true }, async ({ name, symbol }) => {
71
- const kp = loadKp(); const mint = await createMint(conn, kp, kp.publicKey, null, 6); // returns a PublicKey
91
+ const kp = loadKp(); const mint = await retryTransient(() => createMint(conn, kp, kp.publicKey, null, 6)); // returns a PublicKey
92
+ await send(new Transaction().add(metaIx(mint, kp.publicKey, kp.publicKey, name, symbol)), [kp]); // on-chain name/symbol so it shows on the launchpad
72
93
  const curve = curveOf(mint), cAta = ataOf(mint, curve);
73
- await sendAndConfirmTransaction(conn, new Transaction().add(createAssociatedTokenAccountIdempotentInstruction(kp.publicKey, cAta, curve, mint)), [kp]);
74
- await mintTo(conn, kp, mint, cAta, kp, SUPPLY);
94
+ await send(new Transaction().add(createAssociatedTokenAccountIdempotentInstruction(kp.publicKey, cAta, curve, mint)), [kp]);
95
+ await retryTransient(() => mintTo(conn, kp, mint, cAta, kp, SUPPLY));
75
96
  const ix = new TransactionInstruction({ programId: PROGRAM, data: Buffer.concat([Buffer.from([1]), u64(V_SOL), u64(SUPPLY)]), keys: [
76
97
  { pubkey: CONFIG, isSigner: false, isWritable: true }, { pubkey: curve, isSigner: false, isWritable: true }, { pubkey: mint, isSigner: false, isWritable: false },
77
98
  { pubkey: cAta, isSigner: false, isWritable: true }, { pubkey: kp.publicKey, isSigner: true, isWritable: true }, { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
78
99
  ] });
79
- await sendAndConfirmTransaction(conn, new Transaction().add(ix), [kp]);
100
+ await send(new Transaction().add(ix), [kp]);
80
101
  return ok(`Launched ${symbol}. Token: ${mint.toBase58()}\nTradeable on the curve; graduates to Raydium at 10 SOL.`);
81
102
  });
82
103
  s.tool("sol_buy", "Buy a token on its bonding curve (pre-graduation). For graduated tokens use sol_raydium_buy.", { mint: z.string(), sol: z.number() }, { title: "Buy (curve)", readOnlyHint: false, openWorldHint: true }, async ({ mint: ms, sol: amt }) => {
83
104
  const kp = loadKp(); const mint = new PublicKey(ms); const curve = curveOf(mint), cAta = ataOf(mint, curve), uAta = ataOf(mint, kp.publicKey);
84
105
  const tx = new Transaction().add(createAssociatedTokenAccountIdempotentInstruction(kp.publicKey, uAta, kp.publicKey, mint))
85
106
  .add(new TransactionInstruction({ programId: PROGRAM, keys: tradeKeys(mint, curve, cAta, uAta, kp.publicKey), data: Buffer.concat([Buffer.from([2]), u64(Math.round(amt * LAMPORTS_PER_SOL)), u64(0)]) }));
86
- const sig = await sendAndConfirmTransaction(conn, tx, [kp]); return ok("Bought. " + sig);
107
+ const sig = await send(tx, [kp]); return ok("Bought. " + sig);
87
108
  });
88
109
  s.tool("sol_sell", "Sell a percentage of a token holding back to the bonding curve (pre-graduation). For graduated tokens use sol_raydium_sell.", { mint: z.string(), percent: z.number() }, { title: "Sell (curve)", readOnlyHint: false, openWorldHint: true }, async ({ mint: ms, percent }) => {
89
110
  const kp = loadKp(); const mint = new PublicKey(ms); const curve = curveOf(mint), cAta = ataOf(mint, curve), uAta = ataOf(mint, kp.publicKey);
90
111
  const acc = await getAccount(conn, uAta); const amt = (acc.amount * BigInt(Math.round(percent))) / 100n;
91
112
  if (amt <= 0n) throw new Error("nothing to sell");
92
113
  const ix = new TransactionInstruction({ programId: PROGRAM, keys: tradeKeys(mint, curve, cAta, uAta, kp.publicKey), data: Buffer.concat([Buffer.from([3]), u64(amt), u64(0)]) });
93
- const sig = await sendAndConfirmTransaction(conn, new Transaction().add(ix), [kp]); return ok("Sold. " + sig);
114
+ const sig = await send(new Transaction().add(ix), [kp]); return ok("Sold. " + sig);
94
115
  });
95
116
  s.tool("sol_raydium_buy", "Buy any graduated/listed token on Raydium (after it leaves the bonding curve). Charges a 1% fee.", { mint: z.string(), sol: z.number() }, { title: "Buy (Raydium)", readOnlyHint: false, openWorldHint: true }, async ({ mint: ms, sol: amt }) => {
96
117
  const kp = loadKp(); const mint = new PublicKey(ms);
@@ -128,4 +149,18 @@ s.tool("sol_raydium_sell", "Sell a percentage of a graduated/listed token on Ray
128
149
  return ok(`Sold on Raydium. tx ${r.txId}\n1% fee (${(feePaid / LAMPORTS_PER_SOL).toFixed(5)} SOL) sent to treasury.`);
129
150
  });
130
151
 
152
+ s.tool("sol_withdraw", "Send SOL out of the agent wallet to any address. Omit 'sol' to send the whole balance (minus the network fee).", { to: z.string(), sol: z.number().optional() }, { title: "Withdraw SOL", readOnlyHint: false, openWorldHint: true }, async ({ to, sol }) => {
153
+ const kp = loadKp(); const dest = new PublicKey(to);
154
+ const bal = await conn.getBalance(kp.publicKey); const FEE_L = 5000;
155
+ let lamports = (sol == null) ? bal - FEE_L : Math.round(sol * LAMPORTS_PER_SOL);
156
+ if (lamports > bal - FEE_L) lamports = bal - FEE_L;
157
+ if (lamports <= 0) throw new Error("balance too low to withdraw (need to cover the ~0.000005 SOL network fee)");
158
+ const sig = await send(new Transaction().add(SystemProgram.transfer({ fromPubkey: kp.publicKey, toPubkey: dest, lamports })), [kp]);
159
+ return ok(`Sent ${(lamports / LAMPORTS_PER_SOL).toFixed(6)} SOL to ${to}\n${sig}`);
160
+ });
161
+ s.tool("sol_export_key", "Reveal the agent wallet's private key (base58) so it can be imported into Phantom/Solflare. Anyone with this key controls the funds — only show it to the wallet owner.", {}, { title: "Export private key", readOnlyHint: true }, async () => {
162
+ const kp = loadKp();
163
+ return ok("Private key (import into Phantom → 'Import Private Key'):\n" + bs58.encode(kp.secretKey) + "\n\n⚠️ Anyone with this key controls the wallet. Keep it secret.");
164
+ });
165
+
131
166
  await s.connect(new StdioServerTransport());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentpump-mcp",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "MCP server to launch & trade tokens on AgentPump (Solana bonding-curve launchpad) from AI agents. Trade graduated tokens on Raydium.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -37,4 +37,4 @@
37
37
  "zod": "^3.23.8"
38
38
  },
39
39
  "mcpName": "io.github.axiosdevs/agentpump-mcp"
40
- }
40
+ }