bsv-mcp 0.2.14 → 0.3.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.
- package/CHANGELOG.md +90 -10
- package/README.md +13 -13
- package/dist/app.html +483 -106
- package/dist/index.js +265787 -155292
- package/index.ts +505 -70
- package/package.json +24 -15
- package/prompts/bsvSdk/auth.ts +1 -1
- package/prompts/bsvSdk/cryptography.ts +1 -1
- package/prompts/bsvSdk/overview.ts +1 -1
- package/prompts/bsvSdk/primitives.ts +1 -1
- package/prompts/bsvSdk/script.ts +1 -1
- package/prompts/bsvSdk/transaction.ts +1 -1
- package/prompts/bsvSdk/wallet.ts +1 -1
- package/prompts/ordinals.ts +1 -1
- package/test-mcp-server.ts +26 -4
- package/tools/a2b/discover.ts +2 -2
- package/tools/bap/friend.ts +17 -24
- package/tools/bap/generate.test.ts +34 -32
- package/tools/bap/generate.ts +48 -43
- package/tools/bap/getCurrentAddress.ts +1 -3
- package/tools/bap/getId.test.ts +18 -10
- package/tools/bap/getId.ts +8 -6
- package/tools/bap/utils.ts +1 -1
- package/tools/bsocial/bmapReadPosts.ts +16 -2
- package/tools/bsocial/createPost.ts +21 -10
- package/tools/bsocial/readPosts.ts +10 -4
- package/tools/bsv/decodeTransaction.ts +1 -1
- package/tools/bsv/explore.ts +0 -4
- package/tools/bsv/getPrice.ts +1 -1
- package/tools/bsv/token.ts +14 -6
- package/tools/constants.ts +6 -2
- package/tools/index.ts +10 -10
- package/tools/mnee/getBalance.ts +1 -1
- package/tools/mnee/parseTx.ts +1 -1
- package/tools/mnee/sendMnee.ts +30 -8
- package/tools/ordinals/getInscription.ts +1 -3
- package/tools/ordinals/getTokenByIdOrTicker.ts +1 -3
- package/tools/ordinals/index.ts +4 -1
- package/tools/ordinals/marketListings.ts +1 -1
- package/tools/ordinals/marketSales.ts +1 -1
- package/tools/ordinals/searchInscriptions.ts +1 -1
- package/tools/utils/aip.ts +31 -22
- package/tools/utils/installAgentMaster.ts +8 -9
- package/tools/utils/toolRegistration.ts +21 -22
- package/tools/utils/transactionBuilder.ts +21 -14
- package/tools/wallet/a2bPublishMcp.ts +15 -5
- package/tools/wallet/brc100.ts +541 -310
- package/tools/wallet/cancelListing.ts +29 -37
- package/tools/wallet/createOrdinals.ts +43 -27
- package/tools/wallet/fetchPaymentUtxos.ts +7 -5
- package/tools/wallet/gatherCollectionInfo.ts +3 -5
- package/tools/wallet/getAddress.ts +1 -4
- package/tools/wallet/getBalance.ts +15 -15
- package/tools/wallet/{getBalanceDroplet.ts → getBalanceDroplit.ts} +6 -6
- package/tools/wallet/getBsv21Balances.ts +20 -14
- package/tools/wallet/getLockData.ts +11 -11
- package/tools/wallet/getOrdinals.ts +26 -20
- package/tools/wallet/integratedWallet.ts +55 -53
- package/tools/wallet/listOrdinal.ts +40 -39
- package/tools/wallet/listTokens.ts +18 -17
- package/tools/wallet/lockBsv.ts +36 -22
- package/tools/wallet/mintCollection.ts +15 -10
- package/tools/wallet/opnsDeregister.ts +29 -39
- package/tools/wallet/opnsRegister.ts +29 -39
- package/tools/wallet/purchaseListing.test.ts +27 -0
- package/tools/wallet/purchaseListing.ts +59 -40
- package/tools/wallet/refreshUtxos.ts +1 -1
- package/tools/wallet/schemas.ts +0 -13
- package/tools/wallet/sendAllBsv.ts +26 -20
- package/tools/wallet/sendBsv.ts +107 -0
- package/tools/wallet/setupDroplit.ts +157 -0
- package/tools/wallet/signBsm.ts +18 -18
- package/tools/wallet/sweepBsv.ts +48 -27
- package/tools/wallet/sweepBsv21.ts +42 -28
- package/tools/wallet/sweepOrdinals.ts +38 -26
- package/tools/wallet/tools.ts +11 -13
- package/tools/wallet/transactionHelper.ts +13 -5
- package/tools/wallet/transferOrdToken.ts +72 -84
- package/tools/wallet/unlockBsv.ts +23 -17
- package/tools/wallet/utxo.ts +1 -0
- package/tools/wallet/wallet.ts +1 -13
- package/tools/wallet/sendToAddress.ts +0 -74
- package/tools/wallet/setupDroplet.ts +0 -161
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { type PrivateKey, Utils } from "@bsv/sdk";
|
|
2
|
+
import { DroplitClient, type DroplitConfig } from "../../utils/droplit";
|
|
3
|
+
import {
|
|
4
|
+
buildAndSendTransaction,
|
|
5
|
+
buildOpReturnScript,
|
|
6
|
+
} from "../utils/transactionBuilder";
|
|
3
7
|
import { Wallet } from "./wallet";
|
|
4
8
|
|
|
5
9
|
export interface IntegratedWalletConfig {
|
|
@@ -7,26 +11,26 @@ export interface IntegratedWalletConfig {
|
|
|
7
11
|
paymentKey?: PrivateKey;
|
|
8
12
|
identityKey?: PrivateKey;
|
|
9
13
|
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
// Droplit API config
|
|
15
|
+
useDroplitApi?: boolean;
|
|
16
|
+
droplitConfig?: DroplitConfig;
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
/**
|
|
16
|
-
* Integrated wallet that can use either local keys or
|
|
20
|
+
* Integrated wallet that can use either local keys or Droplit API
|
|
17
21
|
*/
|
|
18
22
|
export class IntegratedWallet {
|
|
19
23
|
private localWallet?: Wallet;
|
|
20
|
-
private
|
|
24
|
+
private droplitClient?: DroplitClient;
|
|
21
25
|
|
|
22
|
-
constructor(
|
|
23
|
-
if (config.
|
|
24
|
-
// If we have a payment key, use it for auth with
|
|
26
|
+
constructor(config: IntegratedWalletConfig) {
|
|
27
|
+
if (config.useDroplitApi && config.droplitConfig) {
|
|
28
|
+
// If we have a payment key, use it for auth with Droplit API
|
|
25
29
|
if (config.paymentKey) {
|
|
26
|
-
config.
|
|
30
|
+
config.droplitConfig.authKey = config.paymentKey;
|
|
27
31
|
}
|
|
28
|
-
this.
|
|
29
|
-
console.error("IntegratedWallet: Using
|
|
32
|
+
this.droplitClient = new DroplitClient(config.droplitConfig);
|
|
33
|
+
console.error("IntegratedWallet: Using Droplit API mode");
|
|
30
34
|
} else if (config.paymentKey) {
|
|
31
35
|
this.localWallet = new Wallet(config.paymentKey, config.identityKey);
|
|
32
36
|
console.error("IntegratedWallet: Using local wallet mode");
|
|
@@ -37,21 +41,22 @@ export class IntegratedWallet {
|
|
|
37
41
|
}
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
get
|
|
41
|
-
return !!this.
|
|
44
|
+
get isDroplitMode(): boolean {
|
|
45
|
+
return !!this.droplitClient;
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
get hasWallet(): boolean {
|
|
45
|
-
return !!this.localWallet || !!this.
|
|
49
|
+
return !!this.localWallet || !!this.droplitClient;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
async getBalance(): Promise<number> {
|
|
49
|
-
if (this.
|
|
50
|
-
const status = await this.
|
|
53
|
+
if (this.droplitClient) {
|
|
54
|
+
const status = await this.droplitClient.getFaucetStatus();
|
|
51
55
|
return status.balance_satoshis;
|
|
52
56
|
}
|
|
53
57
|
if (this.localWallet) {
|
|
54
|
-
|
|
58
|
+
const { paymentUtxos } = await this.localWallet.getUtxos();
|
|
59
|
+
return paymentUtxos.reduce((sum, utxo) => sum + utxo.satoshis, 0);
|
|
55
60
|
}
|
|
56
61
|
throw new Error("No wallet configured");
|
|
57
62
|
}
|
|
@@ -59,52 +64,49 @@ export class IntegratedWallet {
|
|
|
59
64
|
async sendToAddress(
|
|
60
65
|
address: string,
|
|
61
66
|
satoshis: number,
|
|
62
|
-
description?: string,
|
|
63
67
|
): Promise<{ txid: string }> {
|
|
64
|
-
if (this.
|
|
65
|
-
// For
|
|
66
|
-
// Note:
|
|
67
|
-
const response = await this.
|
|
68
|
+
if (this.droplitClient) {
|
|
69
|
+
// For Droplit API, we use the tap endpoint which sends the faucet's fixed amount
|
|
70
|
+
// Note: Droplit API doesn't support custom amounts, it uses fixed_drop_sats
|
|
71
|
+
const response = await this.droplitClient.tap(address);
|
|
68
72
|
return { txid: response.txid };
|
|
69
73
|
}
|
|
70
74
|
if (this.localWallet) {
|
|
71
|
-
|
|
72
|
-
description: description || "Send to address",
|
|
73
|
-
outputs: [
|
|
74
|
-
{
|
|
75
|
-
lockingScript: new P2PKH().lock(address).toHex(),
|
|
76
|
-
satoshis,
|
|
77
|
-
outputDescription: `Payment to ${address}`,
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
});
|
|
81
|
-
return { txid: tx.txid };
|
|
75
|
+
return await this.localWallet.sendToAddress(address, satoshis);
|
|
82
76
|
}
|
|
83
77
|
throw new Error("No wallet configured");
|
|
84
78
|
}
|
|
85
79
|
|
|
86
80
|
async pushData(data: string[], encoding = "hex"): Promise<{ txid: string }> {
|
|
87
|
-
if (this.
|
|
88
|
-
const response = await this.
|
|
81
|
+
if (this.droplitClient) {
|
|
82
|
+
const response = await this.droplitClient.push(data, encoding);
|
|
89
83
|
return { txid: response.txid };
|
|
90
84
|
}
|
|
91
85
|
if (this.localWallet) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
86
|
+
const paymentKey = this.localWallet.getPaymentKey();
|
|
87
|
+
const changeAddress = this.localWallet.getAddress();
|
|
88
|
+
if (!paymentKey || !changeAddress) {
|
|
89
|
+
throw new Error("Local wallet has no payment key");
|
|
90
|
+
}
|
|
91
|
+
if (encoding !== "hex" && encoding !== "utf8" && encoding !== "base64") {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`Unsupported push data encoding "${encoding}"; expected hex, utf8 or base64`,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
const script = buildOpReturnScript(
|
|
97
|
+
data.map((item) => Utils.toArray(item, encoding)),
|
|
96
98
|
);
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
outputs: [
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
outputDescription: "OP_RETURN data",
|
|
104
|
-
},
|
|
105
|
-
],
|
|
99
|
+
const { paymentUtxos } = await this.localWallet.getUtxos();
|
|
100
|
+
const result = await buildAndSendTransaction({
|
|
101
|
+
outputs: [{ script, satoshis: 0 }],
|
|
102
|
+
utxos: paymentUtxos,
|
|
103
|
+
changeAddress,
|
|
104
|
+
paymentKey,
|
|
106
105
|
});
|
|
107
|
-
|
|
106
|
+
if (!result.success || !result.txid) {
|
|
107
|
+
throw new Error(result.error ?? "Failed to broadcast OP_RETURN data");
|
|
108
|
+
}
|
|
109
|
+
return { txid: result.txid };
|
|
108
110
|
}
|
|
109
111
|
throw new Error("No wallet configured");
|
|
110
112
|
}
|
|
@@ -114,7 +116,7 @@ export class IntegratedWallet {
|
|
|
114
116
|
return this.localWallet;
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
|
|
118
|
-
return this.
|
|
119
|
+
getDroplitClient(): DroplitClient | undefined {
|
|
120
|
+
return this.droplitClient;
|
|
119
121
|
}
|
|
120
122
|
}
|
|
@@ -1,86 +1,87 @@
|
|
|
1
|
-
import type { OneSatContext } from
|
|
2
|
-
import {
|
|
3
|
-
import type { McpServer } from
|
|
4
|
-
import { z } from
|
|
5
|
-
|
|
6
|
-
const walletOutputSchema = z.object({
|
|
7
|
-
outpoint: z.string(),
|
|
8
|
-
satoshis: z.number().optional(),
|
|
9
|
-
tags: z.array(z.string()).optional(),
|
|
10
|
-
customInstructions: z.string().optional(),
|
|
11
|
-
lockingScript: z.string().optional(),
|
|
12
|
-
})
|
|
1
|
+
import type { OneSatContext } from "@1sat/actions";
|
|
2
|
+
import { sellOrdinal } from "@1sat/actions";
|
|
3
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { assertBroadcastAllowed } from "../../utils/broadcastGuard";
|
|
13
6
|
|
|
14
7
|
const listOrdinalArgsSchema = z.object({
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
),
|
|
18
|
-
inputBEEF: z
|
|
19
|
-
.array(z.number())
|
|
8
|
+
id: z
|
|
9
|
+
.string()
|
|
20
10
|
.describe(
|
|
21
|
-
"
|
|
11
|
+
"Tracking id of the ordinal in the ordinals basket (the 'id:' tag from wallet_getOrdinals)",
|
|
22
12
|
),
|
|
23
|
-
price: z
|
|
13
|
+
price: z
|
|
14
|
+
.number()
|
|
15
|
+
.int()
|
|
16
|
+
.positive()
|
|
17
|
+
.describe("Price in satoshis; whole satoshis above zero"),
|
|
24
18
|
payAddress: z
|
|
25
19
|
.string()
|
|
26
|
-
.
|
|
27
|
-
|
|
20
|
+
.optional()
|
|
21
|
+
.describe(
|
|
22
|
+
"Address to receive payment on purchase. Defaults to the wallet's P1SAT '1sat 0' address.",
|
|
23
|
+
),
|
|
24
|
+
});
|
|
28
25
|
|
|
29
26
|
export function registerListOrdinalTool(
|
|
30
27
|
server: McpServer,
|
|
31
28
|
ctx: OneSatContext | undefined,
|
|
32
29
|
) {
|
|
33
30
|
server.tool(
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
"wallet_listOrdinal",
|
|
32
|
+
"List an ordinal for sale on the marketplace",
|
|
36
33
|
{ ...listOrdinalArgsSchema.shape },
|
|
37
|
-
async ({
|
|
34
|
+
async ({ id, price, payAddress }) => {
|
|
38
35
|
if (!ctx) {
|
|
39
36
|
return {
|
|
40
37
|
content: [
|
|
41
38
|
{
|
|
42
|
-
type:
|
|
43
|
-
text:
|
|
39
|
+
type: "text",
|
|
40
|
+
text: "Wallet not initialized. Please configure a wallet before listing.",
|
|
44
41
|
},
|
|
45
42
|
],
|
|
46
43
|
isError: true,
|
|
47
|
-
}
|
|
44
|
+
};
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
assertBroadcastAllowed("wallet_listOrdinal");
|
|
49
|
+
const result = await sellOrdinal.execute(ctx, {
|
|
50
|
+
id,
|
|
54
51
|
price,
|
|
55
52
|
payAddress,
|
|
56
|
-
})
|
|
53
|
+
});
|
|
57
54
|
|
|
58
55
|
if (result.error) {
|
|
59
56
|
return {
|
|
60
|
-
content: [{ type:
|
|
57
|
+
content: [{ type: "text", text: result.error }],
|
|
61
58
|
isError: true,
|
|
62
|
-
}
|
|
59
|
+
};
|
|
63
60
|
}
|
|
64
61
|
|
|
65
62
|
return {
|
|
66
63
|
content: [
|
|
67
64
|
{
|
|
68
|
-
type:
|
|
69
|
-
text: JSON.stringify(
|
|
65
|
+
type: "text",
|
|
66
|
+
text: JSON.stringify(
|
|
67
|
+
result,
|
|
68
|
+
(_, v) => (typeof v === "bigint" ? v.toString() : v),
|
|
69
|
+
2,
|
|
70
|
+
),
|
|
70
71
|
},
|
|
71
72
|
],
|
|
72
|
-
}
|
|
73
|
+
};
|
|
73
74
|
} catch (err: unknown) {
|
|
74
75
|
return {
|
|
75
76
|
content: [
|
|
76
77
|
{
|
|
77
|
-
type:
|
|
78
|
+
type: "text",
|
|
78
79
|
text: err instanceof Error ? err.message : String(err),
|
|
79
80
|
},
|
|
80
81
|
],
|
|
81
82
|
isError: true,
|
|
82
|
-
}
|
|
83
|
+
};
|
|
83
84
|
}
|
|
84
85
|
},
|
|
85
|
-
)
|
|
86
|
+
);
|
|
86
87
|
}
|
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { McpServer } from
|
|
3
|
-
import { z } from
|
|
1
|
+
import { listBsv21, type OneSatContext } from "@1sat/actions";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
4
|
|
|
5
|
-
export function registerListTokensTool(
|
|
6
|
-
server: McpServer,
|
|
7
|
-
ctx?: OneSatContext,
|
|
8
|
-
) {
|
|
5
|
+
export function registerListTokensTool(server: McpServer, ctx?: OneSatContext) {
|
|
9
6
|
server.tool(
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
"wallet_listTokens",
|
|
8
|
+
"List BSV21 token outputs in the wallet",
|
|
12
9
|
{
|
|
13
|
-
limit: z
|
|
10
|
+
limit: z
|
|
11
|
+
.number()
|
|
12
|
+
.int()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("Max number of results to return"),
|
|
14
15
|
},
|
|
15
16
|
async (params) => {
|
|
16
17
|
try {
|
|
17
|
-
if (!ctx) throw new Error(
|
|
18
|
-
const result = await
|
|
18
|
+
if (!ctx) throw new Error("BRC-100 wallet context not available");
|
|
19
|
+
const result = await listBsv21.execute(ctx, params);
|
|
19
20
|
return {
|
|
20
|
-
content: [{ type:
|
|
21
|
-
}
|
|
21
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
22
|
+
};
|
|
22
23
|
} catch (err: unknown) {
|
|
23
|
-
const msg = err instanceof Error ? err.message : String(err)
|
|
24
|
-
return { content: [{ type:
|
|
24
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
25
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
25
26
|
}
|
|
26
27
|
},
|
|
27
|
-
)
|
|
28
|
+
);
|
|
28
29
|
}
|
package/tools/wallet/lockBsv.ts
CHANGED
|
@@ -1,69 +1,83 @@
|
|
|
1
|
-
import type { OneSatContext } from
|
|
2
|
-
import { lockBsv } from
|
|
3
|
-
import type { McpServer } from
|
|
4
|
-
import { z } from
|
|
1
|
+
import type { OneSatContext } from "@1sat/actions";
|
|
2
|
+
import { lockBsv } from "@1sat/actions";
|
|
3
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { assertBroadcastAllowed } from "../../utils/broadcastGuard";
|
|
5
6
|
|
|
6
7
|
const lockBsvArgsSchema = z.object({
|
|
7
8
|
requests: z
|
|
8
9
|
.array(
|
|
9
10
|
z.object({
|
|
10
|
-
satoshis: z
|
|
11
|
-
|
|
11
|
+
satoshis: z
|
|
12
|
+
.number()
|
|
13
|
+
.int()
|
|
14
|
+
.positive()
|
|
15
|
+
.describe("Amount in satoshis to lock; whole satoshis above zero"),
|
|
16
|
+
until: z
|
|
17
|
+
.number()
|
|
18
|
+
.int()
|
|
19
|
+
.positive()
|
|
20
|
+
.describe("Block height until which to lock"),
|
|
12
21
|
}),
|
|
13
22
|
)
|
|
14
|
-
.describe(
|
|
15
|
-
})
|
|
23
|
+
.describe("Array of lock requests"),
|
|
24
|
+
});
|
|
16
25
|
|
|
17
26
|
export function registerLockBsvTool(
|
|
18
27
|
server: McpServer,
|
|
19
28
|
ctx: OneSatContext | undefined,
|
|
20
29
|
) {
|
|
21
30
|
server.tool(
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
"wallet_lockBsv",
|
|
32
|
+
"Lock BSV until a specific block height",
|
|
24
33
|
{ ...lockBsvArgsSchema.shape },
|
|
25
34
|
async ({ requests }) => {
|
|
26
35
|
if (!ctx) {
|
|
27
36
|
return {
|
|
28
37
|
content: [
|
|
29
38
|
{
|
|
30
|
-
type:
|
|
31
|
-
text:
|
|
39
|
+
type: "text",
|
|
40
|
+
text: "Wallet not initialized. Please configure a wallet before locking.",
|
|
32
41
|
},
|
|
33
42
|
],
|
|
34
43
|
isError: true,
|
|
35
|
-
}
|
|
44
|
+
};
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
try {
|
|
39
|
-
|
|
48
|
+
assertBroadcastAllowed("wallet_lockBsv");
|
|
49
|
+
const result = await lockBsv.execute(ctx, { requests });
|
|
40
50
|
|
|
41
51
|
if (result.error) {
|
|
42
52
|
return {
|
|
43
|
-
content: [{ type:
|
|
53
|
+
content: [{ type: "text", text: result.error }],
|
|
44
54
|
isError: true,
|
|
45
|
-
}
|
|
55
|
+
};
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
return {
|
|
49
59
|
content: [
|
|
50
60
|
{
|
|
51
|
-
type:
|
|
52
|
-
text: JSON.stringify(
|
|
61
|
+
type: "text",
|
|
62
|
+
text: JSON.stringify(
|
|
63
|
+
result,
|
|
64
|
+
(_, v) => (typeof v === "bigint" ? v.toString() : v),
|
|
65
|
+
2,
|
|
66
|
+
),
|
|
53
67
|
},
|
|
54
68
|
],
|
|
55
|
-
}
|
|
69
|
+
};
|
|
56
70
|
} catch (err: unknown) {
|
|
57
71
|
return {
|
|
58
72
|
content: [
|
|
59
73
|
{
|
|
60
|
-
type:
|
|
74
|
+
type: "text",
|
|
61
75
|
text: err instanceof Error ? err.message : String(err),
|
|
62
76
|
},
|
|
63
77
|
],
|
|
64
78
|
isError: true,
|
|
65
|
-
}
|
|
79
|
+
};
|
|
66
80
|
}
|
|
67
81
|
},
|
|
68
|
-
)
|
|
82
|
+
);
|
|
69
83
|
}
|
|
@@ -12,11 +12,11 @@ import type {
|
|
|
12
12
|
CreateOrdinalsCollectionMetadata,
|
|
13
13
|
CreateOrdinalsConfig,
|
|
14
14
|
LocalSigner,
|
|
15
|
-
RarityLabels,
|
|
16
15
|
} from "js-1sat-ord";
|
|
17
16
|
import { createOrdinals } from "js-1sat-ord";
|
|
18
17
|
import { z } from "zod";
|
|
19
18
|
import { V5Broadcaster } from "../../utils/broadcaster";
|
|
19
|
+
import { assertBroadcastAllowed } from "../../utils/broadcastGuard";
|
|
20
20
|
import type { Wallet } from "./wallet";
|
|
21
21
|
|
|
22
22
|
const mintCollectionArgsSchema = z.object({
|
|
@@ -46,8 +46,6 @@ const mintCollectionArgsSchema = z.object({
|
|
|
46
46
|
.describe("Skip broadcasting transactions (for testing)"),
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
type MintCollectionArgs = z.infer<typeof mintCollectionArgsSchema>;
|
|
50
|
-
|
|
51
49
|
interface ImageFile {
|
|
52
50
|
path: string;
|
|
53
51
|
name: string;
|
|
@@ -121,10 +119,20 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
|
|
|
121
119
|
"wallet_mintCollection",
|
|
122
120
|
"Mint a collection of ordinals from a folder of images with proper metadata. This tool creates a collection inscription first, then mints each image as a collection item with the appropriate metadata linking it to the collection.",
|
|
123
121
|
{ ...mintCollectionArgsSchema.shape },
|
|
124
|
-
async ({
|
|
122
|
+
async ({
|
|
123
|
+
folderPath,
|
|
124
|
+
collectionName,
|
|
125
|
+
description,
|
|
126
|
+
rarityLabels,
|
|
127
|
+
traits: traitsJson,
|
|
128
|
+
skipBroadcast,
|
|
129
|
+
}): Promise<CallToolResult> => {
|
|
125
130
|
try {
|
|
131
|
+
assertBroadcastAllowed("wallet_mintCollection");
|
|
126
132
|
// Parse traits JSON string if provided
|
|
127
|
-
const traits: Record<string, string[]> | undefined = traitsJson
|
|
133
|
+
const traits: Record<string, string[]> | undefined = traitsJson
|
|
134
|
+
? JSON.parse(traitsJson)
|
|
135
|
+
: undefined;
|
|
128
136
|
// Get keys from wallet
|
|
129
137
|
const paymentPk = wallet.getPaymentKey();
|
|
130
138
|
if (!paymentPk) {
|
|
@@ -145,8 +153,7 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
|
|
|
145
153
|
description: description,
|
|
146
154
|
quantity: imageFiles.length,
|
|
147
155
|
// Transform rarity labels to correct format
|
|
148
|
-
rarityLabels:
|
|
149
|
-
rarityLabels?.map((r) => ({ label: r.label })) || [],
|
|
156
|
+
rarityLabels: rarityLabels?.map((r) => ({ label: r.label })) || [],
|
|
150
157
|
// Transform traits - need to match the CollectionTraits type
|
|
151
158
|
traits: traits
|
|
152
159
|
? Object.entries(traits).reduce((acc, [key, values]) => {
|
|
@@ -262,9 +269,7 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
|
|
|
262
269
|
(i / imageFiles.length) * rarityLabels.length,
|
|
263
270
|
);
|
|
264
271
|
const rarityItem =
|
|
265
|
-
rarityLabels[
|
|
266
|
-
Math.min(rarityIndex, rarityLabels.length - 1)
|
|
267
|
-
];
|
|
272
|
+
rarityLabels[Math.min(rarityIndex, rarityLabels.length - 1)];
|
|
268
273
|
if (rarityItem) {
|
|
269
274
|
itemSubTypeData.rarityLabel = [
|
|
270
275
|
{ [rarityItem.label]: `${rarityItem.percentage}%` },
|
|
@@ -1,80 +1,70 @@
|
|
|
1
|
-
import type { OneSatContext } from
|
|
2
|
-
import {
|
|
3
|
-
import type { McpServer } from
|
|
4
|
-
import { z } from
|
|
5
|
-
|
|
6
|
-
const walletOutputSchema = z.object({
|
|
7
|
-
outpoint: z.string(),
|
|
8
|
-
satoshis: z.number().optional(),
|
|
9
|
-
tags: z.array(z.string()).optional(),
|
|
10
|
-
customInstructions: z.string().optional(),
|
|
11
|
-
lockingScript: z.string().optional(),
|
|
12
|
-
})
|
|
1
|
+
import type { OneSatContext } from "@1sat/actions";
|
|
2
|
+
import { deregisterOpns } from "@1sat/actions";
|
|
3
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { assertBroadcastAllowed } from "../../utils/broadcastGuard";
|
|
13
6
|
|
|
14
7
|
const opnsDeregisterArgsSchema = z.object({
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
.array(z.number())
|
|
20
|
-
.describe(
|
|
21
|
-
"BEEF bytes from listOutputs (include: 'entire transactions')",
|
|
22
|
-
),
|
|
23
|
-
})
|
|
8
|
+
id: z
|
|
9
|
+
.string()
|
|
10
|
+
.describe("Tracking id of the OpNS name in the wallet's OPNS basket"),
|
|
11
|
+
});
|
|
24
12
|
|
|
25
13
|
export function registerOpnsDeregisterTool(
|
|
26
14
|
server: McpServer,
|
|
27
15
|
ctx: OneSatContext | undefined,
|
|
28
16
|
) {
|
|
29
17
|
server.tool(
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
"wallet_opnsDeregister",
|
|
19
|
+
"Deregister an OpNS name",
|
|
32
20
|
{ ...opnsDeregisterArgsSchema.shape },
|
|
33
|
-
async ({
|
|
21
|
+
async ({ id }) => {
|
|
34
22
|
if (!ctx) {
|
|
35
23
|
return {
|
|
36
24
|
content: [
|
|
37
25
|
{
|
|
38
|
-
type:
|
|
39
|
-
text:
|
|
26
|
+
type: "text",
|
|
27
|
+
text: "Wallet not initialized. Please configure a wallet before deregistering.",
|
|
40
28
|
},
|
|
41
29
|
],
|
|
42
30
|
isError: true,
|
|
43
|
-
}
|
|
31
|
+
};
|
|
44
32
|
}
|
|
45
33
|
|
|
46
34
|
try {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
inputBEEF,
|
|
50
|
-
})
|
|
35
|
+
assertBroadcastAllowed("wallet_opnsDeregister");
|
|
36
|
+
const result = await deregisterOpns.execute(ctx, { id });
|
|
51
37
|
|
|
52
38
|
if (result.error) {
|
|
53
39
|
return {
|
|
54
|
-
content: [{ type:
|
|
40
|
+
content: [{ type: "text", text: result.error }],
|
|
55
41
|
isError: true,
|
|
56
|
-
}
|
|
42
|
+
};
|
|
57
43
|
}
|
|
58
44
|
|
|
59
45
|
return {
|
|
60
46
|
content: [
|
|
61
47
|
{
|
|
62
|
-
type:
|
|
63
|
-
text: JSON.stringify(
|
|
48
|
+
type: "text",
|
|
49
|
+
text: JSON.stringify(
|
|
50
|
+
result,
|
|
51
|
+
(_, v) => (typeof v === "bigint" ? v.toString() : v),
|
|
52
|
+
2,
|
|
53
|
+
),
|
|
64
54
|
},
|
|
65
55
|
],
|
|
66
|
-
}
|
|
56
|
+
};
|
|
67
57
|
} catch (err: unknown) {
|
|
68
58
|
return {
|
|
69
59
|
content: [
|
|
70
60
|
{
|
|
71
|
-
type:
|
|
61
|
+
type: "text",
|
|
72
62
|
text: err instanceof Error ? err.message : String(err),
|
|
73
63
|
},
|
|
74
64
|
],
|
|
75
65
|
isError: true,
|
|
76
|
-
}
|
|
66
|
+
};
|
|
77
67
|
}
|
|
78
68
|
},
|
|
79
|
-
)
|
|
69
|
+
);
|
|
80
70
|
}
|