bsv-mcp 0.0.35 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +112 -1
  2. package/README.md +233 -4
  3. package/dist/index.js +111762 -0
  4. package/index.ts +804 -86
  5. package/next-env.d.ts +6 -0
  6. package/package.json +57 -15
  7. package/prompts/bsvSdk/index.ts +5 -5
  8. package/prompts/bsvSdk/transaction.ts +2 -2
  9. package/prompts/bsvSdk/wallet.ts +1 -1
  10. package/prompts/index.ts +1 -1
  11. package/resources/bitcom.ts +132 -0
  12. package/resources/resources.ts +7 -3
  13. package/smithery.yaml +3 -0
  14. package/test-mcp-server.ts +157 -0
  15. package/tools/bap/friend.ts +267 -0
  16. package/tools/bap/generate.test.ts +350 -0
  17. package/tools/bap/generate.ts +433 -0
  18. package/tools/bap/getCurrentAddress.ts +76 -0
  19. package/tools/bap/getId.test.ts +121 -0
  20. package/tools/bap/getId.ts +169 -0
  21. package/tools/bap/index.ts +111 -0
  22. package/tools/bap/types.ts +66 -0
  23. package/tools/bap/utils.ts +33 -0
  24. package/tools/bigblocks/components.ts +304 -0
  25. package/tools/bigblocks/docs.ts +488 -0
  26. package/tools/bigblocks/examples.ts +527 -0
  27. package/tools/bigblocks/generator.ts +485 -0
  28. package/tools/bigblocks/index.ts +23 -0
  29. package/tools/bsocial/bigblocksApiClient.ts +189 -0
  30. package/tools/bsocial/bmapFollow.ts +125 -0
  31. package/tools/bsocial/bmapLikes.ts +111 -0
  32. package/tools/bsocial/bmapReadPosts.ts +148 -0
  33. package/tools/bsocial/createPost.ts +136 -0
  34. package/tools/bsocial/index.ts +45 -0
  35. package/tools/bsocial/readPosts.ts +255 -0
  36. package/tools/bsv/decodeTransaction.ts +5 -1
  37. package/tools/constants.ts +21 -0
  38. package/tools/index.ts +103 -17
  39. package/tools/mnee/index.ts +8 -0
  40. package/tools/mnee/parseTx.ts +1 -1
  41. package/tools/mnee/sendMnee.ts +1 -1
  42. package/tools/utils/aip.ts +46 -0
  43. package/tools/utils/conversion.ts +1 -0
  44. package/tools/utils/errorHandler.ts +76 -0
  45. package/tools/utils/index.ts +45 -1
  46. package/tools/utils/installAgentMaster.ts +84 -0
  47. package/tools/utils/logger.ts +20 -0
  48. package/tools/utils/toolConfig.ts +80 -0
  49. package/tools/utils/toolRegistration.ts +66 -0
  50. package/tools/utils/transactionBuilder.ts +196 -0
  51. package/tools/wallet/a2bPublishAgent.ts +8 -4
  52. package/tools/wallet/a2bPublishMcp.ts +28 -24
  53. package/tools/wallet/createOrdinals.ts +4 -2
  54. package/tools/wallet/fetchPaymentUtxos.ts +44 -43
  55. package/tools/wallet/gatherCollectionInfo.ts +374 -0
  56. package/tools/wallet/getAddress.ts +13 -21
  57. package/tools/wallet/getBalance.ts +66 -0
  58. package/tools/wallet/getBalanceDroplet.ts +59 -0
  59. package/tools/wallet/integratedWallet.ts +120 -0
  60. package/tools/wallet/mintCollection.ts +378 -0
  61. package/tools/wallet/purchaseListing.ts +4 -4
  62. package/tools/wallet/schemas.ts +18 -249
  63. package/tools/wallet/sendOrdinals.ts +4 -2
  64. package/tools/wallet/sendToAddress.ts +5 -1
  65. package/tools/wallet/setupDroplet.ts +172 -0
  66. package/tools/wallet/tools.ts +71 -156
  67. package/tools/wallet/transactionHelper.ts +121 -0
  68. package/tools/wallet/transferOrdToken.ts +7 -4
  69. package/tools/wallet/utxo.ts +62 -0
  70. package/tools/wallet/wallet.ts +237 -234
  71. package/tools/a2b/call.ts +0 -32
@@ -1,77 +1,11 @@
1
- import type { SecurityLevel } from "@bsv/sdk";
2
1
  import { z } from "zod";
3
2
 
