@t2000/mcp 0.23.0 → 0.24.0

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.
package/dist/index.js CHANGED
@@ -352,17 +352,19 @@ function registerWriteTools(server, agent) {
352
352
  );
353
353
  server.tool(
354
354
  "t2000_save",
355
- 'Deposit USDC to savings at the best USDC rate (earns yield). Amount is in dollars. Use "all" to save entire available balance. Set dryRun: true to preview.',
355
+ 'Deposit to NAVI lending to earn yield. Supports USDC (default), USDT, SUI, USDe, USDsui. Amount is in token units. Use "all" to save entire available balance. Set dryRun: true to preview.',
356
356
  {
357
- amount: z.union([z.number(), z.literal("all")]).describe('Dollar amount to save, or "all"'),
357
+ amount: z.union([z.number(), z.literal("all")]).describe('Amount to save, or "all"'),
358
+ asset: z.enum(["USDC", "USDT", "SUI", "USDe", "USDsui"]).optional().describe("Asset to deposit (default: USDC)"),
358
359
  dryRun: z.boolean().optional().describe("Preview without signing (default: false)")
359
360
  },
360
- async ({ amount, dryRun }) => {
361
+ async ({ amount, asset, dryRun }) => {
361
362
  try {
362
363
  if (dryRun) {
363
364
  agent.enforcer.assertNotLocked();
364
365
  const balance = await agent.balance();
365
366
  const rates = await agent.rates();
367
+ const assetKey = asset ?? "USDC";
366
368
  const saveAmount = amount === "all" ? balance.available - 1 : amount;
367
369
  return {
368
370
  content: [{
@@ -370,13 +372,14 @@ function registerWriteTools(server, agent) {
370
372
  text: JSON.stringify({
371
373
  preview: true,
372
374
  amount: saveAmount,
373
- currentApy: rates.USDC?.saveApy ?? 0,
375
+ asset: assetKey,
376
+ currentApy: rates[assetKey]?.saveApy ?? rates.USDC?.saveApy ?? 0,
374
377
  savingsBalanceAfter: balance.savings + saveAmount
375
378
  })
376
379
  }]
377
380
  };
378
381
  }
379
- const result = await mutex.run(() => agent.save({ amount }));
382
+ const result = await mutex.run(() => agent.save({ amount, asset }));
380
383
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
381
384
  } catch (err) {
382
385
  return errorResult(err);
@@ -385,31 +388,33 @@ function registerWriteTools(server, agent) {
385
388
  );
386
389
  server.tool(
387
390
  "t2000_withdraw",
388
- 'Withdraw from savings back to checking. Amount is in dollars. Use "all" to withdraw everything. Set dryRun: true to preview.',
391
+ 'Withdraw from NAVI lending back to wallet. Supports any deposited asset. Amount is in token units. Use "all" to withdraw everything. Set dryRun: true to preview.',
389
392
  {
390
- amount: z.union([z.number(), z.literal("all")]).describe('Dollar amount to withdraw, or "all"'),
393
+ amount: z.union([z.number(), z.literal("all")]).describe('Amount to withdraw, or "all"'),
394
+ asset: z.string().optional().describe("Asset to withdraw (default: auto-selects largest position)"),
391
395
  dryRun: z.boolean().optional().describe("Preview without signing (default: false)")
392
396
  },
393
- async ({ amount, dryRun }) => {
397
+ async ({ amount, asset, dryRun }) => {
394
398
  try {
395
399
  if (dryRun) {
396
400
  agent.enforcer.assertNotLocked();
397
401
  const positions = await agent.positions();
398
402
  const health = await agent.healthFactor();
399
- const savings = positions.positions.filter((p) => p.type === "save").reduce((sum, p) => sum + p.amount, 0);
403
+ const savings = positions.positions.filter((p) => p.type === "save" && (!asset || p.asset === asset)).reduce((sum, p) => sum + p.amount, 0);
400
404
  return {
401
405
  content: [{
402
406
  type: "text",
403
407
  text: JSON.stringify({
404
408
  preview: true,
405
409
  amount: amount === "all" ? savings : amount,
410
+ asset: asset ?? "auto",
406
411
  currentSavings: savings,
407
412
  currentHealthFactor: health.healthFactor
408
413
  })
409
414
  }]
410
415
  };
411
416
  }
412
- const result = await mutex.run(() => agent.withdraw({ amount }));
417
+ const result = await mutex.run(() => agent.withdraw({ amount, asset }));
413
418
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
414
419
  } catch (err) {
415
420
  return errorResult(err);
@@ -561,6 +566,54 @@ ${text}`;
561
566
  }
562
567
  }
563
568
  );
569
+ server.tool(
570
+ "t2000_swap",
571
+ "Swap tokens on Sui via Cetus Aggregator (20+ DEXs). Supports any token pair with liquidity. Use user-friendly names (SUI, USDC, CETUS, DEEP, etc.) or full coin types.",
572
+ {
573
+ from: z.string().describe('Source token (e.g. "SUI", "USDC", or full coin type)'),
574
+ to: z.string().describe('Target token (e.g. "USDC", "CETUS", or full coin type)'),
575
+ amount: z.number().positive().describe("Amount to swap"),
576
+ slippage: z.number().min(1e-3).max(0.05).optional().describe("Max slippage (default 0.01 = 1%, max 5%)")
577
+ },
578
+ async ({ from, to, amount, slippage }) => {
579
+ try {
580
+ const result = await mutex.run(() => agent.swap({ from, to, amount, slippage }));
581
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
582
+ } catch (err) {
583
+ return errorResult(err);
584
+ }
585
+ }
586
+ );
587
+ server.tool(
588
+ "t2000_stake",
589
+ "Stake SUI for vSUI via VOLO liquid staking. Earn ~3-5% APY. Rewards compound automatically via exchange rate. Minimum 1 SUI.",
590
+ {
591
+ amount: z.number().min(1).describe("Amount of SUI to stake (minimum 1)")
592
+ },
593
+ async ({ amount }) => {
594
+ try {
595
+ const result = await mutex.run(() => agent.stakeVSui({ amount }));
596
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
597
+ } catch (err) {
598
+ return errorResult(err);
599
+ }
600
+ }
601
+ );
602
+ server.tool(
603
+ "t2000_unstake",
604
+ 'Unstake vSUI back to SUI. Returns SUI including accumulated yield. Use amount in vSUI units or "all" to unstake entire position.',
605
+ {
606
+ amount: z.union([z.number().positive(), z.literal("all")]).describe('Amount of vSUI to unstake, or "all"')
607
+ },
608
+ async ({ amount }) => {
609
+ try {
610
+ const result = await mutex.run(() => agent.unstakeVSui({ amount }));
611
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
612
+ } catch (err) {
613
+ return errorResult(err);
614
+ }
615
+ }
616
+ );
564
617
  server.tool(
565
618
  "t2000_contact_add",
566
619
  'Save a contact name \u2192 Sui address mapping. After saving, use the name with t2000_send instead of pasting addresses. Example: save "Tom" as 0x1234... then send to "Tom".',