bsv-mcp 0.0.21 → 0.0.23
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/README.md +17 -40
- package/index.ts +28 -28
- package/package.json +4 -4
- package/tools/bsv/explore.ts +331 -261
- package/tools/bsv/getPrice.ts +19 -10
- package/tools/bsv/index.ts +1 -1
- package/tools/index.ts +10 -10
- package/tools/mnee/getBalance.ts +53 -43
- package/tools/mnee/index.ts +7 -7
- package/tools/mnee/parseTx.ts +31 -27
- package/tools/mnee/sendMnee.ts +70 -66
- package/tools/ordinals/getTokenByIdOrTicker.ts +14 -7
- package/tools/ordinals/marketListings.ts +26 -13
- package/tools/ordinals/marketSales.ts +11 -17
- package/tools/utils/index.ts +19 -15
- package/tools/wallet/createOrdinals.ts +27 -13
- package/tools/wallet/getAddress.ts +6 -1
- package/tools/wallet/purchaseListing.ts +18 -16
- package/tools/wallet/schemas.ts +55 -32
- package/tools/wallet/sendOrdinals.ts +106 -92
- package/tools/wallet/sendToAddress.ts +1 -1
- package/tools/wallet/tools.test.ts +3 -3
- package/tools/wallet/tools.ts +51 -38
- package/tools/wallet/transferOrdToken.ts +138 -0
- package/tools/wallet/wallet.ts +3 -9
- package/tools/wallet/transferOrdToken/index.ts +0 -103
package/tools/utils/index.ts
CHANGED
|
@@ -12,24 +12,28 @@ export function registerUtilsTools(server: McpServer): void {
|
|
|
12
12
|
server.tool(
|
|
13
13
|
"utils_convertData",
|
|
14
14
|
"Converts data between different encodings (utf8, hex, base64, binary). Useful for transforming data formats when working with blockchain data, encryption, or file processing.\n\n" +
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
"Parameters:\n" +
|
|
16
|
+
"- data (required): The string to convert\n" +
|
|
17
|
+
"- from (required): Source encoding format (utf8, hex, base64, or binary)\n" +
|
|
18
|
+
"- to (required): Target encoding format (utf8, hex, base64, or binary)\n\n" +
|
|
19
|
+
"Example usage:\n" +
|
|
20
|
+
'- UTF-8 to hex: {"data": "hello world", "from": "utf8", "to": "hex"} → 68656c6c6f20776f726c64\n' +
|
|
21
|
+
'- UTF-8 to base64: {"data": "Hello World", "from": "utf8", "to": "base64"} → SGVsbG8gV29ybGQ=\n' +
|
|
22
|
+
'- base64 to UTF-8: {"data": "SGVsbG8gV29ybGQ=", "from": "base64", "to": "utf8"} → Hello World\n' +
|
|
23
|
+
'- hex to base64: {"data": "68656c6c6f20776f726c64", "from": "hex", "to": "base64"} → aGVsbG8gd29ybGQ=\n\n' +
|
|
24
|
+
"Notes:\n" +
|
|
25
|
+
"- All parameters are required\n" +
|
|
26
|
+
"- The tool returns the converted data as a string\n" +
|
|
27
|
+
"- For binary conversion, data is represented as an array of byte values",
|
|
28
28
|
{
|
|
29
29
|
args: z.object({
|
|
30
30
|
data: z.string().describe("The data string to be converted"),
|
|
31
|
-
from: encodingSchema.describe(
|
|
32
|
-
|
|
31
|
+
from: encodingSchema.describe(
|
|
32
|
+
"Source encoding format (utf8, hex, base64, or binary)",
|
|
33
|
+
),
|
|
34
|
+
to: encodingSchema.describe(
|
|
35
|
+
"Target encoding format to convert to (utf8, hex, base64, or binary)",
|
|
36
|
+
),
|
|
33
37
|
}),
|
|
34
38
|
},
|
|
35
39
|
async ({ args }) => {
|
|
@@ -2,13 +2,13 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
3
3
|
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
4
4
|
import { createOrdinals } from "js-1sat-ord";
|
|
5
|
-
import type {
|
|
6
|
-
ChangeResult,
|
|
7
|
-
|
|
8
|
-
Inscription,
|
|
9
|
-
PreMAP,
|
|
5
|
+
import type {
|
|
6
|
+
ChangeResult,
|
|
7
|
+
CreateOrdinalsCollectionItemMetadata,
|
|
10
8
|
CreateOrdinalsCollectionMetadata,
|
|
11
|
-
|
|
9
|
+
Destination,
|
|
10
|
+
Inscription,
|
|
11
|
+
PreMAP,
|
|
12
12
|
} from "js-1sat-ord";
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
import type { Wallet } from "./wallet";
|
|
@@ -24,9 +24,15 @@ export const createOrdinalsArgsSchema = z.object({
|
|
|
24
24
|
// Content type (e.g., "image/jpeg", "text/plain", etc.)
|
|
25
25
|
contentType: z.string().describe("MIME type of the content"),
|
|
26
26
|
// Optional destination address (if not provided, uses the wallet's address)
|
|
27
|
-
destinationAddress: z
|
|
27
|
+
destinationAddress: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Optional destination address for the ordinal"),
|
|
28
31
|
// Optional metadata for the inscription
|
|
29
|
-
metadata: z
|
|
32
|
+
metadata: z
|
|
33
|
+
.any()
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Optional MAP metadata for the inscription"),
|
|
30
36
|
});
|
|
31
37
|
|
|
32
38
|
export type CreateOrdinalsArgs = z.infer<typeof createOrdinalsArgsSchema>;
|
|
@@ -53,7 +59,9 @@ export function registerCreateOrdinalsTool(server: McpServer, wallet: Wallet) {
|
|
|
53
59
|
// 2. Get payment UTXOs from wallet
|
|
54
60
|
const { paymentUtxos } = await wallet.getUtxos();
|
|
55
61
|
if (!paymentUtxos || paymentUtxos.length === 0) {
|
|
56
|
-
throw new Error(
|
|
62
|
+
throw new Error(
|
|
63
|
+
"No payment UTXOs available to fund this inscription",
|
|
64
|
+
);
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
// 3. Get the wallet address for change/destination if not provided
|
|
@@ -79,19 +87,25 @@ export function registerCreateOrdinalsTool(server: McpServer, wallet: Wallet) {
|
|
|
79
87
|
destinations,
|
|
80
88
|
paymentPk,
|
|
81
89
|
changeAddress: walletAddress,
|
|
82
|
-
metaData: args.metadata as
|
|
90
|
+
metaData: args.metadata as
|
|
91
|
+
| PreMAP
|
|
92
|
+
| CreateOrdinalsCollectionMetadata
|
|
93
|
+
| CreateOrdinalsCollectionItemMetadata,
|
|
83
94
|
});
|
|
84
95
|
|
|
85
96
|
const changeResult = result as ChangeResult;
|
|
86
|
-
|
|
97
|
+
|
|
87
98
|
// 7. Broadcast the transaction
|
|
88
99
|
await changeResult.tx.broadcast();
|
|
89
|
-
|
|
100
|
+
|
|
90
101
|
// 8. Refresh the wallet's UTXOs after spending
|
|
91
102
|
try {
|
|
92
103
|
await wallet.refreshUtxos();
|
|
93
104
|
} catch (refreshError) {
|
|
94
|
-
console.warn(
|
|
105
|
+
console.warn(
|
|
106
|
+
"Failed to refresh UTXOs after transaction:",
|
|
107
|
+
refreshError,
|
|
108
|
+
);
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
// 9. Return transaction details
|
|
@@ -11,7 +11,12 @@ export function registerGetAddressTool(server: McpServer): void {
|
|
|
11
11
|
"wallet_getAddress",
|
|
12
12
|
"Retrieves the current wallet's Bitcoin SV address. This address can be used to receive BSV, ordinals, or tokens, and is derived from the wallet's private key.",
|
|
13
13
|
{
|
|
14
|
-
args: z
|
|
14
|
+
args: z
|
|
15
|
+
.object({})
|
|
16
|
+
.optional()
|
|
17
|
+
.describe(
|
|
18
|
+
"No parameters required - simply returns the current wallet address",
|
|
19
|
+
),
|
|
15
20
|
},
|
|
16
21
|
async () => {
|
|
17
22
|
try {
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
type ExistingListing,
|
|
8
8
|
type Payment,
|
|
9
9
|
type Royalty,
|
|
10
|
+
TokenType,
|
|
10
11
|
type TokenUtxo,
|
|
11
12
|
type Utxo,
|
|
12
|
-
TokenType,
|
|
13
13
|
oneSatBroadcaster,
|
|
14
14
|
purchaseOrdListing,
|
|
15
15
|
purchaseOrdTokenListing,
|
|
@@ -160,31 +160,30 @@ Please fund this wallet address with enough BSV to cover the purchase price
|
|
|
160
160
|
|
|
161
161
|
// Create the purchase transaction based on listing type
|
|
162
162
|
let transaction: ChangeResult;
|
|
163
|
-
|
|
163
|
+
|
|
164
164
|
if (args.listingType === "token") {
|
|
165
165
|
if (!args.tokenProtocol) {
|
|
166
166
|
throw new Error("tokenProtocol is required for token listings");
|
|
167
167
|
}
|
|
168
|
-
|
|
168
|
+
|
|
169
169
|
if (!args.tokenID) {
|
|
170
170
|
throw new Error("tokenID is required for token listings");
|
|
171
171
|
}
|
|
172
|
-
|
|
172
|
+
|
|
173
173
|
// Validate token data from the listing
|
|
174
174
|
if (!listingData.data.bsv20) {
|
|
175
175
|
throw new Error("This is not a valid BSV-20 token listing");
|
|
176
176
|
}
|
|
177
|
-
|
|
177
|
+
|
|
178
178
|
// For BSV-20, the amount should be included in the listing data
|
|
179
179
|
if (!listingData.data.bsv20.amt) {
|
|
180
180
|
throw new Error("Token listing doesn't have an amount specified");
|
|
181
181
|
}
|
|
182
|
-
|
|
182
|
+
|
|
183
183
|
// Convert the token protocol to the enum type expected by js-1sat-ord
|
|
184
|
-
const protocol =
|
|
185
|
-
? TokenType.BSV20
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
const protocol =
|
|
185
|
+
args.tokenProtocol === "bsv-20" ? TokenType.BSV20 : TokenType.BSV21;
|
|
186
|
+
|
|
188
187
|
// Create a TokenUtxo with the required fields
|
|
189
188
|
const listingUtxo: TokenUtxo = {
|
|
190
189
|
txid,
|
|
@@ -195,7 +194,7 @@ Please fund this wallet address with enough BSV to cover the purchase price
|
|
|
195
194
|
id: args.tokenID,
|
|
196
195
|
payout: listingData.data.list.payout,
|
|
197
196
|
};
|
|
198
|
-
|
|
197
|
+
|
|
199
198
|
transaction = await purchaseOrdTokenListing({
|
|
200
199
|
protocol,
|
|
201
200
|
tokenID: args.tokenID,
|
|
@@ -214,13 +213,13 @@ Please fund this wallet address with enough BSV to cover the purchase price
|
|
|
214
213
|
script: listingData.script,
|
|
215
214
|
satoshis: listingData.satoshis,
|
|
216
215
|
};
|
|
217
|
-
|
|
216
|
+
|
|
218
217
|
// Create the ExistingListing object for NFT listings
|
|
219
218
|
const listing: ExistingListing = {
|
|
220
219
|
payout: listingData.data.list.payout,
|
|
221
220
|
listingUtxo,
|
|
222
221
|
};
|
|
223
|
-
|
|
222
|
+
|
|
224
223
|
// Check for royalties in the NFT origin data
|
|
225
224
|
// Royalties are only supported for NFTs, not for tokens
|
|
226
225
|
// The royalties are defined by the original creator as a JSON string
|
|
@@ -233,7 +232,7 @@ Please fund this wallet address with enough BSV to cover the purchase price
|
|
|
233
232
|
// Remove console.warn
|
|
234
233
|
}
|
|
235
234
|
}
|
|
236
|
-
|
|
235
|
+
|
|
237
236
|
transaction = await purchaseOrdListing({
|
|
238
237
|
utxos: paymentUtxos,
|
|
239
238
|
paymentPk,
|
|
@@ -285,8 +284,11 @@ Please fund this wallet address with enough BSV to cover the purchase price
|
|
|
285
284
|
price: listingData.data.list.price,
|
|
286
285
|
marketFee,
|
|
287
286
|
marketFeeAddress: MARKET_WALLET_ADDRESS,
|
|
288
|
-
royaltiesPaid:
|
|
289
|
-
|
|
287
|
+
royaltiesPaid:
|
|
288
|
+
args.listingType === "nft" &&
|
|
289
|
+
listingData.origin?.data?.map?.royalties
|
|
290
|
+
? JSON.parse(listingData.origin.data.map.royalties)
|
|
291
|
+
: undefined,
|
|
290
292
|
}),
|
|
291
293
|
},
|
|
292
294
|
],
|
package/tools/wallet/schemas.ts
CHANGED
|
@@ -73,14 +73,26 @@ export const walletDecryptArgsSchema = z.object({
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
// Combined wallet encryption/decryption args
|
|
76
|
-
export const walletEncryptionArgsSchema = z
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
export const walletEncryptionArgsSchema = z
|
|
77
|
+
.object({
|
|
78
|
+
mode: z
|
|
79
|
+
.enum(["encrypt", "decrypt"])
|
|
80
|
+
.describe(
|
|
81
|
+
"Operation mode: 'encrypt' to encrypt plaintext or 'decrypt' to decrypt data",
|
|
82
|
+
),
|
|
83
|
+
data: z
|
|
84
|
+
.union([
|
|
85
|
+
z.string().describe("Text data to encrypt or decrypt"),
|
|
86
|
+
z.array(z.number()).describe("Binary data to encrypt or decrypt"),
|
|
87
|
+
])
|
|
88
|
+
.describe("Data to process: text/data for encryption or decryption"),
|
|
89
|
+
encoding: z
|
|
90
|
+
.enum(["utf8", "hex", "base64"])
|
|
91
|
+
.optional()
|
|
92
|
+
.default("utf8")
|
|
93
|
+
.describe("Encoding of text data (default: utf8)"),
|
|
94
|
+
})
|
|
95
|
+
.describe("Schema for encryption and decryption operations");
|
|
84
96
|
|
|
85
97
|
// Create HMAC arguments
|
|
86
98
|
export const createHmacArgsSchema = z.object({
|
|
@@ -278,30 +290,41 @@ export const sendToAddressArgsSchema = z.object({
|
|
|
278
290
|
/**
|
|
279
291
|
* Schema for purchase listing arguments
|
|
280
292
|
*/
|
|
281
|
-
export const purchaseListingArgsSchema = z
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
293
|
+
export const purchaseListingArgsSchema = z
|
|
294
|
+
.object({
|
|
295
|
+
listingOutpoint: z
|
|
296
|
+
.string()
|
|
297
|
+
.describe("The outpoint of the listing to purchase (txid_vout format)"),
|
|
298
|
+
ordAddress: z
|
|
299
|
+
.string()
|
|
300
|
+
.describe("The ordinal address to receive the purchased item"),
|
|
301
|
+
listingType: z
|
|
302
|
+
.enum(["nft", "token"])
|
|
303
|
+
.default("nft")
|
|
304
|
+
.describe(
|
|
305
|
+
"Type of listing: 'nft' for ordinal NFTs, 'token' for BSV-20 tokens",
|
|
306
|
+
),
|
|
307
|
+
tokenProtocol: z
|
|
308
|
+
.enum(["bsv-20", "bsv-21"])
|
|
309
|
+
.optional()
|
|
310
|
+
.default("bsv-21")
|
|
311
|
+
.describe(
|
|
312
|
+
"Token protocol for token listings (required when listingType is 'token')",
|
|
313
|
+
),
|
|
314
|
+
tokenID: z
|
|
315
|
+
.string()
|
|
316
|
+
.optional()
|
|
317
|
+
.describe(
|
|
318
|
+
"Token ID for BSV-21 tokens or ticker for BSV-20 tokens (required when listingType is 'token')",
|
|
319
|
+
),
|
|
320
|
+
description: z
|
|
321
|
+
.string()
|
|
322
|
+
.optional()
|
|
323
|
+
.describe("Optional description for the transaction"),
|
|
324
|
+
})
|
|
325
|
+
.describe(
|
|
326
|
+
"Schema for the wallet_purchaseListing tool arguments (purchase NFTs or tokens), with detailed field descriptions.",
|
|
327
|
+
);
|
|
305
328
|
|
|
306
329
|
// Export types
|
|
307
330
|
export type SendToAddressArgs = z.infer<typeof sendToAddressArgsSchema>;
|
|
@@ -10,12 +10,19 @@ import type { Wallet } from "./wallet";
|
|
|
10
10
|
* Schema for the sendOrdinals tool arguments
|
|
11
11
|
*/
|
|
12
12
|
export const sendOrdinalsArgsSchema = z.object({
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
// Outpoint of the inscription to send (txid_vout format)
|
|
14
|
+
inscriptionOutpoint: z
|
|
15
|
+
.string()
|
|
16
|
+
.describe("Inscription outpoint in format txid_vout"),
|
|
17
|
+
// Destination address to send the inscription to
|
|
18
|
+
destinationAddress: z
|
|
19
|
+
.string()
|
|
20
|
+
.describe("Destination address for the inscription"),
|
|
21
|
+
// Optional metadata for the ordinal transfer
|
|
22
|
+
metadata: z
|
|
23
|
+
.any()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Optional MAP metadata for the transfer"),
|
|
19
26
|
});
|
|
20
27
|
|
|
21
28
|
export type SendOrdinalsArgs = z.infer<typeof sendOrdinalsArgsSchema>;
|
|
@@ -24,97 +31,104 @@ export type SendOrdinalsArgs = z.infer<typeof sendOrdinalsArgsSchema>;
|
|
|
24
31
|
* Registers the wallet_sendOrdinals tool for transferring ordinals
|
|
25
32
|
*/
|
|
26
33
|
export function registerSendOrdinalsTool(server: McpServer, wallet: Wallet) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
server.tool(
|
|
35
|
+
"wallet_sendOrdinals",
|
|
36
|
+
"Transfers ordinals (NFTs) from your wallet to another address on the Bitcoin SV blockchain. This tool enables sending inscriptions you own to any valid BSV address. The transaction is created, signed, and broadcast automatically, with appropriate fee calculation and change handling.",
|
|
37
|
+
{ args: sendOrdinalsArgsSchema },
|
|
38
|
+
async (
|
|
39
|
+
{ args }: { args: SendOrdinalsArgs },
|
|
40
|
+
extra: RequestHandlerExtra,
|
|
41
|
+
): Promise<CallToolResult> => {
|
|
42
|
+
try {
|
|
43
|
+
// 1. Get private key from wallet
|
|
44
|
+
const paymentPk = wallet.getPrivateKey();
|
|
45
|
+
if (!paymentPk) {
|
|
46
|
+
throw new Error("No private key available in wallet");
|
|
47
|
+
}
|
|
41
48
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
// 2. Get payment UTXOs from wallet
|
|
50
|
+
const { paymentUtxos, nftUtxos } = await wallet.getUtxos();
|
|
51
|
+
if (!paymentUtxos || paymentUtxos.length === 0) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
"No payment UTXOs available to fund this transaction",
|
|
54
|
+
);
|
|
55
|
+
}
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
// 3. Get the wallet address for change
|
|
58
|
+
const walletAddress = paymentPk.toAddress().toString();
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const inscription = nftUtxos.find(
|
|
60
|
-
(utxo) => utxo.txid === txid && utxo.vout === vout
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
if (!inscription) {
|
|
64
|
-
throw new Error(
|
|
65
|
-
`Inscription ${args.inscriptionOutpoint} not found in your wallet`
|
|
66
|
-
);
|
|
67
|
-
}
|
|
60
|
+
// 4. Parse the inscription outpoint
|
|
61
|
+
const [txid, voutStr] = args.inscriptionOutpoint.split("_");
|
|
62
|
+
if (!txid || !voutStr) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
"Invalid inscription outpoint format. Expected txid_vout",
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
const vout = Number.parseInt(voutStr, 10);
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
ordinals: [inscription],
|
|
74
|
-
destinations: [{ address: args.destinationAddress }],
|
|
75
|
-
changeAddress: walletAddress,
|
|
76
|
-
};
|
|
69
|
+
// 5. Find the inscription in nftUtxos
|
|
70
|
+
const inscription = nftUtxos.find(
|
|
71
|
+
(utxo) => utxo.txid === txid && utxo.vout === vout,
|
|
72
|
+
);
|
|
77
73
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
if (!inscription) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Inscription ${args.inscriptionOutpoint} not found in your wallet`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
82
79
|
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
// 6. Create config and transfer the inscription
|
|
81
|
+
const sendOrdinalsConfig: SendOrdinalsConfig = {
|
|
82
|
+
paymentPk,
|
|
83
|
+
paymentUtxos,
|
|
84
|
+
ordinals: [inscription],
|
|
85
|
+
destinations: [{ address: args.destinationAddress }],
|
|
86
|
+
changeAddress: walletAddress,
|
|
87
|
+
};
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
await changeResult.tx.broadcast();
|
|
91
|
-
|
|
92
|
-
// 8. Refresh the wallet's UTXOs after spending
|
|
93
|
-
try {
|
|
94
|
-
await wallet.refreshUtxos();
|
|
95
|
-
} catch (refreshError) {
|
|
96
|
-
console.warn("Failed to refresh UTXOs after transaction:", refreshError);
|
|
97
|
-
}
|
|
89
|
+
// Add metadata if provided
|
|
90
|
+
if (args.metadata) {
|
|
91
|
+
sendOrdinalsConfig.metaData = args.metadata;
|
|
92
|
+
}
|
|
98
93
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
94
|
+
// Using the wallet's key for both payment and ordinals
|
|
95
|
+
sendOrdinalsConfig.ordPk = paymentPk;
|
|
96
|
+
|
|
97
|
+
const result = await sendOrdinals(sendOrdinalsConfig);
|
|
98
|
+
const changeResult = result as ChangeResult;
|
|
99
|
+
|
|
100
|
+
// 7. Broadcast the transaction
|
|
101
|
+
await changeResult.tx.broadcast();
|
|
102
|
+
|
|
103
|
+
// 8. Refresh the wallet's UTXOs after spending
|
|
104
|
+
try {
|
|
105
|
+
await wallet.refreshUtxos();
|
|
106
|
+
} catch (refreshError) {
|
|
107
|
+
console.warn(
|
|
108
|
+
"Failed to refresh UTXOs after transaction:",
|
|
109
|
+
refreshError,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 9. Return transaction details
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: "text",
|
|
118
|
+
text: JSON.stringify({
|
|
119
|
+
txid: changeResult.tx.id("hex"),
|
|
120
|
+
spentOutpoints: changeResult.spentOutpoints,
|
|
121
|
+
payChange: changeResult.payChange,
|
|
122
|
+
inscriptionOutpoint: args.inscriptionOutpoint,
|
|
123
|
+
destinationAddress: args.destinationAddress,
|
|
124
|
+
}),
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
};
|
|
128
|
+
} catch (err: unknown) {
|
|
129
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
130
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
);
|
|
134
|
+
}
|
|
@@ -3,9 +3,9 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
3
3
|
import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
4
4
|
import { toSatoshi } from "satoshi-token";
|
|
5
5
|
import type { z } from "zod";
|
|
6
|
+
import { getBsvPriceWithCache } from "../bsv/getPrice";
|
|
6
7
|
import { sendToAddressArgsSchema } from "./schemas";
|
|
7
8
|
import type { Wallet } from "./wallet";
|
|
8
|
-
import { getBsvPriceWithCache } from "../bsv/getPrice";
|
|
9
9
|
|
|
10
10
|
// Use the schema imported from schemas.ts
|
|
11
11
|
export type SendToAddressArgs = z.infer<typeof sendToAddressArgsSchema>;
|
|
@@ -11,7 +11,7 @@ type WalletToolName =
|
|
|
11
11
|
| "wallet_getPublicKey"
|
|
12
12
|
| "wallet_createSignature"
|
|
13
13
|
| "wallet_verifySignature"
|
|
14
|
-
| "wallet_encryption";
|
|
14
|
+
| "wallet_encryption";
|
|
15
15
|
|
|
16
16
|
const toolNames: WalletToolName[] = [
|
|
17
17
|
"wallet_getPublicKey",
|
|
@@ -34,9 +34,9 @@ function getDummyArgs(tool: WalletToolName): Record<string, unknown> {
|
|
|
34
34
|
signature: "sig",
|
|
35
35
|
publicKey: "pubkey",
|
|
36
36
|
};
|
|
37
|
-
|
|
37
|
+
// TODO we merged encrypt and decrypt into encryption we need to update the test file
|
|
38
38
|
// case "wallet_encryption":
|
|
39
|
-
// if
|
|
39
|
+
// if
|
|
40
40
|
// return { data: "test", publicKey: "pubkey" };
|
|
41
41
|
// case "wallet_decryption":
|
|
42
42
|
// return { encryptedData: "data" };
|