4
- // Define SecurityLevel to match the BSV SDK exactly
5
- const SecurityLevelEnum = z.union([z.literal(0), z.literal(1), z.literal(2)]);
6
-
7
- // Create a custom validator without tuples
8
- export const walletProtocolSchema = z.custom<[SecurityLevel, string]>((val) => {
9
- return (
10
- Array.isArray(val) &&
11
- val.length === 2 &&
12
- (val[0] === 0 || val[0] === 1 || val[0] === 2) &&
13
- typeof val[1] === "string"
14
- );
15
- });
16
-
17
3
  // Empty args schema for functions that don't take arguments
18
4
  export const emptyArgsSchema = z.object({});
19
5
 
20
6
  // Get public key arguments
21
7
  export const getPublicKeyArgsSchema = z.object({});
22
8
 
23
- // Create signature arguments
24
- export const createSignatureArgsSchema = z.object({
25
- data: z.array(z.number()).optional(),
26
- hashToDirectlySign: z.array(z.number()).optional(),
27
- protocolID: walletProtocolSchema,
28
- keyID: z.string(),
29
- privilegedReason: z.string().optional(),
30
- counterparty: z
31
- .union([z.string(), z.literal("self"), z.literal("anyone")])
32
- .optional(),
33
- privileged: z.boolean().optional(),
34
- });
35
-
36
- // Verify signature arguments
37
- export const verifySignatureArgsSchema = z.object({
38
- data: z.array(z.number()).optional(),
39
- hashToDirectlyVerify: z.array(z.number()).optional(),
40
- signature: z.array(z.number()),
41
- protocolID: walletProtocolSchema,
42
- keyID: z.string(),
43
- privilegedReason: z.string().optional(),
44
- counterparty: z
45
- .union([z.string(), z.literal("self"), z.literal("anyone")])
46
- .optional(),
47
- forSelf: z.boolean().optional(),
48
- privileged: z.boolean().optional(),
49
- });
50
-
51
- // Wallet encryption args
52
- export const walletEncryptArgsSchema = z.object({
53
- plaintext: z.array(z.number()),
54
- protocolID: walletProtocolSchema,
55
- keyID: z.string(),
56
- privilegedReason: z.string().optional(),
57
- counterparty: z
58
- .union([z.string(), z.literal("self"), z.literal("anyone")])
59
- .optional(),
60
- privileged: z.boolean().optional(),
61
- });
62
-
63
- // Wallet decryption args
64
- export const walletDecryptArgsSchema = z.object({
65
- ciphertext: z.array(z.number()),
66
- protocolID: walletProtocolSchema,
67
- keyID: z.string(),
68
- privilegedReason: z.string().optional(),
69
- counterparty: z
70
- .union([z.string(), z.literal("self"), z.literal("anyone")])
71
- .optional(),
72
- privileged: z.boolean().optional(),
73
- });
74
-
75
9
  // Combined wallet encryption/decryption args
76
10
  export const walletEncryptionArgsSchema = z
77
11
  .object({
@@ -91,190 +25,25 @@ export const walletEncryptionArgsSchema = z
91
25
  .optional()
92
26
  .default("utf8")
93
27
  .describe("Encoding of text data (default: utf8)"),
28
+ recipientPublicKeyHex: z
29
+ .string()
30
+ .length(66)
31
+ .regex(/^(02|03)[0-9a-fA-F]{64}$/)
32
+ .optional()
33
+ .describe(
34
+ "Recipient's public key in hex format (required for encryption mode)",
35
+ ),
94
36
  })
