@sun-protocol/tron-mcp-server 1.0.0-beta.1

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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +282 -0
  3. package/bin/cli.js +51 -0
  4. package/build/core/chains.d.ts +17 -0
  5. package/build/core/chains.js +55 -0
  6. package/build/core/chains.js.map +1 -0
  7. package/build/core/prompts.d.ts +16 -0
  8. package/build/core/prompts.js +268 -0
  9. package/build/core/prompts.js.map +1 -0
  10. package/build/core/resources.d.ts +14 -0
  11. package/build/core/resources.js +42 -0
  12. package/build/core/resources.js.map +1 -0
  13. package/build/core/services/address.d.ts +8 -0
  14. package/build/core/services/address.js +52 -0
  15. package/build/core/services/address.js.map +1 -0
  16. package/build/core/services/balance.d.ts +26 -0
  17. package/build/core/services/balance.js +60 -0
  18. package/build/core/services/balance.js.map +1 -0
  19. package/build/core/services/blocks.d.ts +16 -0
  20. package/build/core/services/blocks.js +46 -0
  21. package/build/core/services/blocks.js.map +1 -0
  22. package/build/core/services/clients.d.ts +9 -0
  23. package/build/core/services/clients.js +46 -0
  24. package/build/core/services/clients.js.map +1 -0
  25. package/build/core/services/contracts.d.ts +50 -0
  26. package/build/core/services/contracts.js +225 -0
  27. package/build/core/services/contracts.js.map +1 -0
  28. package/build/core/services/index.d.ts +119 -0
  29. package/build/core/services/index.js +39 -0
  30. package/build/core/services/index.js.map +1 -0
  31. package/build/core/services/multicall-abi.d.ts +55 -0
  32. package/build/core/services/multicall-abi.js +61 -0
  33. package/build/core/services/multicall-abi.js.map +1 -0
  34. package/build/core/services/tokens.d.ts +22 -0
  35. package/build/core/services/tokens.js +68 -0
  36. package/build/core/services/tokens.js.map +1 -0
  37. package/build/core/services/transactions.d.ts +16 -0
  38. package/build/core/services/transactions.js +42 -0
  39. package/build/core/services/transactions.js.map +1 -0
  40. package/build/core/services/transfer.d.ts +24 -0
  41. package/build/core/services/transfer.js +70 -0
  42. package/build/core/services/transfer.js.map +1 -0
  43. package/build/core/services/utils.d.ts +13 -0
  44. package/build/core/services/utils.js +39 -0
  45. package/build/core/services/utils.js.map +1 -0
  46. package/build/core/services/wallet.d.ts +33 -0
  47. package/build/core/services/wallet.js +113 -0
  48. package/build/core/services/wallet.js.map +1 -0
  49. package/build/core/tools.d.ts +16 -0
  50. package/build/core/tools.js +792 -0
  51. package/build/core/tools.js.map +1 -0
  52. package/build/index.d.ts +1 -0
  53. package/build/index.js +20 -0
  54. package/build/index.js.map +1 -0
  55. package/build/server/http-server.d.ts +1 -0
  56. package/build/server/http-server.js +197 -0
  57. package/build/server/http-server.js.map +1 -0
  58. package/build/server/server.d.ts +3 -0
  59. package/build/server/server.js +46 -0
  60. package/build/server/server.js.map +1 -0
  61. package/package.json +90 -0
