@tongateway/mcp 0.19.2 → 0.21.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.
Files changed (2) hide show
  1. package/dist/index.js +57 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -209,10 +209,15 @@ server.tool('transfer.request', 'Send a TON transfer. The user approves in their
209
209
  }
210
210
  try {
211
211
  const body = { to, amount };
212
- if (comment)
213
- body.comment = comment;
214
- if (payload)
212
+ // Encode comment as BOC payload using @ton/core
213
+ if (comment && !payload) {
214
+ const { beginCell } = await import('@ton/core');
215
+ const commentCell = beginCell().storeUint(0, 32).storeStringTail(comment).endCell();
216
+ body.payload = commentCell.toBoc().toString('base64');
217
+ }
218
+ else if (payload) {
215
219
  body.payload = payload;
220
+ }
216
221
  if (stateInit)
217
222
  body.stateInit = stateInit;
218
223
  const result = await apiCall('/v1/safe/tx/transfer', {
@@ -316,7 +321,7 @@ server.tool('transfer.pending', 'List all transfer requests waiting for wallet o
316
321
  }
317
322
  });
318
323
  server.tool('transfer.batch', 'Send multiple TON transfers in a SINGLE wallet approval. Up to 4 transfers per batch (v4 wallet). All transfers appear as one transaction to sign. Use for batch payments, multi-recipient sends, or multiple DEX orders at once.', {
319
- transfers: z.string().describe('JSON array of transfers: [{"to":"addr","amountNano":"1000000000","comment":"optional text"},...]'),
324
+ transfers: z.string().describe('JSON array of transfers: [{"to":"addr","amountNano":"1000000000","comment":"optional text","payload":"base64 BOC"},...]. Use payload for custom BOC (e.g. DEX close order), comment for text messages. payload takes precedence over comment.'),
320
325
  }, { title: 'Batch Transfer', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, async ({ transfers: transfersJson }) => {
321
326
  if (!TOKEN) {
322
327
  return { content: [{ type: 'text', text: 'No token configured. Use auth.request first.' }], isError: true };
@@ -327,11 +332,14 @@ server.tool('transfer.batch', 'Send multiple TON transfers in a SINGLE wallet ap
327
332
  throw new Error('No transfers provided');
328
333
  if (transfers.length > 4)
329
334
  throw new Error('Max 4 transfers per batch (v4 wallet). Use agent_wallet.batch_transfer for more.');
330
- // Encode comments as payloads
335
+ // Encode comments as payloads (payload field takes precedence)
331
336
  const processed = [];
332
337
  for (const t of transfers) {
333
338
  const entry = { to: t.to, amountNano: t.amountNano };
334
- if (t.comment) {
339
+ if (t.payload) {
340
+ entry.payload = t.payload;
341
+ }
342
+ else if (t.comment) {
335
343
  const { beginCell } = await import('@ton/core');
336
344
  const commentCell = beginCell().storeUint(0, 32).storeStringTail(t.comment).endCell();
337
345
  entry.payload = commentCell.toBoc().toString('base64');
@@ -354,7 +362,7 @@ server.tool('transfer.batch', 'Send multiple TON transfers in a SINGLE wallet ap
354
362
  `Total: ${totalTon} TON`,
355
363
  `Request ID: ${result.id}`,
356
364
  '',
357
- ...transfers.map((t, i) => ` ${i + 1}. ${t.amountNano} nanoTON → ${t.to.slice(0, 16)}...${t.comment ? ` "${t.comment}"` : ''}`),
365
+ ...transfers.map((t, i) => ` ${i + 1}. ${t.amountNano} nanoTON → ${t.to.slice(0, 16)}...${t.payload ? ' [payload]' : t.comment ? ` "${t.comment}"` : ''}`),
358
366
  '',
359
367
  'Approve in your wallet app — one signature for all transfers.',
360
368
  ].join('\n'),
@@ -495,35 +503,56 @@ server.tool('lookup.price', 'Get the current TON price in USD, EUR, or other cur
495
503
  return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
496
504
  }
497
505
  });
498
- server.tool('dex.create_order', 'Place a limit order on the open4dev DEX order book. Both amount and price are human-readable the API converts to raw units automatically. The order requires wallet approval. Slippage (4% including fees) is applied automatically.', {
499
- fromToken: z.string().describe('Token to sell, e.g. "NOT", "TON", "USDT"'),
500
- toToken: z.string().describe('Token to buy, e.g. "TON", "NOT", "AGNT"'),
501
- amount: z.string().describe('Human-readable amount to sell, e.g. "10000" for 10,000 NOT or "5" for 5 USDT'),
502
- price: z.number().describe('Human-readable price: how many toToken per 1 fromToken. E.g. price=20 means "1 USDT = 20 AGNT". price=0.000289 means "1 NOT = 0.000289 TON".'),
503
- }, { title: 'Create DEX Order', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, async ({ fromToken, toToken, amount, price }) => {
506
+ server.tool('dex.create_order', 'Place one or more limit orders on the open4dev DEX order book. For a single order, provide fromToken/toToken/amount/price directly. For multiple orders, provide an orders array. All orders are batched into one wallet transaction. Both amount and price are human-readable. Slippage (4% including fees) is applied automatically.', {
507
+ fromToken: z.string().optional().describe('Token to sell (single order), e.g. "NOT", "TON", "USDT"'),
508
+ toToken: z.string().optional().describe('Token to buy (single order), e.g. "TON", "NOT", "AGNT"'),
509
+ amount: z.string().optional().describe('Human-readable amount to sell (single order), e.g. "10000"'),
510
+ price: z.number().optional().describe('Human-readable price (single order): how many toToken per 1 fromToken'),
511
+ orders: z.array(z.object({
512
+ fromToken: z.string().describe('Token to sell'),
513
+ toToken: z.string().describe('Token to buy'),
514
+ amount: z.string().describe('Human-readable amount to sell'),
515
+ price: z.number().describe('Human-readable price: how many toToken per 1 fromToken'),
516
+ })).optional().describe('Array of orders for batch creation. If provided, flat params are ignored.'),
517
+ }, { title: 'Create DEX Order', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, async ({ fromToken, toToken, amount, price, orders }) => {
504
518
  if (!TOKEN) {
505
519
  return { content: [{ type: 'text', text: 'No token configured. Use auth.request first.' }], isError: true };
506
520
  }
507
521
  try {
522
+ // Build request body: batch or single
523
+ let requestBody;
524
+ if (orders && orders.length > 0) {
525
+ requestBody = JSON.stringify({ orders });
526
+ }
527
+ else if (fromToken && toToken && amount && price) {
528
+ requestBody = JSON.stringify({ fromToken, toToken, amount, price });
529
+ }
530
+ else {
531
+ return { content: [{ type: 'text', text: 'Provide either orders array or fromToken/toToken/amount/price.' }], isError: true };
532
+ }
508
533
  const result = await apiCall('/v1/dex/order', {
509
534
  method: 'POST',
510
- body: JSON.stringify({ fromToken, toToken, amount, price }),
535
+ body: requestBody,
511
536
  });
537
+ // Format output
538
+ const orderList = result.orders || [result.swap];
539
+ const lines = [];
540
+ if (orderList.length === 1) {
541
+ const s = orderList[0];
542
+ lines.push(`Order placed on open4dev DEX!`, ``, `${s.fromToken} → ${s.toToken}`, `Amount: ${s.amount}`, `Price: ${s.price} ${s.toToken} per ${s.fromToken}`, `Slippage: ${s.slippage ?? 4}% (includes fees)`);
543
+ }
544
+ else {
545
+ lines.push(`${orderList.length} orders placed on open4dev DEX!`, ``);
546
+ for (let i = 0; i < orderList.length; i++) {
547
+ const s = orderList[i];
548
+ lines.push(`Order ${i + 1}: ${s.fromToken} → ${s.toToken} | Amount: ${s.amount} | Price: ${s.price}`);
549
+ }
550
+ lines.push(``);
551
+ lines.push(`Slippage: 4% (includes fees)`);
552
+ }
553
+ lines.push(`Request ID: ${result.id}`, ``, `Approve in your wallet app.`);
512
554
  return {
513
- content: [{
514
- type: 'text',
515
- text: [
516
- `Order placed on open4dev DEX!`,
517
- ``,
518
- `${fromToken} → ${toToken}`,
519
- `Amount: ${amount}`,
520
- `Price: ${price} ${toToken} per ${fromToken}`,
521
- `Slippage: ${result.swap?.slippage ?? 4}% (includes fees)`,
522
- `Request ID: ${result.id}`,
523
- ``,
524
- `Approve the order in your wallet app.`,
525
- ].join('\n'),
526
- }],
555
+ content: [{ type: 'text', text: lines.join('\n') }],
527
556
  };
528
557
  }
529
558
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tongateway/mcp",
3
- "version": "0.19.2",
3
+ "version": "0.21.0",
4
4
  "description": "TON blockchain gateway for AI agents — 16 MCP tools: wallet info, transfers, jettons, NFTs, DNS, prices, DEX orders, agent wallets",
5
5
  "homepage": "https://tongateway.ai",
6
6
  "license": "MIT",