95
- .describe("Schema for encryption and decryption operations");
96
-
97
- // Create HMAC arguments
98
- export const createHmacArgsSchema = z.object({
99
- message: z.string(),
100
- encoding: z.enum(["utf8", "hex", "base64"]).optional(),
101
- });
102
-
103
- // Verify HMAC arguments
104
- export const verifyHmacArgsSchema = z.object({
105
- message: z.string(),
106
- hmac: z.string(),
107
- publicKey: z.string(),
108
- encoding: z.enum(["utf8", "hex", "base64"]).optional(),
109
- });
110
-
111
- // Transaction input schema
112
- export const transactionInputSchema = z.object({
113
- outpoint: z.string(),
114
- inputDescription: z.string(), // Required field
115
- sequence: z.number().optional(),
116
- });
117
-
118
- // Transaction output schema
119
- export const transactionOutputSchema = z.object({
120
- lockingScript: z.string(),
121
- satoshis: z.number(),
122
- outputDescription: z.string(), // Required field
123
- change: z.boolean().optional(),
124
- });
125
-
126
- // Create action args
127
- export const createActionArgsSchema = z.object({
128
- description: z.string(),
129
- labels: z.array(z.string()).optional(),
130
- lockTime: z.number().optional(),
131
- version: z.number().optional(),
132
- inputBEEF: z.array(z.number()).optional(),
133
- inputs: z.array(transactionInputSchema).optional(),
134
- outputs: z.array(transactionOutputSchema).optional(),
135
- options: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),
136
- });
137
-
138
- // Sign action args
139
- export const signActionArgsSchema = z.object({
140
- reference: z.string(),
141
- spends: z.record(z.any()).optional(),
142
- options: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),
143
- });
144
-
145
- // List actions args
146
- export const listActionsArgsSchema = z.object({
147
- labels: z.array(z.string()),
148
- labelQueryMode: z.enum(["any", "all"]).optional(),
149
- limit: z.number().optional(),
150
- offset: z.number().optional(),
151
- includeInputs: z.boolean().optional(),
152
- includeOutputs: z.boolean().optional(),
153
- includeLabels: z.boolean().optional(),
154
- includeInputSourceLockingScripts: z.boolean().optional(),
155
- includeInputUnlockingScripts: z.boolean().optional(),
156
- seekPermission: z.boolean().optional(),
157
- });
158
-
159
- // List outputs args
160
- export const listOutputsArgsSchema = z.object({
161
- basket: z.string(),
162
- tags: z.array(z.string()).optional(),
163
- tagQueryMode: z.enum(["all", "any"]).optional(),
164
- limit: z.number().optional(),
165
- offset: z.number().optional(),
166
- include: z.enum(["locking scripts", "entire transactions"]).optional(),
167
- includeLabels: z.boolean().optional(),
168
- includeTags: z.boolean().optional(),
169
- includeCustomInstructions: z.boolean().optional(),
170
- seekPermission: z.boolean().optional(),
171
- });
172
-
173
- // Reveal counterparty key linkage args
174
- export const revealCounterpartyKeyLinkageArgsSchema = z.object({
175
- counterparty: z.string(),
176
- verifier: z.string(),
177
- privileged: z.boolean().optional(),
178
- privilegedReason: z.string().optional(),
179
- });
180
-
181
- // Reveal specific key linkage args
182
- export const revealSpecificKeyLinkageArgsSchema = z.object({
183
- keyID: z.number(),
184
- verifier: z.string(),
185
- privileged: z.boolean().optional(),
186
- privilegedReason: z.string().optional(),
187
- });
188
-
189
- // Abort action args
190
- export const abortActionArgsSchema = z.object({
191
- reference: z.string(),
192
- });
193
-
194
- // Internalize action args
195
- export const internalizeActionArgsSchema = z.object({
196
- tx: z.array(z.number()),
197
- outputs: z.array(
198
- z.object({
199
- outputIndex: z.number(),
200
- protocol: z.enum(["wallet payment", "basket insertion"]),
201
- lockingScript: z.string(),
202
- satoshis: z.number(),
203
- }),
204
- ),
205
- description: z.string(),
206
- labels: z.array(z.string()).optional(),
207
- seekPermission: z.boolean().optional(),
208
- });
209
-
210
- // Relinquish output args
211
- export const relinquishOutputArgsSchema = z.object({
212
- basket: z.string(),
213
- output: z.string(),
214
- });
215
-
216
- // Acquire certificate args
217
- export const acquireCertificateArgsSchema = z.object({
218
- type: z.string(),
219
- certifier: z.string(),
220
- acquisitionProtocol: z.enum(["direct", "issuance"]),
221
- fields: z.record(z.string()),
222
- certifierUrl: z.string().optional(),
223
- serialNumber: z.string().optional(),
224
- signature: z.string().optional(),
225
- revocationOutpoint: z.string().optional(),
226
- keyringForSubject: z.record(z.string()).optional(),
227
- keyringRevealer: z.string().optional(),
228
- privileged: z.boolean().optional(),
229
- privilegedReason: z.string().optional(),
230
- });
231
-
232
- // List certificates args
233
- export const listCertificatesArgsSchema = z.object({
234
- certifiers: z.array(z.string()),
235
- types: z.array(z.string()),
236
- limit: z.number().optional(),
237
- offset: z.number().optional(),
238
- privileged: z.boolean().optional(),
239
- privilegedReason: z.string().optional(),
240
- });
241
-
242
- // Prove certificate args
243
- export const proveCertificateArgsSchema = z.object({
244
- certificate: z.object({}),
245
- fieldsToReveal: z.array(z.string()),
246
- verifier: z.string(),
247
- privileged: z.boolean().optional(),
248
- privilegedReason: z.string().optional(),
249
- });
250
-
251
- // Relinquish certificate args
252
- export const relinquishCertificateArgsSchema = z.object({
253
- type: z.string(),
254
- serialNumber: z.string(),
255
- certifier: z.string(),
256
- });
257
-
258
- // Discover by identity key args
259
- export const discoverByIdentityKeyArgsSchema = z.object({
260
- identityKey: z.string(),
261
- limit: z.number().optional(),
262
- offset: z.number().optional(),
263
- seekPermission: z.boolean().optional(),
264
- });
265
-
266
- // Discover by attributes args
267
- export const discoverByAttributesArgsSchema = z.object({
268
- attributes: z.record(z.string()),
269
- limit: z.number().optional(),
270
- offset: z.number().optional(),
271
- seekPermission: z.boolean().optional(),
272
- });
273
-
274
- // Get header for height args
275
- export const getHeaderArgsSchema = z.object({
276
- height: z.number(),
277
- });
37
+ .describe("Schema for encryption and decryption operations")
38
+ .superRefine((val, ctx) => {
39
+ if (val.mode === "encrypt" && !val.recipientPublicKeyHex) {
40
+ ctx.addIssue({
41
+ code: z.ZodIssueCode.custom,
42
+ message: "recipientPublicKeyHex is required when mode is 'encrypt'",
43
+ path: ["recipientPublicKeyHex"],
44
+ });
45
+ }
46
+ });
278
47
 
