@truecarry/mcp 0.1.4 → 0.1.6
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/cli.js +447 -82
- package/dist/factory.d.ts.map +1 -1
- package/dist/index.cjs +447 -82
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +447 -82
- package/dist/services/McpWalletService.d.ts +66 -13
- package/dist/services/McpWalletService.d.ts.map +1 -1
- package/dist/tools/dns-tools.d.ts +49 -0
- package/dist/tools/dns-tools.d.ts.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/known-jettons-tools.d.ts +44 -0
- package/dist/tools/known-jettons-tools.d.ts.map +1 -0
- package/dist/tools/nft-tools.d.ts +85 -0
- package/dist/tools/nft-tools.d.ts.map +1 -0
- package/dist/tools/swap-tools.d.ts +0 -18
- package/dist/tools/swap-tools.d.ts.map +1 -1
- package/dist/tools/transfer-tools.d.ts +80 -0
- package/dist/tools/transfer-tools.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -70172,7 +70172,7 @@ async function dnsLookup(client, domain, category, resolver) {
|
|
|
70172
70172
|
type: "int",
|
|
70173
70173
|
value: toTonDnsCategory(category)
|
|
70174
70174
|
}];
|
|
70175
|
-
const { stack, exitCode } = await client.runGetMethod(asAddressFriendly(resolver), "dnsresolve", SerializeStack(param));
|
|
70175
|
+
const { stack, exitCode } = await CallForSuccess(() => client.runGetMethod(asAddressFriendly(resolver), "dnsresolve", SerializeStack(param)));
|
|
70176
70176
|
if (stack?.length !== 2) return null;
|
|
70177
70177
|
const parsedStack = ParseStack(stack);
|
|
70178
70178
|
if (exitCode !== 0) return null;
|
|
@@ -86802,7 +86802,24 @@ var McpWalletService = class McpWalletService {
|
|
|
86802
86802
|
}
|
|
86803
86803
|
}
|
|
86804
86804
|
/**
|
|
86805
|
-
*
|
|
86805
|
+
* Send a raw transaction request directly
|
|
86806
|
+
*/
|
|
86807
|
+
async sendRawTransaction(request) {
|
|
86808
|
+
try {
|
|
86809
|
+
await this.wallet.sendTransaction(request);
|
|
86810
|
+
return {
|
|
86811
|
+
success: true,
|
|
86812
|
+
message: `Successfully sent transaction with ${request.messages.length} message(s)`
|
|
86813
|
+
};
|
|
86814
|
+
} catch (error) {
|
|
86815
|
+
return {
|
|
86816
|
+
success: false,
|
|
86817
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
86818
|
+
};
|
|
86819
|
+
}
|
|
86820
|
+
}
|
|
86821
|
+
/**
|
|
86822
|
+
* Get swap quote with transaction params ready to execute
|
|
86806
86823
|
*/
|
|
86807
86824
|
async getSwapQuote(fromToken, toToken, amount, slippageBps) {
|
|
86808
86825
|
const network = this.wallet.getNetwork();
|
|
@@ -86821,32 +86838,95 @@ var McpWalletService = class McpWalletService {
|
|
|
86821
86838
|
slippageBps
|
|
86822
86839
|
};
|
|
86823
86840
|
const quote = await kit.swap.getQuote(params);
|
|
86824
|
-
|
|
86841
|
+
const swapParams = {
|
|
86825
86842
|
quote,
|
|
86843
|
+
userAddress: this.wallet.getAddress()
|
|
86844
|
+
};
|
|
86845
|
+
const tx = await kit.swap.buildSwapTransaction(swapParams);
|
|
86846
|
+
return {
|
|
86826
86847
|
fromToken: quote.fromToken.type === "ton" ? "TON" : quote.fromToken.value,
|
|
86827
86848
|
toToken: quote.toToken.type === "ton" ? "TON" : quote.toToken.value,
|
|
86828
86849
|
fromAmount: quote.fromAmount,
|
|
86829
86850
|
toAmount: quote.toAmount,
|
|
86830
86851
|
minReceived: quote.minReceived,
|
|
86831
86852
|
provider: quote.providerId,
|
|
86832
|
-
expiresAt: quote.expiresAt
|
|
86853
|
+
expiresAt: quote.expiresAt,
|
|
86854
|
+
transaction: {
|
|
86855
|
+
messages: tx.messages.map((m) => ({
|
|
86856
|
+
address: m.address,
|
|
86857
|
+
amount: m.amount.toString(),
|
|
86858
|
+
stateInit: m.stateInit,
|
|
86859
|
+
payload: m.payload
|
|
86860
|
+
})),
|
|
86861
|
+
validUntil: tx.validUntil
|
|
86862
|
+
}
|
|
86863
|
+
};
|
|
86864
|
+
}
|
|
86865
|
+
/**
|
|
86866
|
+
* Get all NFTs
|
|
86867
|
+
*/
|
|
86868
|
+
async getNfts(limit = 20, offset = 0) {
|
|
86869
|
+
return (await this.wallet.getNfts({ pagination: {
|
|
86870
|
+
limit,
|
|
86871
|
+
offset
|
|
86872
|
+
} })).nfts.map((nft) => ({
|
|
86873
|
+
address: nft.address,
|
|
86874
|
+
name: nft.info?.name,
|
|
86875
|
+
description: nft.info?.description,
|
|
86876
|
+
image: typeof nft.info?.image === "string" ? nft.info.image : nft.info?.image?.url,
|
|
86877
|
+
collection: nft.collection ? {
|
|
86878
|
+
address: nft.collection.address,
|
|
86879
|
+
name: nft.collection.name
|
|
86880
|
+
} : void 0,
|
|
86881
|
+
attributes: nft.attributes?.map((attr) => ({
|
|
86882
|
+
trait_type: attr.traitType,
|
|
86883
|
+
value: attr.value
|
|
86884
|
+
})),
|
|
86885
|
+
ownerAddress: nft.ownerAddress,
|
|
86886
|
+
isOnSale: nft.isOnSale,
|
|
86887
|
+
isSoulbound: nft.isSoulbound,
|
|
86888
|
+
saleContractAddress: nft.saleContractAddress
|
|
86889
|
+
}));
|
|
86890
|
+
}
|
|
86891
|
+
/**
|
|
86892
|
+
* Get a specific NFT by address
|
|
86893
|
+
*/
|
|
86894
|
+
async getNft(nftAddress) {
|
|
86895
|
+
const nft = await this.wallet.getNft(nftAddress);
|
|
86896
|
+
if (!nft) return null;
|
|
86897
|
+
return {
|
|
86898
|
+
address: nft.address,
|
|
86899
|
+
name: nft.info?.name,
|
|
86900
|
+
description: nft.info?.description,
|
|
86901
|
+
image: typeof nft.info?.image === "string" ? nft.info.image : nft.info?.image?.url,
|
|
86902
|
+
collection: nft.collection ? {
|
|
86903
|
+
address: nft.collection.address,
|
|
86904
|
+
name: nft.collection.name
|
|
86905
|
+
} : void 0,
|
|
86906
|
+
attributes: nft.attributes?.map((attr) => ({
|
|
86907
|
+
trait_type: attr.traitType,
|
|
86908
|
+
value: attr.value
|
|
86909
|
+
})),
|
|
86910
|
+
ownerAddress: nft.ownerAddress,
|
|
86911
|
+
isOnSale: nft.isOnSale,
|
|
86912
|
+
isSoulbound: nft.isSoulbound,
|
|
86913
|
+
saleContractAddress: nft.saleContractAddress
|
|
86833
86914
|
};
|
|
86834
86915
|
}
|
|
86835
86916
|
/**
|
|
86836
|
-
*
|
|
86917
|
+
* Send NFT
|
|
86837
86918
|
*/
|
|
86838
|
-
async
|
|
86919
|
+
async sendNft(nftAddress, toAddress, comment) {
|
|
86839
86920
|
try {
|
|
86840
|
-
const
|
|
86841
|
-
|
|
86842
|
-
|
|
86843
|
-
|
|
86844
|
-
};
|
|
86845
|
-
const tx = await kit.swap.buildSwapTransaction(params);
|
|
86921
|
+
const tx = await this.wallet.createTransferNftTransaction({
|
|
86922
|
+
nftAddress,
|
|
86923
|
+
recipientAddress: toAddress,
|
|
86924
|
+
comment
|
|
86925
|
+
});
|
|
86846
86926
|
await this.wallet.sendTransaction(tx);
|
|
86847
86927
|
return {
|
|
86848
86928
|
success: true,
|
|
86849
|
-
message: `Successfully
|
|
86929
|
+
message: `Successfully sent NFT ${nftAddress} to ${toAddress}`
|
|
86850
86930
|
};
|
|
86851
86931
|
} catch (error) {
|
|
86852
86932
|
return {
|
|
@@ -86863,6 +86943,18 @@ var McpWalletService = class McpWalletService {
|
|
|
86863
86943
|
return this.config.contacts.resolve("default", name);
|
|
86864
86944
|
}
|
|
86865
86945
|
/**
|
|
86946
|
+
* Resolve a TON DNS domain (e.g., "wallet.ton") to a wallet address
|
|
86947
|
+
*/
|
|
86948
|
+
async resolveDns(domain) {
|
|
86949
|
+
return this.wallet.getClient().resolveDnsWallet(domain);
|
|
86950
|
+
}
|
|
86951
|
+
/**
|
|
86952
|
+
* Reverse resolve a wallet address to a TON DNS domain
|
|
86953
|
+
*/
|
|
86954
|
+
async backResolveDns(address) {
|
|
86955
|
+
return this.wallet.getClient().backResolveDnsWallet(address);
|
|
86956
|
+
}
|
|
86957
|
+
/**
|
|
86866
86958
|
* Close and cleanup
|
|
86867
86959
|
*/
|
|
86868
86960
|
async close() {
|
|
@@ -87067,6 +87159,17 @@ const sendJettonSchema = z.object({
|
|
|
87067
87159
|
amount: z.string().min(1).describe("Amount of tokens to send in human-readable format"),
|
|
87068
87160
|
comment: z.string().optional().describe("Optional comment/memo for the transaction")
|
|
87069
87161
|
});
|
|
87162
|
+
const transactionMessageSchema = z.object({
|
|
87163
|
+
address: z.string().min(1).describe("Recipient wallet address"),
|
|
87164
|
+
amount: z.string().min(1).describe("Amount to transfer in nanotons"),
|
|
87165
|
+
stateInit: z.string().optional().describe("Initial state for deploying a new contract (Base64)"),
|
|
87166
|
+
payload: z.string().optional().describe("Message payload data (Base64)")
|
|
87167
|
+
});
|
|
87168
|
+
const sendRawTransactionSchema = z.object({
|
|
87169
|
+
messages: z.array(transactionMessageSchema).min(1).describe("Array of messages to include in the transaction"),
|
|
87170
|
+
validUntil: z.number().optional().describe("Unix timestamp after which the transaction becomes invalid"),
|
|
87171
|
+
fromAddress: z.string().optional().describe("Sender wallet address")
|
|
87172
|
+
});
|
|
87070
87173
|
function createMcpTransferTools(service) {
|
|
87071
87174
|
return {
|
|
87072
87175
|
send_ton: {
|
|
@@ -87159,6 +87262,41 @@ function createMcpTransferTools(service) {
|
|
|
87159
87262
|
}, null, 2)
|
|
87160
87263
|
}] };
|
|
87161
87264
|
}
|
|
87265
|
+
},
|
|
87266
|
+
send_raw_transaction: {
|
|
87267
|
+
description: "Send a raw transaction with full control over messages. Amounts are in nanotons. Supports multiple messages in a single transaction.",
|
|
87268
|
+
inputSchema: sendRawTransactionSchema,
|
|
87269
|
+
handler: async (args) => {
|
|
87270
|
+
const result = await service.sendRawTransaction({
|
|
87271
|
+
messages: args.messages,
|
|
87272
|
+
validUntil: args.validUntil,
|
|
87273
|
+
fromAddress: args.fromAddress
|
|
87274
|
+
});
|
|
87275
|
+
if (!result.success) return {
|
|
87276
|
+
content: [{
|
|
87277
|
+
type: "text",
|
|
87278
|
+
text: JSON.stringify({
|
|
87279
|
+
success: false,
|
|
87280
|
+
error: result.message
|
|
87281
|
+
})
|
|
87282
|
+
}],
|
|
87283
|
+
isError: true
|
|
87284
|
+
};
|
|
87285
|
+
return { content: [{
|
|
87286
|
+
type: "text",
|
|
87287
|
+
text: JSON.stringify({
|
|
87288
|
+
success: true,
|
|
87289
|
+
message: result.message,
|
|
87290
|
+
details: {
|
|
87291
|
+
messageCount: args.messages.length,
|
|
87292
|
+
messages: args.messages.map((m) => ({
|
|
87293
|
+
to: m.address,
|
|
87294
|
+
amount: `${m.amount} nanoTON`
|
|
87295
|
+
}))
|
|
87296
|
+
}
|
|
87297
|
+
}, null, 2)
|
|
87298
|
+
}] };
|
|
87299
|
+
}
|
|
87162
87300
|
}
|
|
87163
87301
|
};
|
|
87164
87302
|
}
|
|
@@ -87172,49 +87310,153 @@ function createMcpTransferTools(service) {
|
|
|
87172
87310
|
* LICENSE file in the root directory of this source tree.
|
|
87173
87311
|
*
|
|
87174
87312
|
*/
|
|
87175
|
-
const quoteCache = /* @__PURE__ */ new Map();
|
|
87176
|
-
function generateQuoteId() {
|
|
87177
|
-
return `quote_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
87178
|
-
}
|
|
87179
|
-
function cleanExpiredQuotes() {
|
|
87180
|
-
const now = Date.now();
|
|
87181
|
-
for (const [id, data] of quoteCache.entries()) if (data.expiresAt < now) quoteCache.delete(id);
|
|
87182
|
-
}
|
|
87183
87313
|
const getSwapQuoteSchema = z.object({
|
|
87184
87314
|
fromToken: z.string().min(1).describe("Token to swap from (\"TON\" or jetton address)"),
|
|
87185
87315
|
toToken: z.string().min(1).describe("Token to swap to (\"TON\" or jetton address)"),
|
|
87186
87316
|
amount: z.string().min(1).describe("Amount to swap in raw units"),
|
|
87187
87317
|
slippageBps: z.number().optional().describe("Slippage tolerance in basis points (default 100 = 1%)")
|
|
87188
87318
|
});
|
|
87189
|
-
const executeSwapSchema = z.object({ quoteId: z.string().min(1).describe("Quote ID returned from get_swap_quote") });
|
|
87190
87319
|
function createMcpSwapTools(service) {
|
|
87320
|
+
return { get_swap_quote: {
|
|
87321
|
+
description: "Get a quote for swapping tokens. Returns quote details and transaction params. If user confirms, use send_raw_transaction to execute.",
|
|
87322
|
+
inputSchema: getSwapQuoteSchema,
|
|
87323
|
+
handler: async (args) => {
|
|
87324
|
+
try {
|
|
87325
|
+
const result = await service.getSwapQuote(args.fromToken, args.toToken, args.amount, args.slippageBps);
|
|
87326
|
+
return { content: [{
|
|
87327
|
+
type: "text",
|
|
87328
|
+
text: JSON.stringify({
|
|
87329
|
+
success: true,
|
|
87330
|
+
quote: {
|
|
87331
|
+
fromToken: result.fromToken,
|
|
87332
|
+
toToken: result.toToken,
|
|
87333
|
+
fromAmount: result.fromAmount,
|
|
87334
|
+
toAmount: result.toAmount,
|
|
87335
|
+
minReceived: result.minReceived,
|
|
87336
|
+
provider: result.provider,
|
|
87337
|
+
expiresAt: result.expiresAt ? (/* @__PURE__ */ new Date(result.expiresAt * 1e3)).toISOString() : null
|
|
87338
|
+
},
|
|
87339
|
+
transaction: result.transaction,
|
|
87340
|
+
note: "If user confirms, use send_raw_transaction with the transaction params to execute the swap."
|
|
87341
|
+
}, null, 2)
|
|
87342
|
+
}] };
|
|
87343
|
+
} catch (error) {
|
|
87344
|
+
return {
|
|
87345
|
+
content: [{
|
|
87346
|
+
type: "text",
|
|
87347
|
+
text: JSON.stringify({
|
|
87348
|
+
success: false,
|
|
87349
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
87350
|
+
})
|
|
87351
|
+
}],
|
|
87352
|
+
isError: true
|
|
87353
|
+
};
|
|
87354
|
+
}
|
|
87355
|
+
}
|
|
87356
|
+
} };
|
|
87357
|
+
}
|
|
87358
|
+
|
|
87359
|
+
//#endregion
|
|
87360
|
+
//#region src/tools/known-jettons-tools.ts
|
|
87361
|
+
/**
|
|
87362
|
+
* Copyright (c) TonTech.
|
|
87363
|
+
*
|
|
87364
|
+
* This source code is licensed under the MIT license found in the
|
|
87365
|
+
* LICENSE file in the root directory of this source tree.
|
|
87366
|
+
*
|
|
87367
|
+
*/
|
|
87368
|
+
const getKnownJettonsSchema = z.object({});
|
|
87369
|
+
const KNOWN_JETTONS = [
|
|
87370
|
+
{
|
|
87371
|
+
symbol: "USD₮",
|
|
87372
|
+
name: "Tether USD",
|
|
87373
|
+
address: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs",
|
|
87374
|
+
decimals: 6
|
|
87375
|
+
},
|
|
87376
|
+
{
|
|
87377
|
+
symbol: "NOT",
|
|
87378
|
+
name: "Notcoin",
|
|
87379
|
+
address: "EQAvlWFDxGF2lXm67y4yzC17wYKD9A0guwPkMs1gOsM__NOT",
|
|
87380
|
+
decimals: 9
|
|
87381
|
+
},
|
|
87382
|
+
{
|
|
87383
|
+
symbol: "DOGS",
|
|
87384
|
+
name: "Dogs",
|
|
87385
|
+
address: "EQCvxJy4eG8hyHBFsZ7eePxrRsUQSFE_jpptRAYBmcG_DOGS",
|
|
87386
|
+
decimals: 9
|
|
87387
|
+
},
|
|
87388
|
+
{
|
|
87389
|
+
symbol: "DUST",
|
|
87390
|
+
name: "DeDust",
|
|
87391
|
+
address: "EQBlqsm144Dq6SjbPI4jjZvA1hqTIP3CvHovbIfW_t-SCALE",
|
|
87392
|
+
decimals: 9
|
|
87393
|
+
},
|
|
87394
|
+
{
|
|
87395
|
+
symbol: "GRAM",
|
|
87396
|
+
name: "Gram",
|
|
87397
|
+
address: "EQC47093oX5Xhb0xuk2lCr2RhS8rj-vul61u4W2UH5ORmG_O",
|
|
87398
|
+
decimals: 9
|
|
87399
|
+
}
|
|
87400
|
+
];
|
|
87401
|
+
function createMcpKnownJettonsTools() {
|
|
87402
|
+
return { get_known_jettons: {
|
|
87403
|
+
description: "Get a list of known/popular Jettons (tokens) on TON with their addresses and metadata. Useful for looking up token addresses for swaps or transfers.",
|
|
87404
|
+
inputSchema: getKnownJettonsSchema,
|
|
87405
|
+
handler: async () => {
|
|
87406
|
+
return { content: [{
|
|
87407
|
+
type: "text",
|
|
87408
|
+
text: JSON.stringify({
|
|
87409
|
+
success: true,
|
|
87410
|
+
jettons: KNOWN_JETTONS,
|
|
87411
|
+
count: KNOWN_JETTONS.length
|
|
87412
|
+
}, null, 2)
|
|
87413
|
+
}] };
|
|
87414
|
+
}
|
|
87415
|
+
} };
|
|
87416
|
+
}
|
|
87417
|
+
|
|
87418
|
+
//#endregion
|
|
87419
|
+
//#region src/tools/nft-tools.ts
|
|
87420
|
+
/**
|
|
87421
|
+
* Copyright (c) TonTech.
|
|
87422
|
+
*
|
|
87423
|
+
* This source code is licensed under the MIT license found in the
|
|
87424
|
+
* LICENSE file in the root directory of this source tree.
|
|
87425
|
+
*
|
|
87426
|
+
*/
|
|
87427
|
+
const getNftsSchema = z.object({
|
|
87428
|
+
limit: z.number().min(1).max(100).optional().describe("Maximum number of NFTs to return (default: 20, max: 100)"),
|
|
87429
|
+
offset: z.number().min(0).optional().describe("Offset for pagination (default: 0)")
|
|
87430
|
+
});
|
|
87431
|
+
const getNftSchema = z.object({ nftAddress: z.string().min(1).describe("NFT item contract address") });
|
|
87432
|
+
const sendNftSchema = z.object({
|
|
87433
|
+
nftAddress: z.string().min(1).describe("NFT item contract address to transfer"),
|
|
87434
|
+
toAddress: z.string().min(1).describe("Recipient TON address"),
|
|
87435
|
+
comment: z.string().optional().describe("Optional comment/memo for the transaction")
|
|
87436
|
+
});
|
|
87437
|
+
function createMcpNftTools(service) {
|
|
87191
87438
|
return {
|
|
87192
|
-
|
|
87193
|
-
description: "
|
|
87194
|
-
inputSchema:
|
|
87439
|
+
get_nfts: {
|
|
87440
|
+
description: "List all NFTs (non-fungible tokens) in the wallet with their metadata, collection info, and attributes.",
|
|
87441
|
+
inputSchema: getNftsSchema,
|
|
87195
87442
|
handler: async (args) => {
|
|
87196
87443
|
try {
|
|
87197
|
-
|
|
87198
|
-
const result = await service.getSwapQuote(args.fromToken, args.toToken, args.amount, args.slippageBps);
|
|
87199
|
-
const quoteId = generateQuoteId();
|
|
87200
|
-
const expiresAt = result.expiresAt ? result.expiresAt * 1e3 : Date.now() + 6e4;
|
|
87201
|
-
quoteCache.set(quoteId, {
|
|
87202
|
-
quote: result.quote,
|
|
87203
|
-
expiresAt
|
|
87204
|
-
});
|
|
87444
|
+
const nfts = await service.getNfts(args.limit ?? 20, args.offset ?? 0);
|
|
87205
87445
|
return { content: [{
|
|
87206
87446
|
type: "text",
|
|
87207
87447
|
text: JSON.stringify({
|
|
87208
87448
|
success: true,
|
|
87209
|
-
|
|
87210
|
-
|
|
87211
|
-
|
|
87212
|
-
|
|
87213
|
-
|
|
87214
|
-
|
|
87215
|
-
|
|
87216
|
-
|
|
87217
|
-
|
|
87449
|
+
nfts: nfts.map((nft) => ({
|
|
87450
|
+
address: nft.address,
|
|
87451
|
+
name: nft.name,
|
|
87452
|
+
description: nft.description,
|
|
87453
|
+
image: nft.image,
|
|
87454
|
+
collection: nft.collection,
|
|
87455
|
+
attributes: nft.attributes,
|
|
87456
|
+
isOnSale: nft.isOnSale,
|
|
87457
|
+
isSoulbound: nft.isSoulbound
|
|
87458
|
+
})),
|
|
87459
|
+
count: nfts.length
|
|
87218
87460
|
}, null, 2)
|
|
87219
87461
|
}] };
|
|
87220
87462
|
} catch (error) {
|
|
@@ -87231,61 +87473,175 @@ function createMcpSwapTools(service) {
|
|
|
87231
87473
|
}
|
|
87232
87474
|
}
|
|
87233
87475
|
},
|
|
87234
|
-
|
|
87235
|
-
description: "
|
|
87236
|
-
inputSchema:
|
|
87476
|
+
get_nft: {
|
|
87477
|
+
description: "Get detailed information about a specific NFT by its address.",
|
|
87478
|
+
inputSchema: getNftSchema,
|
|
87237
87479
|
handler: async (args) => {
|
|
87238
|
-
|
|
87239
|
-
|
|
87240
|
-
|
|
87241
|
-
|
|
87480
|
+
try {
|
|
87481
|
+
const nft = await service.getNft(args.nftAddress);
|
|
87482
|
+
if (!nft) return {
|
|
87483
|
+
content: [{
|
|
87484
|
+
type: "text",
|
|
87485
|
+
text: JSON.stringify({
|
|
87486
|
+
success: false,
|
|
87487
|
+
error: "NFT not found"
|
|
87488
|
+
})
|
|
87489
|
+
}],
|
|
87490
|
+
isError: true
|
|
87491
|
+
};
|
|
87492
|
+
return { content: [{
|
|
87242
87493
|
type: "text",
|
|
87243
87494
|
text: JSON.stringify({
|
|
87244
|
-
success:
|
|
87245
|
-
|
|
87246
|
-
|
|
87247
|
-
|
|
87248
|
-
|
|
87249
|
-
|
|
87250
|
-
|
|
87251
|
-
|
|
87495
|
+
success: true,
|
|
87496
|
+
nft: {
|
|
87497
|
+
address: nft.address,
|
|
87498
|
+
name: nft.name,
|
|
87499
|
+
description: nft.description,
|
|
87500
|
+
image: nft.image,
|
|
87501
|
+
collection: nft.collection,
|
|
87502
|
+
attributes: nft.attributes,
|
|
87503
|
+
ownerAddress: nft.ownerAddress,
|
|
87504
|
+
isOnSale: nft.isOnSale,
|
|
87505
|
+
isSoulbound: nft.isSoulbound,
|
|
87506
|
+
saleContractAddress: nft.saleContractAddress
|
|
87507
|
+
}
|
|
87508
|
+
}, null, 2)
|
|
87509
|
+
}] };
|
|
87510
|
+
} catch (error) {
|
|
87252
87511
|
return {
|
|
87253
87512
|
content: [{
|
|
87254
87513
|
type: "text",
|
|
87255
87514
|
text: JSON.stringify({
|
|
87256
87515
|
success: false,
|
|
87257
|
-
error:
|
|
87516
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
87258
87517
|
})
|
|
87259
87518
|
}],
|
|
87260
87519
|
isError: true
|
|
87261
87520
|
};
|
|
87262
87521
|
}
|
|
87263
|
-
|
|
87264
|
-
|
|
87265
|
-
|
|
87266
|
-
|
|
87522
|
+
}
|
|
87523
|
+
},
|
|
87524
|
+
send_nft: {
|
|
87525
|
+
description: "Transfer an NFT from the wallet to another address.",
|
|
87526
|
+
inputSchema: sendNftSchema,
|
|
87527
|
+
handler: async (args) => {
|
|
87528
|
+
try {
|
|
87529
|
+
const result = await service.sendNft(args.nftAddress, args.toAddress, args.comment);
|
|
87530
|
+
return {
|
|
87531
|
+
content: [{
|
|
87532
|
+
type: "text",
|
|
87533
|
+
text: JSON.stringify({
|
|
87534
|
+
success: result.success,
|
|
87535
|
+
message: result.message,
|
|
87536
|
+
nftAddress: args.nftAddress,
|
|
87537
|
+
recipient: args.toAddress
|
|
87538
|
+
}, null, 2)
|
|
87539
|
+
}],
|
|
87540
|
+
isError: !result.success
|
|
87541
|
+
};
|
|
87542
|
+
} catch (error) {
|
|
87543
|
+
return {
|
|
87544
|
+
content: [{
|
|
87545
|
+
type: "text",
|
|
87546
|
+
text: JSON.stringify({
|
|
87547
|
+
success: false,
|
|
87548
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
87549
|
+
})
|
|
87550
|
+
}],
|
|
87551
|
+
isError: true
|
|
87552
|
+
};
|
|
87553
|
+
}
|
|
87554
|
+
}
|
|
87555
|
+
}
|
|
87556
|
+
};
|
|
87557
|
+
}
|
|
87558
|
+
|
|
87559
|
+
//#endregion
|
|
87560
|
+
//#region src/tools/dns-tools.ts
|
|
87561
|
+
/**
|
|
87562
|
+
* Copyright (c) TonTech.
|
|
87563
|
+
*
|
|
87564
|
+
* This source code is licensed under the MIT license found in the
|
|
87565
|
+
* LICENSE file in the root directory of this source tree.
|
|
87566
|
+
*
|
|
87567
|
+
*/
|
|
87568
|
+
const resolveDnsSchema = z.object({ domain: z.string().min(1).describe("TON DNS domain to resolve (e.g., \"foundation.ton\")") });
|
|
87569
|
+
const backResolveDnsSchema = z.object({ address: z.string().min(1).describe("TON wallet address to reverse resolve") });
|
|
87570
|
+
function createMcpDnsTools(service) {
|
|
87571
|
+
return {
|
|
87572
|
+
resolve_dns: {
|
|
87573
|
+
description: "Resolve a TON DNS domain (e.g., \"foundation.ton\") to a wallet address. Use this when the user provides a .ton domain instead of a raw address.",
|
|
87574
|
+
inputSchema: resolveDnsSchema,
|
|
87575
|
+
handler: async (args) => {
|
|
87576
|
+
try {
|
|
87577
|
+
const address = await service.resolveDns(args.domain);
|
|
87578
|
+
if (!address) return {
|
|
87579
|
+
content: [{
|
|
87580
|
+
type: "text",
|
|
87581
|
+
text: JSON.stringify({
|
|
87582
|
+
success: false,
|
|
87583
|
+
error: `Could not resolve domain "${args.domain}". The domain may not exist or may not have a wallet record.`
|
|
87584
|
+
})
|
|
87585
|
+
}],
|
|
87586
|
+
isError: true
|
|
87587
|
+
};
|
|
87588
|
+
return { content: [{
|
|
87267
87589
|
type: "text",
|
|
87268
87590
|
text: JSON.stringify({
|
|
87269
|
-
success:
|
|
87270
|
-
|
|
87591
|
+
success: true,
|
|
87592
|
+
domain: args.domain,
|
|
87593
|
+
address
|
|
87594
|
+
}, null, 2)
|
|
87595
|
+
}] };
|
|
87596
|
+
} catch (error) {
|
|
87597
|
+
return {
|
|
87598
|
+
content: [{
|
|
87599
|
+
type: "text",
|
|
87600
|
+
text: JSON.stringify({
|
|
87601
|
+
success: false,
|
|
87602
|
+
error: `Failed to resolve domain: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
87603
|
+
})
|
|
87604
|
+
}],
|
|
87605
|
+
isError: true
|
|
87606
|
+
};
|
|
87607
|
+
}
|
|
87608
|
+
}
|
|
87609
|
+
},
|
|
87610
|
+
back_resolve_dns: {
|
|
87611
|
+
description: "Reverse resolve a TON wallet address to its DNS domain (e.g., find the .ton domain associated with an address).",
|
|
87612
|
+
inputSchema: backResolveDnsSchema,
|
|
87613
|
+
handler: async (args) => {
|
|
87614
|
+
try {
|
|
87615
|
+
const domain = await service.backResolveDns(args.address);
|
|
87616
|
+
if (!domain) return { content: [{
|
|
87617
|
+
type: "text",
|
|
87618
|
+
text: JSON.stringify({
|
|
87619
|
+
success: true,
|
|
87620
|
+
address: args.address,
|
|
87621
|
+
domain: null,
|
|
87622
|
+
message: "No DNS domain found for this address."
|
|
87271
87623
|
})
|
|
87272
|
-
}]
|
|
87273
|
-
|
|
87274
|
-
|
|
87275
|
-
|
|
87276
|
-
|
|
87277
|
-
|
|
87278
|
-
|
|
87279
|
-
|
|
87280
|
-
|
|
87281
|
-
|
|
87282
|
-
|
|
87283
|
-
|
|
87284
|
-
|
|
87285
|
-
|
|
87286
|
-
|
|
87287
|
-
|
|
87288
|
-
|
|
87624
|
+
}] };
|
|
87625
|
+
return { content: [{
|
|
87626
|
+
type: "text",
|
|
87627
|
+
text: JSON.stringify({
|
|
87628
|
+
success: true,
|
|
87629
|
+
address: args.address,
|
|
87630
|
+
domain
|
|
87631
|
+
}, null, 2)
|
|
87632
|
+
}] };
|
|
87633
|
+
} catch (error) {
|
|
87634
|
+
return {
|
|
87635
|
+
content: [{
|
|
87636
|
+
type: "text",
|
|
87637
|
+
text: JSON.stringify({
|
|
87638
|
+
success: false,
|
|
87639
|
+
error: `Failed to reverse resolve address: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
87640
|
+
})
|
|
87641
|
+
}],
|
|
87642
|
+
isError: true
|
|
87643
|
+
};
|
|
87644
|
+
}
|
|
87289
87645
|
}
|
|
87290
87646
|
}
|
|
87291
87647
|
};
|
|
@@ -87342,6 +87698,9 @@ async function createTonWalletMCP(config) {
|
|
|
87342
87698
|
const balanceTools = createMcpBalanceTools(walletService);
|
|
87343
87699
|
const transferTools = createMcpTransferTools(walletService);
|
|
87344
87700
|
const swapTools = createMcpSwapTools(walletService);
|
|
87701
|
+
const knownJettonsTools = createMcpKnownJettonsTools();
|
|
87702
|
+
const nftTools = createMcpNftTools(walletService);
|
|
87703
|
+
const dnsTools = createMcpDnsTools(walletService);
|
|
87345
87704
|
const registerTool = (name, tool) => {
|
|
87346
87705
|
server.registerTool(name, {
|
|
87347
87706
|
description: tool.description,
|
|
@@ -87354,8 +87713,14 @@ async function createTonWalletMCP(config) {
|
|
|
87354
87713
|
registerTool("get_transactions", balanceTools.get_transactions);
|
|
87355
87714
|
registerTool("send_ton", transferTools.send_ton);
|
|
87356
87715
|
registerTool("send_jetton", transferTools.send_jetton);
|
|
87716
|
+
registerTool("send_raw_transaction", transferTools.send_raw_transaction);
|
|
87357
87717
|
registerTool("get_swap_quote", swapTools.get_swap_quote);
|
|
87358
|
-
registerTool("
|
|
87718
|
+
registerTool("get_known_jettons", knownJettonsTools.get_known_jettons);
|
|
87719
|
+
registerTool("get_nfts", nftTools.get_nfts);
|
|
87720
|
+
registerTool("get_nft", nftTools.get_nft);
|
|
87721
|
+
registerTool("send_nft", nftTools.send_nft);
|
|
87722
|
+
registerTool("resolve_dns", dnsTools.resolve_dns);
|
|
87723
|
+
registerTool("back_resolve_dns", dnsTools.back_resolve_dns);
|
|
87359
87724
|
return server;
|
|
87360
87725
|
}
|
|
87361
87726
|
/**
|