@tongateway/mcp 0.7.0 → 0.9.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 (3) hide show
  1. package/README.md +95 -13
  2. package/dist/index.js +65 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,24 +1,34 @@
1
1
  # @tongateway/mcp
2
2
 
3
- MCP server for [Agent Gateway](https://github.com/pewpewgogo/ton-agent-gateway) — lets AI agents request TON blockchain transfers via Model Context Protocol.
3
+ MCP server for [Agent Gateway](https://tongateway.ai) — gives AI agents full access to the TON blockchain via Model Context Protocol.
4
4
 
5
- ## Install
5
+ **14 tools:** wallet info, jettons, NFTs, transactions, transfers, .ton DNS, prices, agent wallets, and more.
6
+
7
+ ## Quick Start
8
+
9
+ ### Claude Code
6
10
 
7
11
  ```bash
8
- npm install -g @tongateway/mcp
12
+ claude mcp add-json tongateway '{
13
+ "command": "npx",
14
+ "args": ["-y", "@tongateway/mcp"],
15
+ "env": {
16
+ "AGENT_GATEWAY_API_URL": "https://api.tongateway.ai"
17
+ }
18
+ }' --scope user
9
19
  ```
10
20
 
11
- ## Configure
21
+ ### Cursor
12
22
 
13
- Add to your MCP client config (Claude Code, Cursor, etc.):
23
+ Add to Cursor Settings MCP Servers:
14
24
 
15
25
  ```json
16
26
  {
17
27
  "mcpServers": {
18
28
  "tongateway": {
19
- "command": "tongateway-mcp",
29
+ "command": "npx",
30
+ "args": ["-y", "@tongateway/mcp"],
20
31
  "env": {
21
- "AGENT_GATEWAY_TOKEN": "YOUR_TOKEN_HERE",
22
32
  "AGENT_GATEWAY_API_URL": "https://api.tongateway.ai"
23
33
  }
24
34
  }
@@ -26,18 +36,90 @@ Add to your MCP client config (Claude Code, Cursor, etc.):
26
36
  }
27
37
  ```
28
38
 
29
- Get your token at [tongateway.ai/app.html](https://tongateway.ai/app.html).
39
+ ### OpenClaw
40
+
41
+ ```bash
42
+ openclaw config set --strict-json plugins.entries.acpx.config.mcpServers '{
43
+ "tongateway": {
44
+ "command": "npx",
45
+ "args": ["-y", "@tongateway/mcp"],
46
+ "env": {
47
+ "AGENT_GATEWAY_API_URL": "https://api.tongateway.ai"
48
+ }
49
+ }
50
+ }'
51
+ ```
52
+
53
+ No token needed upfront — the agent authenticates via `request_auth` (generates a one-time link, user connects wallet). Token persists in `~/.tongateway/token` across restarts.
30
54
 
31
55
  ## Tools
32
56
 
57
+ ### Auth
58
+
59
+ | Tool | Description |
60
+ |------|-------------|
61
+ | `request_auth` | Generate a one-time link for wallet connection |
62
+ | `get_auth_token` | Retrieve token after user connects wallet |
63
+
64
+ ### Wallet
65
+
33
66
  | Tool | Description |
34
- |---|---|
35
- | `request_transfer` | Request a TON transfer (to, amountNano, payloadBoc?) |
36
- | `get_request_status` | Check status of a request by ID |
67
+ |------|-------------|
68
+ | `get_wallet_info` | Wallet address, TON balance, account status |
69
+ | `get_jetton_balances` | All token balances (USDT, NOT, DOGS, etc.) |
70
+ | `get_transactions` | Recent transaction history |
71
+ | `get_nft_items` | NFTs owned by the wallet |
72
+
73
+ ### Transfers (Safe — requires wallet approval)
74
+
75
+ | Tool | Description |
76
+ |------|-------------|
77
+ | `request_transfer` | Request a TON transfer (to, amountNano, payload?, stateInit?) |
78
+ | `get_request_status` | Check transfer status by ID |
37
79
  | `list_pending_requests` | List all pending requests |
38
80
 
81
+ ### Lookup
82
+
83
+ | Tool | Description |
84
+ |------|-------------|
85
+ | `resolve_name` | Resolve .ton domain to address |
86
+ | `get_ton_price` | Current TON price in USD/EUR |
87
+
88
+ ### Agent Wallet (Autonomous — no approval needed)
89
+
90
+ | Tool | Description |
91
+ |------|-------------|
92
+ | `deploy_agent_wallet` | Deploy a dedicated wallet contract for the agent |
93
+ | `execute_agent_wallet_transfer` | Send TON directly from agent wallet |
94
+ | `get_agent_wallet_info` | Balance, seqno, agent key status |
95
+
96
+ ## How it works
97
+
98
+ ```
99
+ You: "Send 1 TON to alice.ton"
100
+
101
+ Agent: resolve_name("alice.ton") → 0:83df...
102
+ request_transfer(to="0:83df...", amountNano="1000000000")
103
+ → Transfer request created. Approve in your wallet app.
104
+ ```
105
+
106
+ For agent wallets (autonomous mode):
107
+
108
+ ```
109
+ You: "Send 0.5 TON from my agent wallet to 0:abc..."
110
+
111
+ Agent: execute_agent_wallet_transfer(wallet, to, amount)
112
+ → Transfer executed. No approval needed.
113
+ ```
114
+
39
115
  ## Links
40
116
 
41
- - [Agent Gateway](https://github.com/pewpewgogo/ton-agent-gateway) — main repo with all links
42
- - [Dashboard](https://tongateway.ai) — connect wallet & manage tokens
117
+ - [tongateway.ai](https://tongateway.ai) — landing page + install guides
118
+ - [Dashboard](https://tongateway.ai/app.html) — connect wallet & manage tokens
43
119
  - [API Docs](https://api.tongateway.ai/docs) — Swagger UI
120
+ - [Agent Wallet Contract](https://github.com/tongateway/ton-agent-gateway-contract) — FunC smart contract
121
+ - [Skill File](https://tongateway.ai/agent-gateway.md) — context file for AI agents
122
+
123
+ ## License
124
+
125
+ MIT
package/dist/index.js CHANGED
@@ -67,7 +67,7 @@ const server = new McpServer({
67
67
  name: 'agent-gateway',
68
68
  version: '0.1.0',
69
69
  });
70
- server.tool('request_auth', 'Request wallet authentication. Generates a one-time link for the user to connect their TON wallet. After the user connects, use get_auth_token to retrieve the token. Use this when no token is configured.', {
70
+ server.tool('request_auth', 'Authenticate with TON blockchain. Call this FIRST if you get "No token configured" errors. Generates a one-time link ask the user to open it and connect their wallet. Then call get_auth_token to complete. Token persists across restarts.', {
71
71
  label: z.string().optional().describe('Label for this agent session (e.g. "claude-agent")'),
72
72
  }, async ({ label }) => {
73
73
  try {
@@ -105,7 +105,7 @@ server.tool('request_auth', 'Request wallet authentication. Generates a one-time
105
105
  };
106
106
  }
107
107
  });
108
- server.tool('get_auth_token', 'Check if the user has completed wallet authentication and retrieve the token. Call this after request_auth once the user has opened the link and connected their wallet.', {
108
+ server.tool('get_auth_token', 'Complete authentication after the user opened the link from request_auth. Pass the authId you received. Once successful, all other tools become available. You only need to authenticate once — the token is saved automatically.', {
109
109
  authId: z.string().describe('The authId returned by request_auth'),
110
110
  }, async ({ authId }) => {
111
111
  try {
@@ -155,7 +155,7 @@ server.tool('get_auth_token', 'Check if the user has completed wallet authentica
155
155
  };
156
156
  }
157
157
  });
158
- server.tool('request_transfer', 'Request a TON transfer from the wallet owner. The request will be queued and the owner must approve it via TON Connect.', {
158
+ server.tool('request_transfer', 'Request a TON transfer. The user must approve it in their wallet app. Amount is in nanoTON (1 TON = 1000000000). Supports optional payload (BOC) and stateInit (for contract deployment). The transfer is queued — use get_request_status to check if approved.', {
159
159
  to: z.string().describe('Destination TON address'),
160
160
  amountNano: z.string().describe('Amount in nanoTON (1 TON = 1000000000)'),
161
161
  payload: z.string().optional().describe('Optional BOC-encoded payload for the transaction'),
@@ -202,7 +202,7 @@ server.tool('request_transfer', 'Request a TON transfer from the wallet owner. T
202
202
  };
203
203
  }
204
204
  });
205
- server.tool('get_request_status', 'Check the status of a previously submitted transfer request.', {
205
+ server.tool('get_request_status', 'Check the status of a transfer request. Statuses: pending (waiting for approval), confirmed (signed and broadcast), rejected (user declined), expired (5 min timeout). Also shows broadcast result if available.', {
206
206
  id: z.string().describe('The request ID returned by request_transfer'),
207
207
  }, async ({ id }) => {
208
208
  if (!TOKEN) {
@@ -241,7 +241,7 @@ server.tool('get_request_status', 'Check the status of a previously submitted tr
241
241
  };
242
242
  }
243
243
  });
244
- server.tool('list_pending_requests', 'List all pending transfer requests waiting for wallet owner approval.', {}, async () => {
244
+ server.tool('list_pending_requests', 'List all transfer requests waiting for wallet owner approval. Use to check if there are unfinished transfers.', {}, async () => {
245
245
  if (!TOKEN) {
246
246
  return {
247
247
  content: [{ type: 'text', text: 'No token configured. Use request_auth first to authenticate.' }],
@@ -273,7 +273,7 @@ server.tool('list_pending_requests', 'List all pending transfer requests waiting
273
273
  };
274
274
  }
275
275
  });
276
- server.tool('get_wallet_info', 'Get the connected wallet address, TON balance, and account status.', {}, async () => {
276
+ server.tool('get_wallet_info', 'Get the connected wallet address, TON balance (in nanoTON and TON), and account status. Use this to check how much TON the user has before sending transfers.', {}, async () => {
277
277
  if (!TOKEN) {
278
278
  return { content: [{ type: 'text', text: 'No token configured. Use request_auth first.' }], isError: true };
279
279
  }
@@ -296,7 +296,7 @@ server.tool('get_wallet_info', 'Get the connected wallet address, TON balance, a
296
296
  return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
297
297
  }
298
298
  });
299
- server.tool('get_jetton_balances', 'Get all jetton (token) balances in the connected wallet. Shows USDT, NOT, DOGS, and other tokens.', {}, async () => {
299
+ server.tool('get_jetton_balances', 'List all tokens (jettons) in the wallet USDT, NOT, DOGS, and others. Shows symbol, name, balance, and decimals for each. Use this when the user asks about their tokens or wants to know what they hold.', {}, async () => {
300
300
  if (!TOKEN) {
301
301
  return { content: [{ type: 'text', text: 'No token configured. Use request_auth first.' }], isError: true };
302
302
  }
@@ -321,7 +321,7 @@ server.tool('get_jetton_balances', 'Get all jetton (token) balances in the conne
321
321
  return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
322
322
  }
323
323
  });
324
- server.tool('get_transactions', 'Get recent transaction history for the connected wallet.', {
324
+ server.tool('get_transactions', 'Get recent transaction history. Shows timestamps, action types, and whether transactions were flagged as scam. Use when the user asks "what happened" or wants to review recent activity.', {
325
325
  limit: z.number().optional().describe('Number of transactions to return (default 10)'),
326
326
  }, async ({ limit }) => {
327
327
  if (!TOKEN) {
@@ -346,7 +346,7 @@ server.tool('get_transactions', 'Get recent transaction history for the connecte
346
346
  return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
347
347
  }
348
348
  });
349
- server.tool('get_nft_items', 'List NFTs owned by the connected wallet.', {}, async () => {
349
+ server.tool('get_nft_items', 'List all NFTs owned by the wallet — name, collection, and address for each. Use when the user asks about their NFTs or collectibles.', {}, async () => {
350
350
  if (!TOKEN) {
351
351
  return { content: [{ type: 'text', text: 'No token configured. Use request_auth first.' }], isError: true };
352
352
  }
@@ -365,7 +365,7 @@ server.tool('get_nft_items', 'List NFTs owned by the connected wallet.', {}, asy
365
365
  return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
366
366
  }
367
367
  });
368
- server.tool('resolve_name', 'Resolve a .ton domain name to a wallet address. Use this when the user says "send to alice.ton" instead of a raw address.', {
368
+ server.tool('resolve_name', 'Resolve a .ton domain name (like "alice.ton") to a raw wallet address. ALWAYS use this before request_transfer when the user gives a .ton name instead of a raw address.', {
369
369
  domain: z.string().describe('The .ton domain name to resolve (e.g. "alice.ton")'),
370
370
  }, async ({ domain }) => {
371
371
  try {
@@ -384,7 +384,7 @@ server.tool('resolve_name', 'Resolve a .ton domain name to a wallet address. Use
384
384
  return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
385
385
  }
386
386
  });
387
- server.tool('get_ton_price', 'Get the current price of TON in USD and other currencies.', {
387
+ server.tool('get_ton_price', 'Get the current TON price in USD, EUR, or other currencies. Use when the user asks "how much is my TON worth" or before transfers to show USD equivalents.', {
388
388
  currencies: z.string().optional().describe('Comma-separated currencies (default "USD")'),
389
389
  }, async ({ currencies }) => {
390
390
  try {
@@ -403,7 +403,58 @@ server.tool('get_ton_price', 'Get the current price of TON in USD and other curr
403
403
  return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
404
404
  }
405
405
  });
406
- server.tool('deploy_agent_wallet', 'Deploy a new Agent Wallet smart contract. This creates an autonomous wallet that the agent can use to send TON without requiring approval for each transaction. DANGER: funds in this wallet can be spent by the agent without approval.', {}, async () => {
406
+ server.tool('create_swap_order', 'Swap tokens on the open4dev DEX. Provide the token pair (e.g. NOT→TON), amount, and price. The order is created as a safe transfer the user approves it in their wallet. Use get_ton_price or get_jetton_balances to determine current rates before swapping.', {
407
+ fromToken: z.string().describe('Token to sell, e.g. "NOT", "TON", "USDT"'),
408
+ toToken: z.string().describe('Token to buy, e.g. "TON", "NOT"'),
409
+ amount: z.string().describe('Amount to sell in smallest unit (nanoTON for TON, or raw jetton amount based on decimals)'),
410
+ priceRateNano: z.string().describe('Price rate in nanoTON per unit'),
411
+ }, async ({ fromToken, toToken, amount, priceRateNano }) => {
412
+ if (!TOKEN) {
413
+ return { content: [{ type: 'text', text: 'No token configured. Use request_auth first.' }], isError: true };
414
+ }
415
+ try {
416
+ const result = await apiCall('/v1/dex/swap', {
417
+ method: 'POST',
418
+ body: JSON.stringify({ fromToken, toToken, amount, priceRateNano }),
419
+ });
420
+ return {
421
+ content: [{
422
+ type: 'text',
423
+ text: [
424
+ `Swap order created!`,
425
+ ``,
426
+ `${fromToken} → ${toToken}`,
427
+ `Amount: ${amount}`,
428
+ `Price Rate: ${priceRateNano} nanoTON`,
429
+ `Pool: ${result.swap?.pool || 'unknown'}`,
430
+ `Request ID: ${result.id}`,
431
+ ``,
432
+ `Approve the swap in your wallet app.`,
433
+ ].join('\n'),
434
+ }],
435
+ };
436
+ }
437
+ catch (e) {
438
+ return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
439
+ }
440
+ });
441
+ server.tool('list_dex_pools', 'List available trading pairs on the DEX. Shows which token swaps are configured and available.', {}, async () => {
442
+ try {
443
+ const result = await fetch(`${API_URL}/v1/dex/pools`);
444
+ const data = await result.json();
445
+ if (!data.pools?.length) {
446
+ return { content: [{ type: 'text', text: 'No DEX pools configured yet.' }] };
447
+ }
448
+ const lines = data.pools.map((p) => `- ${p.pair} (${p.direction})`);
449
+ return {
450
+ content: [{ type: 'text', text: `Available pools:\n${lines.join('\n')}` }],
451
+ };
452
+ }
453
+ catch (e) {
454
+ return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
455
+ }
456
+ });
457
+ server.tool('deploy_agent_wallet', 'Deploy an Agent Wallet smart contract — a dedicated sub-wallet for autonomous operations. WARNING: The agent can spend funds from this wallet WITHOUT user approval. Only deploy if the user explicitly wants autonomous transfers. After deployment, top up the wallet with funds.', {}, async () => {
407
458
  if (!TOKEN) {
408
459
  return { content: [{ type: 'text', text: 'No token configured. Use request_auth first.' }], isError: true };
409
460
  }
@@ -486,7 +537,7 @@ server.tool('deploy_agent_wallet', 'Deploy a new Agent Wallet smart contract. Th
486
537
  return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
487
538
  }
488
539
  });
489
- server.tool('execute_agent_wallet_transfer', 'Send TON directly from an Agent Wallet. No approval needed the agent signs and broadcasts immediately. Only works with deployed agent wallets where the agent key is set.', {
540
+ server.tool('execute_agent_wallet_transfer', 'Send TON directly from an Agent Wallet NO approval needed. The agent signs and broadcasts immediately. Only works with deployed agent wallets. Use for automated/autonomous transfers where speed matters and the user has opted in.', {
490
541
  walletAddress: z.string().describe('The agent wallet contract address'),
491
542
  to: z.string().describe('Destination TON address'),
492
543
  amountNano: z.string().describe('Amount in nanoTON'),
@@ -583,7 +634,7 @@ server.tool('execute_agent_wallet_transfer', 'Send TON directly from an Agent Wa
583
634
  return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
584
635
  }
585
636
  });
586
- server.tool('get_agent_wallet_info', 'Get info about an Agent Wallet — balance, seqno, agent key status.', {
637
+ server.tool('get_agent_wallet_info', 'Get info about Agent Wallets — balance, seqno, agent key status. Pass a wallet address for details, or omit to list all agent wallets.', {
587
638
  walletAddress: z.string().optional().describe('Agent wallet address. If omitted, lists all your agent wallets.'),
588
639
  }, async ({ walletAddress }) => {
589
640
  if (!TOKEN) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tongateway/mcp",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "MCP server for Agent Gateway — lets AI agents request TON blockchain transfers",
5
5
  "license": "MIT",
6
6
  "repository": {