279
48
  // Get address args
280
49
  export const getAddressArgsSchema = z.object({});
@@ -6,14 +6,15 @@ import type {
6
6
  ServerNotification,
7
7
  ServerRequest,
8
8
  } from "@modelcontextprotocol/sdk/types.js";
9
- import { sendOrdinals } from "js-1sat-ord";
10
9
  import type {
11
10
  ChangeResult,
12
11
  LocalSigner,
13
12
  SendOrdinalsConfig,
14
13
  } from "js-1sat-ord";
14
+ import { OneSatBroadcaster, sendOrdinals } from "js-1sat-ord";
15
15
  import { Sigma } from "sigma-protocol";
16
16
  import { z } from "zod";
17
+ import { V5Broadcaster } from "../../utils/broadcaster";
17
18
  import type { Wallet } from "./wallet";
18
19
 
19
20
  /**
@@ -121,7 +122,8 @@ export function registerSendOrdinalsTool(server: McpServer, wallet: Wallet) {
121
122
  // 7. Broadcast the transaction
122
123
  const disableBroadcasting = process.env.DISABLE_BROADCASTING === "true";
123
124
  if (!disableBroadcasting) {
124
- await changeResult.tx.broadcast();
125
+ const broadcaster = new V5Broadcaster();
126
+ await changeResult.tx.broadcast(broadcaster);
125
127
 
126
128
  // 8. Refresh the wallet's UTXOs after spending
127
129
  try {
@@ -1,6 +1,10 @@
1
1
  import { P2PKH } from "@bsv/sdk";
2
2
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
4
+ import type {
5
+ ServerNotification,
6
+ ServerRequest,
7
+ } from "@modelcontextprotocol/sdk/types.js";
4
8
  import { toSatoshi } from "satoshi-token";
5
9
  import type { z } from "zod";
6
10
  import { getBsvPriceWithCache } from "../bsv/getPrice";
@@ -22,7 +26,7 @@ export function registerSendToAddressTool(server: McpServer, wallet: Wallet) {
22
26
  },
23
27
  async (
24
28
  { args }: { args: SendToAddressArgs },
25
- extra: RequestHandlerExtra,
29
+ extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
26
30
  ) => {
27
31
  try {
28
32
  const {
@@ -0,0 +1,172 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
3
+ import type {
4
+ ServerNotification,
5
+ ServerRequest,
6
+ } from "@modelcontextprotocol/sdk/types.js";
7
+ import { z } from "zod";
8
+ import { DropletClient } from "../../utils/droplet";
9
+ import type { IntegratedWallet } from "./integratedWallet";
10
+
11
+ const setupDropletArgsSchema = z.object({
12
+ action: z.enum(["register_key", "create_faucet", "check_status"]),
13
+ faucetName: z.string().optional(),
14
+ fixedDropSats: z.number().optional(),
15
+ });
16
+
17
+ export type SetupDropletArgs = z.infer<typeof setupDropletArgsSchema>;
18
+
19
+ /**
20
+ * Register the setupDroplet tool for Droplet API initialization
21
+ */
22
+ export function registerSetupDropletTool(
23
+ server: McpServer,
24
+ integratedWallet: IntegratedWallet,
25
+ ) {
26
+ server.tool(
27
+ "wallet_setupDroplet",
28
+ "Setup and manage Droplet API integration. Actions: register_key (registers your public key), create_faucet (creates a new faucet), check_status (checks faucet status)",
29
+ {
30
+ args: setupDropletArgsSchema,
31
+ },
32
+ async (
33
+ { args }: { args: SetupDropletArgs },
34
+ extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
35
+ ) => {
36
+ try {
37
+ const dropletClient = integratedWallet.getDropletClient();
38
+ if (!dropletClient) {
39
+ throw new Error("Droplet client not configured");
40
+ }
41
+
42
+ const config = dropletClient.getConfig();
43
+ const apiUrl = config.apiUrl;
44
+ const authKey = config.authKey;
45
+
46
+ switch (args.action) {
47
+ case "register_key": {
48
+ if (!authKey) {
49
+ throw new Error("No auth key configured");
50
+ }
51
+
52
+ const pubkey = authKey.toPublicKey().toString();
53
+
54
+ // Register the key with the Droplet API
55
+ const response = await fetch(`${apiUrl}/auth/register`, {
56
+ method: "POST",
57
+ headers: {
58
+ "Content-Type": "application/json",
59
+ },
60
+ body: JSON.stringify({ publicKey: pubkey }),
61
+ });
62
+
63
+ if (!response.ok) {
64
+ const error = await response.text();
65
+ throw new Error(`Failed to register key: ${error}`);
66
+ }
67
+
68
+ return {
69
+ content: [
70
+ {
71
+ type: "text",
72
+ text: JSON.stringify({
73
+ status: "success",
74
+ message: "Key registered successfully",
75
+ publicKey: pubkey,
76
+ }),
77
+ },
78
+ ],
79
+ };
80
+ }
81
+
82
+ case "create_faucet": {
83
+ if (!args.faucetName) {
84
+ throw new Error(
85
+ "faucetName is required for create_faucet action",
86
+ );
87
+ }
88
+
89
+ // First, ensure the key is registered
90
+ if (authKey) {
91
+ const pubkey = authKey.toPublicKey().toString();
92
+ await fetch(`${apiUrl}/auth/register`, {
93
+ method: "POST",
94
+ headers: {
95
+ "Content-Type": "application/json",
96
+ },
97
+ body: JSON.stringify({ publicKey: pubkey }),
98
+ });
99
+ }
100
+
101
+ // Create the faucet
102
+ const body = {
103
+ name: args.faucetName,
104
+ fixed_drop_sats: args.fixedDropSats || 1000,
105
+ max_consolidation_inputs: 20,
106
+ };
107
+
108
+ const headers = authKey
109
+ ? await dropletClient.getAuthHeaders("POST", "/faucets", body)
110
+ : {};
111
+
112
+ const response = await fetch(`${apiUrl}/faucets`, {
113
+ method: "POST",
114
+ headers: {
115
+ "Content-Type": "application/json",
116
+ ...headers,
117
+ },
118
+ body: JSON.stringify(body),
119
+ });
120
+
121
+ if (!response.ok) {
122
+ const error = await response.text();
123
+ throw new Error(`Failed to create faucet: ${error}`);
124
+ }
125
+
126
+ const result = await response.json();
127
+ return {
128
+ content: [
129
+ {
130
+ type: "text",
131
+ text: JSON.stringify({
132
+ status: "success",
133
+ message: "Faucet created successfully",
134
+ faucet: result,
135
+ }),
136
+ },
137
+ ],
138
+ };
139
+ }
140
+
141
+ case "check_status": {
142
+ const status = await dropletClient.getFaucetStatus();
143
+ return {
144
+ content: [
145
+ {
146
+ type: "text",
147
+ text: JSON.stringify({
148
+ status: "success",
149
+ faucetStatus: status,
150
+ }),
151
+ },
152
+ ],
153
+ };
154
+ }
155
+
156
+ default:
157
+ throw new Error(`Unknown action: ${args.action}`);
158
+ }
159
+ } catch (error) {
160
+ return {
161
+ content: [
162
+ {
163
+ type: "text",
164
+ text: error instanceof Error ? error.message : String(error),
165
+ },
166
+ ],
167
+ isError: true,
168
+ };
169
+ }
170
+ },
171
+ );
172
+ }