@@ -0,0 +1,792 @@
1
+ import { z } from "zod";
2
+ import { getSupportedNetworks, getRpcUrl } from "./chains.js";
3
+ import * as services from "./services/index.js";
4
+ /**
5
+ * Register all TRON-related tools with the MCP server
6
+ *
7
+ * SECURITY: Either TRON_PRIVATE_KEY or TRON_MNEMONIC environment variable must be set for write operations.
8
+ * Private keys and mnemonics are never passed as tool arguments for security reasons.
9
+ * Tools will use the configured wallet for all transactions.
10
+ *
11
+ * Configuration options:
12
+ * - TRON_PRIVATE_KEY: Hex private key (with or without 0x prefix)
13
+ * - TRON_MNEMONIC: BIP-39 mnemonic phrase (12 or 24 words)
14
+ * - TRON_ACCOUNT_INDEX: Optional account index for HD wallet derivation (default: 0)
15
+ *
16
+ * @param server The MCP server instance
17
+ */
18
+ export function registerTRONTools(server) {
19
+ // Helpers are now imported from services/wallet.ts
20
+ const { getConfiguredPrivateKey, getWalletAddressFromKey } = services;
21
+ // ============================================================================
22
+ // WALLET INFORMATION TOOLS (Read-only)
23
+ // ============================================================================
24
+ server.registerTool("get_wallet_address", {
25
+ description: "Get the address of the configured wallet. Use this to verify which wallet is active.",
26
+ inputSchema: {},
27
+ annotations: {
28
+ title: "Get Wallet Address",
29
+ readOnlyHint: true,
30
+ destructiveHint: false,
31
+ idempotentHint: true,
32
+ openWorldHint: false,
33
+ },
34
+ }, async () => {
35
+ try {
36
+ const address = getWalletAddressFromKey();
37
+ return {
38
+ content: [
39
+ {
40
+ type: "text",
41
+ text: JSON.stringify({
42
+ address,
43
+ base58: services.toBase58Address(address),
44
+ hex: services.toHexAddress(address),
45
+ message: "This is the wallet that will be used for all transactions",
46
+ }, null, 2),
47
+ },
48
+ ],
49
+ };
50
+ }
51
+ catch (error) {
52
+ return {
53
+ content: [
54
+ {
55
+ type: "text",
56
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
57
+ },
58
+ ],
59
+ isError: true,
60
+ };
61
+ }
62
+ });
63
+ // ============================================================================
64
+ // NETWORK INFORMATION TOOLS (Read-only)
65
+ // ============================================================================
66
+ server.registerTool("get_chain_info", {
67
+ description: "Get information about a TRON network: current block number and RPC endpoint",
68
+ inputSchema: {
69
+ network: z
70
+ .string()
71
+ .optional()
72
+ .describe("Network name (mainnet, nile, shasta). Defaults to mainnet."),
73
+ },
74
+ annotations: {
75
+ title: "Get Chain Info",
76
+ readOnlyHint: true,
77
+ destructiveHint: false,
78
+ idempotentHint: true,
79
+ openWorldHint: true,
80
+ },
81
+ }, async ({ network = "mainnet" }) => {
82
+ try {
83
+ const chainId = await services.getChainId(network);
84
+ const blockNumber = await services.getBlockNumber(network);
85
+ const rpcUrl = getRpcUrl(network);
86
+ return {
87
+ content: [
88
+ {
89
+ type: "text",
90
+ text: JSON.stringify({ network, chainId, blockNumber: blockNumber.toString(), rpcUrl }, null, 2),
91
+ },
92
+ ],
93
+ };
94
+ }
95
+ catch (error) {
96
+ return {
97
+ content: [
98
+ {
99
+ type: "text",
100
+ text: `Error fetching chain info: ${error instanceof Error ? error.message : String(error)}`,
101
+ },
102
+ ],
103
+ isError: true,
104
+ };
105
+ }
106
+ });
107
+ server.registerTool("get_supported_networks", {
108
+ description: "Get a list of all supported TRON networks",
109
+ inputSchema: {},
110
+ annotations: {
111
+ title: "Get Supported Networks",
112
+ readOnlyHint: true,
113
+ destructiveHint: false,
114
+ idempotentHint: true,
115
+ openWorldHint: false,
116
+ },
117
+ }, async () => {
118
+ try {
119
+ const networks = getSupportedNetworks();
120
+ return {
121
+ content: [
122
+ { type: "text", text: JSON.stringify({ supportedNetworks: networks }, null, 2) },
123
+ ],
124
+ };
125
+ }
126
+ catch (error) {
127
+ return {
128
+ content: [
129
+ {
130
+ type: "text",
131
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
132
+ },
133
+ ],
134
+ isError: true,
135
+ };
136
+ }
137
+ });
138
+ server.registerTool("get_chain_parameters", {
139
+ description: "Get current chain parameters including Energy and Bandwidth unit prices. Returns structured fee information similar to gas price queries.",
140
+ inputSchema: {
141
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
142
+ },
143
+ annotations: {
144
+ title: "Get Chain Parameters",
145
+ readOnlyHint: true,
146
+ destructiveHint: false,
147
+ idempotentHint: false,
148
+ openWorldHint: true,
149
+ },
150
+ }, async ({ network = "mainnet" }) => {
151
+ try {
152
+ const tronWeb = services.getTronWeb(network);
153
+ const parameters = await tronWeb.trx.getChainParameters();
154
+ const paramMap = new Map();
155
+ for (const param of parameters) {
156
+ if (param.key) {
157
+ paramMap.set(param.key, param.value);
158
+ }
159
+ }
160
+ const result = {
161
+ network,
162
+ energy_price_sun: paramMap.get("getEnergyFee"), // Energy unit price (sun per unit)
163
+ bandwidth_price_sun: paramMap.get("getTransactionFee"), // Bandwidth unit price (sun per byte)
164
+ all_parameters: parameters,
165
+ };
166
+ return {
167
+ content: [
168
+ {
169
+ type: "text",
170
+ text: JSON.stringify(result, null, 2),
171
+ },
172
+ ],
173
+ };
174
+ }
175
+ catch (error) {
176
+ return {
177
+ content: [
178
+ {
179
+ type: "text",
180
+ text: `Error fetching chain parameters: ${error instanceof Error ? error.message : String(error)}`,
181
+ },
182
+ ],
183
+ isError: true,
184
+ };
185
+ }
186
+ });
187
+ // ============================================================================
188
+ // ADDRESS TOOLS (Read-only)
189
+ // ============================================================================
190
+ server.registerTool("convert_address", {
191
+ description: "Convert addresses between Hex and Base58 formats",
192
+ inputSchema: {
193
+ address: z.string().describe("Address to convert (Hex or Base58)"),
194
+ },
195
+ annotations: {
196
+ title: "Convert Address",
197
+ readOnlyHint: true,
198
+ destructiveHint: false,
199
+ idempotentHint: true,
200
+ openWorldHint: true,
201
+ },
202
+ }, async ({ address }) => {
203
+ try {
204
+ return {
205
+ content: [
206
+ {
207
+ type: "text",
208
+ text: JSON.stringify({
209
+ original: address,
210
+ base58: services.toBase58Address(address),
211
+ hex: services.toHexAddress(address),
212
+ isValid: services.utils.isAddress(address),
213
+ }, null, 2),
214
+ },
215
+ ],
216
+ };
217
+ }
218
+ catch (error) {
219
+ return {
220
+ content: [
221
+ {
222
+ type: "text",
223
+ text: `Error converting address: ${error instanceof Error ? error.message : String(error)}`,
224
+ },
225
+ ],
226
+ isError: true,
227
+ };
228
+ }
229
+ });
230
+ // ============================================================================
231
+ // BLOCK TOOLS (Read-only)
232
+ // ============================================================================
233
+ server.registerTool("get_block", {
234
+ description: "Get block details by block number or hash",
235
+ inputSchema: {
236
+ blockIdentifier: z.string().describe("Block number (as string) or block hash"),
237
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
238
+ },
239
+ annotations: {
240
+ title: "Get Block",
241
+ readOnlyHint: true,
242
+ destructiveHint: false,
243
+ idempotentHint: true,
244
+ openWorldHint: true,
245
+ },
246
+ }, async ({ blockIdentifier, network = "mainnet" }) => {
247
+ try {
248
+ let block;
249
+ // Check if it's a hash (hex string usually 64 chars + prefix) or number
250
+ if (blockIdentifier.startsWith("0x") ||
251
+ (blockIdentifier.length > 20 && isNaN(Number(blockIdentifier)))) {
252
+ // Assume hash
253
+ block = await services.getBlockByHash(blockIdentifier, network);
254
+ }
255
+ else {
256
+ // Assume number
257
+ block = await services.getBlockByNumber(parseInt(blockIdentifier), network);
258
+ }
259
+ return { content: [{ type: "text", text: services.helpers.formatJson(block) }] };
260
+ }
261
+ catch (error) {
262
+ return {
263
+ content: [
264
+ {
265
+ type: "text",
266
+ text: `Error fetching block: ${error instanceof Error ? error.message : String(error)}`,
267
+ },
268
+ ],
269
+ isError: true,
270
+ };
271
+ }
272
+ });
273
+ server.registerTool("get_latest_block", {
274
+ description: "Get the latest block from the network",
275
+ inputSchema: {
276
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
277
+ },
278
+ annotations: {
279
+ title: "Get Latest Block",
280
+ readOnlyHint: true,
281
+ destructiveHint: false,
282
+ idempotentHint: false,
283
+ openWorldHint: true,
284
+ },
285
+ }, async ({ network = "mainnet" }) => {
286
+ try {
287
+ const block = await services.getLatestBlock(network);
288
+ return { content: [{ type: "text", text: services.helpers.formatJson(block) }] };
289
+ }
290
+ catch (error) {
291
+ return {
292
+ content: [
293
+ {
294
+ type: "text",
295
+ text: `Error fetching latest block: ${error instanceof Error ? error.message : String(error)}`,
296
+ },
297
+ ],
298
+ isError: true,
299
+ };
300
+ }
301
+ });
302
+ // ============================================================================
303
+ // BALANCE TOOLS (Read-only)
304
+ // ============================================================================
305
+ server.registerTool("get_balance", {
306
+ description: "Get the TRX balance for an address",
307
+ inputSchema: {
308
+ address: z.string().describe("The wallet address (Base58)"),
309
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
310
+ },
311
+ annotations: {
312
+ title: "Get TRX Balance",
313
+ readOnlyHint: true,
314
+ destructiveHint: false,
315
+ idempotentHint: true,
316
+ openWorldHint: true,
317
+ },
318
+ }, async ({ address, network = "mainnet" }) => {
319
+ try {
320
+ const balance = await services.getTRXBalance(address, network);
321
+ return {
322
+ content: [
323
+ {
324
+ type: "text",
325
+ text: JSON.stringify({
326
+ network,
327
+ address,
328
+ balance: { sun: balance.wei.toString(), trx: balance.formatted },
329
+ }, null, 2),
330
+ },
331
+ ],
332
+ };
333
+ }
334
+ catch (error) {
335
+ return {
336
+ content: [
337
+ {
338
+ type: "text",
339
+ text: `Error fetching balance: ${error instanceof Error ? error.message : String(error)}`,
340
+ },
341
+ ],
342
+ isError: true,
343
+ };
344
+ }
345
+ });
346
+ server.registerTool("get_token_balance", {
347
+ description: "Get the TRC20 token balance for an address",
348
+ inputSchema: {
349
+ address: z.string().describe("The wallet address"),
350
+ tokenAddress: z.string().describe("The TRC20 token contract address"),
351
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
352
+ },
353
+ annotations: {
354
+ title: "Get TRC20 Token Balance",
355
+ readOnlyHint: true,
356
+ destructiveHint: false,
357
+ idempotentHint: true,
358
+ openWorldHint: true,
359
+ },
360
+ }, async ({ address, tokenAddress, network = "mainnet" }) => {
361
+ try {
362
+ const balance = await services.getTRC20Balance(tokenAddress, address, network);
363
+ return {
364
+ content: [
365
+ {
366
+ type: "text",
367
+ text: JSON.stringify({
368
+ network,
369
+ tokenAddress,
370
+ address,
371
+ balance: {
372
+ raw: balance.raw.toString(),
373
+ formatted: balance.formatted,
374
+ symbol: balance.token.symbol,
375
+ decimals: balance.token.decimals,
376
+ },
377
+ }, null, 2),
378
+ },
379
+ ],
380
+ };
381
+ }
382
+ catch (error) {
383
+ return {
384
+ content: [
385
+ {
386
+ type: "text",
387
+ text: `Error fetching token balance: ${error instanceof Error ? error.message : String(error)}`,
388
+ },
389
+ ],
390
+ isError: true,
391
+ };
392
+ }
393
+ });
394
+ // ============================================================================
395
+ // TRANSACTION TOOLS (Read-only)
396
+ // ============================================================================
397
+ server.registerTool("get_transaction", {
398
+ description: "Get transaction details by transaction hash",
399
+ inputSchema: {
400
+ txHash: z.string().describe("Transaction hash"),
401
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
402
+ },
403
+ annotations: {
404
+ title: "Get Transaction",
405
+ readOnlyHint: true,
406
+ destructiveHint: false,
407
+ idempotentHint: true,
408
+ openWorldHint: true,
409
+ },
410
+ }, async ({ txHash, network = "mainnet" }) => {
411
+ try {
412
+ const tx = await services.getTransaction(txHash, network);
413
+ return { content: [{ type: "text", text: services.helpers.formatJson(tx) }] };
414
+ }
415
+ catch (error) {
416
+ return {
417
+ content: [
418
+ {
419
+ type: "text",
420
+ text: `Error fetching transaction: ${error instanceof Error ? error.message : String(error)}`,
421
+ },
422
+ ],
423
+ isError: true,
424
+ };
425
+ }
426
+ });
427
+ server.registerTool("get_transaction_info", {
428
+ description: "Get transaction info (receipt/confirmation status, energy usage, logs).",
429
+ inputSchema: {
430
+ txHash: z.string().describe("Transaction hash"),
431
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
432
+ },
433
+ annotations: {
434
+ title: "Get Transaction Info",
435
+ readOnlyHint: true,
436
+ destructiveHint: false,
437
+ idempotentHint: true,
438
+ openWorldHint: true,
439
+ },
440
+ }, async ({ txHash, network = "mainnet" }) => {
441
+ try {
442
+ const info = await services.getTransactionInfo(txHash, network);
443
+ return { content: [{ type: "text", text: services.helpers.formatJson(info) }] };
444
+ }
445
+ catch (error) {
446
+ return {
447
+ content: [
448
+ {
449
+ type: "text",
450
+ text: `Error fetching transaction info: ${error instanceof Error ? error.message : String(error)}`,
451
+ },
452
+ ],
453
+ isError: true,
454
+ };
455
+ }
456
+ });
457
+ // ============================================================================
458
+ // SMART CONTRACT TOOLS
459
+ // ============================================================================
460
+ server.registerTool("read_contract", {
461
+ description: "Call read-only functions on a smart contract.",
462
+ inputSchema: {
463
+ contractAddress: z.string().describe("The contract address"),
464
+ functionName: z.string().describe("Function name (e.g., 'name', 'symbol', 'balanceOf')"),
465
+ args: z
466
+ .array(z.union([z.string(), z.number(), z.boolean()]))
467
+ .optional()
468
+ .describe("Function arguments"),
469
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
470
+ },
471
+ annotations: {
472
+ title: "Read Smart Contract",
473
+ readOnlyHint: true,
474
+ destructiveHint: false,
475
+ idempotentHint: true,
476
+ openWorldHint: true,
477
+ },
478
+ }, async ({ contractAddress, functionName, args = [], network = "mainnet" }) => {
479
+ try {
480
+ const result = await services.readContract({
481
+ address: contractAddress,
482
+ functionName,
483
+ args,
484
+ }, network);
485
+ return {
486
+ content: [
487
+ {
488
+ type: "text",
489
+ text: services.helpers.formatJson({
490
+ contractAddress,
491
+ function: functionName,
492
+ args: args.length > 0 ? args : undefined,
493
+ result,
494
+ }),
495
+ },
496
+ ],
497
+ };
498
+ }
499
+ catch (error) {
500
+ return {
501
+ content: [
502
+ {
503
+ type: "text",
504
+ text: `Error reading contract: ${error instanceof Error ? error.message : String(error)}`,
505
+ },
506
+ ],
507
+ isError: true,
508
+ };
509
+ }
510
+ });
511
+ server.registerTool("multicall", {
512
+ description: "Execute multiple read-only functions in a single batch call.",
513
+ inputSchema: {
514
+ calls: z
515
+ .array(z.object({
516
+ address: z.string().describe("Target contract address"),
517
+ functionName: z.string().describe("Function name"),
518
+ args: z
519
+ .array(z.union([z.string(), z.number(), z.boolean()]))
520
+ .optional()
521
+ .describe("Function arguments"),
522
+ abi: z
523
+ .array(z.object({}).passthrough())
524
+ .describe("Function ABI (required for multicall)"),
525
+ allowFailure: z
526
+ .boolean()
527
+ .optional()
528
+ .describe("Whether to allow this specific call to fail"),
529
+ }))
530
+ .describe("Array of calls to execute"),
531
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
532
+ multicallAddress: z
533
+ .string()
534
+ .optional()
535
+ .describe("Optional Multicall contract address override"),
536
+ version: z
537
+ .enum(["2", "3"])
538
+ .optional()
539
+ .describe("Multicall version (2 or 3). Defaults to 3."),
540
+ allowFailure: z
541
+ .boolean()
542
+ .optional()
543
+ .describe("Whether to allow individual calls to fail. Defaults to true."),
544
+ },
545
+ annotations: {
546
+ title: "Multicall",
547
+ readOnlyHint: true,
548
+ destructiveHint: false,
549
+ idempotentHint: true,
550
+ openWorldHint: true,
551
+ },
552
+ }, async ({ calls, network = "mainnet", multicallAddress, version: versionArg, allowFailure = true, }) => {
553
+ try {
554
+ const version = versionArg ? parseInt(versionArg) : 3;
555
+ const results = await services.multicall({
556
+ calls,
557
+ multicallAddress,
558
+ version: version,
559
+ allowFailure,
560
+ }, network);
561
+ return {
562
+ content: [
563
+ {
564
+ type: "text",
565
+ text: services.helpers.formatJson({
566
+ network,
567
+ count: calls.length,
568
+ results,
569
+ }),
570
+ },
571
+ ],
572
+ };
573
+ }
574
+ catch (error) {
575
+ return {
576
+ content: [
577
+ {
578
+ type: "text",
579
+ text: `Error executing multicall: ${error instanceof Error ? error.message : String(error)}`,
580
+ },
581
+ ],
582
+ isError: true,
583
+ };
584
+ }
585
+ });
586
+ server.registerTool("write_contract", {
587
+ description: "Execute state-changing functions on a smart contract. Requires configured wallet.",
588
+ inputSchema: {
589
+ contractAddress: z.string().describe("The contract address"),
590
+ functionName: z.string().describe("Function name to call"),
591
+ args: z
592
+ .array(z.union([z.string(), z.number(), z.boolean()]))
593
+ .optional()
594
+ .describe("Function arguments"),
595
+ value: z.string().optional().describe("TRX value to send (in Sun)"),
596
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
597
+ },
598
+ annotations: {
599
+ title: "Write to Smart Contract",
600
+ readOnlyHint: false,
601
+ destructiveHint: true,
602
+ idempotentHint: false,
603
+ openWorldHint: true,
604
+ },
605
+ }, async ({ contractAddress, functionName, args = [], value, network = "mainnet" }) => {
606
+ try {
607
+ const privateKey = getConfiguredPrivateKey();
608
+ const senderAddress = getWalletAddressFromKey();
609
+ const txHash = await services.writeContract(privateKey, {
610
+ address: contractAddress,
611
+ functionName,
612
+ args,
613
+ value,
614
+ }, network);
615
+ return {
616
+ content: [
617
+ {
618
+ type: "text",
619
+ text: JSON.stringify({
620
+ network,
621
+ contractAddress,
622
+ function: functionName,
623
+ args: args.length > 0 ? args : undefined,
624
+ value: value || undefined,
625
+ from: senderAddress,
626
+ txHash,
627
+ message: "Transaction sent. Use get_transaction_info to check confirmation.",
628
+ }, null, 2),
629
+ },
630
+ ],
631
+ };
632
+ }
633
+ catch (error) {
634
+ return {
635
+ content: [
636
+ {
637
+ type: "text",
638
+ text: `Error writing to contract: ${error instanceof Error ? error.message : String(error)}`,
639
+ },
640
+ ],
641
+ isError: true,
642
+ };
643
+ }
644
+ });
645
+ // ============================================================================
646
+ // TRANSFER TOOLS (Write operations)
647
+ // ============================================================================
648
+ server.registerTool("transfer_trx", {
649
+ description: "Transfer TRX to an address.",
650
+ inputSchema: {
651
+ to: z.string().describe("Recipient address"),
652
+ amount: z.string().describe("Amount to send in TRX (e.g., '10.5')"),
653
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
654
+ },
655
+ annotations: {
656
+ title: "Transfer TRX",
657
+ readOnlyHint: false,
658
+ destructiveHint: true,
659
+ idempotentHint: false,
660
+ openWorldHint: true,
661
+ },
662
+ }, async ({ to, amount, network = "mainnet" }) => {
663
+ try {
664
+ const privateKey = getConfiguredPrivateKey();
665
+ const senderAddress = getWalletAddressFromKey();
666
+ const txHash = await services.transferTRX(privateKey, to, amount, network);
667
+ return {
668
+ content: [
669
+ {
670
+ type: "text",
671
+ text: JSON.stringify({
672
+ network,
673
+ from: senderAddress,
674
+ to,
675
+ amount: `${amount} TRX`,
676
+ txHash,
677
+ message: "Transaction sent. Use get_transaction_info to check confirmation.",
678
+ }, null, 2),
679
+ },
680
+ ],
681
+ };
682
+ }
683
+ catch (error) {
684
+ return {
685
+ content: [
686
+ {
687
+ type: "text",
688
+ text: `Error transferring TRX: ${error instanceof Error ? error.message : String(error)}`,
689
+ },
690
+ ],
691
+ isError: true,
692
+ };
693
+ }
694
+ });
695
+ server.registerTool("transfer_trc20", {
696
+ description: "Transfer TRC20 tokens to an address.",
697
+ inputSchema: {
698
+ tokenAddress: z.string().describe("The TRC20 token contract address"),
699
+ to: z.string().describe("Recipient address"),
700
+ amount: z.string().describe("Amount to send (raw amount with decimals)"),
701
+ network: z.string().optional().describe("Network name. Defaults to mainnet."),
702
+ },
703
+ annotations: {
704
+ title: "Transfer TRC20 Tokens",
705
+ readOnlyHint: false,
706
+ destructiveHint: true,
707
+ idempotentHint: false,
708
+ openWorldHint: true,
709
+ },
710
+ }, async ({ tokenAddress, to, amount, network = "mainnet" }) => {
711
+ try {
712
+ const privateKey = getConfiguredPrivateKey();
713
+ const senderAddress = getWalletAddressFromKey();
714
+ const result = await services.transferTRC20(tokenAddress, to, amount, privateKey, network);
715
+ return {
716
+ content: [
717
+ {
718
+ type: "text",
719
+ text: JSON.stringify({
720
+ network,
721
+ tokenAddress,
722
+ from: senderAddress,
723
+ to,
724
+ amount: result.amount.formatted,
725
+ symbol: result.token.symbol,
726
+ decimals: result.token.decimals,
727
+ txHash: result.txHash,
728
+ message: "Transaction sent.",
729
+ }, null, 2),
730
+ },
731
+ ],
732
+ };
733
+ }
734
+ catch (error) {
735
+ return {
736
+ content: [
737
+ {
738
+ type: "text",
739
+ text: `Error transferring TRC20 tokens: ${error instanceof Error ? error.message : String(error)}`,
740
+ },
741
+ ],
742
+ isError: true,
743
+ };
744
+ }
745
+ });
746
+ // ============================================================================
747
+ // MESSAGE SIGNING TOOLS (Write operations)
748
+ // ============================================================================
749
+ server.registerTool("sign_message", {
750
+ description: "Sign an arbitrary message using the configured wallet.",
751
+ inputSchema: {
752
+ message: z.string().describe("The message to sign"),
753
+ },
754
+ annotations: {
755
+ title: "Sign Message",
756
+ readOnlyHint: false,
757
+ destructiveHint: false,
758
+ idempotentHint: true,
759
+ openWorldHint: false,
760
+ },
761
+ }, async ({ message }) => {
762
+ try {
763
+ const senderAddress = getWalletAddressFromKey();
764
+ const signature = await services.signMessage(message);
765
+ return {
766
+ content: [
767
+ {
768
+ type: "text",
769
+ text: JSON.stringify({
770
+ message,
771
+ signature,
772
+ signer: senderAddress,
773
+ messageType: "personal_sign",
774
+ }, null, 2),
775
+ },
776
+ ],
777
+ };
778
+ }
779
+ catch (error) {
780
+ return {
781
+ content: [
782
+ {
783
+ type: "text",
784
+ text: `Error signing message: ${error instanceof Error ? error.message : String(error)}`,
785
+ },
786
+ ],
787
+ isError: true,
788
+ };
789
+ }
790
+ });
791
+ }
792
+ //# sourceMappingURL=tools.js.map