bsv-mcp 0.2.0 → 0.2.8

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 (52) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/index.js +87290 -70731
  3. package/index.ts +422 -22
  4. package/package.json +28 -24
  5. package/tools/a2b/discover.ts +13 -13
  6. package/tools/bap/friend.ts +2 -3
  7. package/tools/bap/generate.ts +7 -9
  8. package/tools/bap/getCurrentAddress.ts +1 -8
  9. package/tools/bap/getId.ts +3 -3
  10. package/tools/bsocial/bmapFollow.ts +3 -7
  11. package/tools/bsocial/bmapLikes.ts +3 -3
  12. package/tools/bsocial/bmapReadPosts.ts +3 -3
  13. package/tools/bsocial/createPost.ts +8 -7
  14. package/tools/bsocial/readPosts.ts +3 -3
  15. package/tools/bsv/decodeTransaction.ts +2 -5
  16. package/tools/bsv/explore.ts +2 -3
  17. package/tools/bsv/getPrice.ts +1 -9
  18. package/tools/bsv/token.ts +14 -26
  19. package/tools/index.ts +0 -13
  20. package/tools/mnee/getBalance.ts +2 -4
  21. package/tools/mnee/parseTx.ts +3 -3
  22. package/tools/mnee/sendMnee.ts +5 -5
  23. package/tools/ordinals/getInscription.ts +2 -3
  24. package/tools/ordinals/getTokenByIdOrTicker.ts +6 -3
  25. package/tools/ordinals/marketListings.ts +2 -18
  26. package/tools/ordinals/marketSales.ts +2 -4
  27. package/tools/ordinals/searchInscriptions.ts +2 -4
  28. package/tools/utils/index.ts +14 -16
  29. package/tools/wallet/a2bPublishAgent.ts +18 -27
  30. package/tools/wallet/a2bPublishMcp.ts +17 -22
  31. package/tools/wallet/createOrdinals.ts +11 -20
  32. package/tools/wallet/fetchPaymentUtxos.ts +9 -1
  33. package/tools/wallet/gatherCollectionInfo.ts +9 -13
  34. package/tools/wallet/getAddress.ts +1 -9
  35. package/tools/wallet/getBalance.ts +2 -14
  36. package/tools/wallet/getBalanceDroplet.ts +2 -13
  37. package/tools/wallet/getPublicKey.ts +3 -16
  38. package/tools/wallet/mintCollection.ts +21 -24
  39. package/tools/wallet/purchaseListing.ts +19 -29
  40. package/tools/wallet/refreshUtxos.ts +2 -14
  41. package/tools/wallet/sendOrdinals.ts +11 -20
  42. package/tools/wallet/sendToAddress.ts +2 -22
  43. package/tools/wallet/setupDroplet.ts +7 -18
  44. package/tools/wallet/tools.ts +10 -80
  45. package/tools/wallet/transferOrdToken.ts +12 -20
  46. package/vite.config.ts +15 -0
  47. package/tools/bigblocks/components.ts +0 -304
  48. package/tools/bigblocks/docs.ts +0 -488
  49. package/tools/bigblocks/examples.ts +0 -527
  50. package/tools/bigblocks/generator.ts +0 -485
  51. package/tools/bigblocks/index.ts +0 -23
  52. package/tools/bsocial/bigblocksApiClient.ts +0 -189
@@ -1,10 +1,5 @@
1
1
  import { PrivateKey, Utils } from "@bsv/sdk";
2
2
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
4
- import type {
5
- ServerNotification,
6
- ServerRequest,
7
- } from "@modelcontextprotocol/sdk/types.js";
8
3
  import type {
9
4
  ChangeResult,
10
5
  CreateOrdinalsConfig,
@@ -14,7 +9,6 @@ import type {
14
9
  PreMAP,
15
10
  } from "js-1sat-ord";
16
11
  import { createOrdinals } from "js-1sat-ord";
17
- import { Sigma } from "sigma-protocol";
18
12
  import { z } from "zod";
19
13
  import packageJson from "../../package.json";
20
14
  import { V5Broadcaster } from "../../utils/broadcaster";
@@ -155,11 +149,8 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
155
149
  server.tool(
156
150
  "wallet_a2bPublish",
157
151
  "Publish an agent.json record on-chain via Ordinal inscription",
158
- { args: a2bPublishArgsSchema },
159
- async (
160
- { args }: { args: A2bPublishArgs },
161
- extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
162
- ) => {
152
+ { ...a2bPublishArgsSchema.shape },
153
+ async ({ agentUrl, agentName, description, providerOrganization, providerUrl, version, documentationUrl, streaming, pushNotifications, stateTransitionHistory, defaultInputModes, defaultOutputModes, skills, destinationAddress }) => {
163
154
  try {
164
155
  const paymentPk = wallet.getPaymentKey();
165
156
  if (!paymentPk) throw new Error("No private key available");
@@ -167,7 +158,7 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
167
158
  if (!paymentUtxos?.length)
168
159
  throw new Error("No payment UTXOs available to fund inscription");
169
160
 
170
- // TODO: Get the skills from actually running the MCP instead of trusting the agent args for args.skills
161
+ // TODO: Get the skills from actually running the MCP instead of trusting the agent args for skills
171
162
  const walletAddress = paymentPk.toAddress().toString();
172
163
 
173
164
  // Create pricing plans using the new schema
@@ -212,27 +203,27 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
212
203
 
213
204
  // Assemble AgentCard with defaults and user overrides
214
205
  const agentCard = {
215
- name: args.agentName,
216
- description: args.description ?? null,
217
- url: args.agentUrl,
206
+ name: agentName,
207
+ description: description ?? null,
208
+ url: agentUrl,
218
209
  provider:
219
- args.providerOrganization && args.providerUrl
210
+ providerOrganization && providerUrl
220
211
  ? {
221
- organization: args.providerOrganization,
222
- url: args.providerUrl,
212
+ organization: providerOrganization,
213
+ url: providerUrl,
223
214
  }
224
215
  : null,
225
- version: args.version ?? packageJson.version,
226
- documentationUrl: args.documentationUrl ?? null,
216
+ version: version ?? packageJson.version,
217
+ documentationUrl: documentationUrl ?? null,
227
218
  capabilities: {
228
- streaming: args.streaming,
229
- pushNotifications: args.pushNotifications,
230
- stateTransitionHistory: args.stateTransitionHistory,
219
+ streaming,
220
+ pushNotifications,
221
+ stateTransitionHistory,
231
222
  },
232
223
  authentication: null,
233
- defaultInputModes: args.defaultInputModes,
234
- defaultOutputModes: args.defaultOutputModes,
235
- skills: args.skills,
224
+ defaultInputModes,
225
+ defaultOutputModes,
226
+ skills,
236
227
  "x-payment-config": pricingConfig,
237
228
  };
238
229
  // Validate compliance
@@ -245,7 +236,7 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
245
236
  contentType: "application/json",
246
237
  };
247
238
  // Destination for the ordinal
248
- const targetAddress = args.destinationAddress ?? walletAddress;
239
+ const targetAddress = destinationAddress ?? walletAddress;
249
240
  const destinations: Destination[] = [
250
241
  { address: targetAddress, inscription },
251
242
  ];
@@ -1,9 +1,8 @@
1
- import type { PrivateKey, WalletInterface } from "@bsv/sdk";
1
+ import type { PrivateKey } from "@bsv/sdk";
2
2
  import { Utils } from "@bsv/sdk";
3
3
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
4
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
5
5
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
- import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
7
6
  import type {
8
7
  ClientNotification,
9
8
  ClientRequest,
@@ -19,10 +18,9 @@ import type {
19
18
  PreMAP,
20
19
  } from "js-1sat-ord";
21
20
  import { createOrdinals } from "js-1sat-ord";
22
- import { Sigma } from "sigma-protocol";
23
21
  import { z } from "zod";
24
22
  import packageJson from "../../package.json";
25
- import { BsocialBroadcaster, V5Broadcaster } from "../../utils/broadcaster";
23
+ import { V5Broadcaster } from "../../utils/broadcaster";
26
24
  import type { Wallet } from "./wallet";
27
25
 
28
26
  const { toArray, toBase64 } = Utils;
@@ -196,11 +194,8 @@ export function registerA2bPublishMcpTool(
196
194
  server.tool(
197
195
  "wallet_a2bPublishMcp",
198
196
  "Publish an MCP tool configuration record on-chain via Ordinal inscription. This creates a permanent, immutable, and discoverable tool definition that can be accessed by other MCP servers. The tool is published as a JSON inscription with metadata and optional digital signatures for authenticity verification.",
199
- { args: a2bPublishMcpArgsSchema },
200
- async (
201
- { args }: { args: A2bPublishMcpArgs },
202
- extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
203
- ) => {
197
+ { ...a2bPublishMcpArgsSchema.shape },
198
+ async ({ toolName, command, args, keywords, env, description, destinationAddress }) => {
204
199
  try {
205
200
  if (!identityPk) {
206
201
  console.warn(
@@ -218,20 +213,20 @@ export function registerA2bPublishMcpTool(
218
213
  const walletAddress = paymentPk.toAddress().toString();
219
214
 
220
215
  // Fetch MCP metadata (tools, prompts, resources)
221
- const metadata = await fetchMcpMetadata(args.command, args.args);
216
+ const metadata = await fetchMcpMetadata(command, args);
222
217
  // console.log(`Discovered ${metadata.tools.length} tools, ${metadata.prompts.length} prompts, and ${metadata.resources.length} resources`);
223
218
 
224
219
  // Assemble tool configuration
225
220
  const toolConfig: McpConfig = {
226
- command: args.command,
227
- args: args.args,
221
+ command,
222
+ args,
228
223
  tools: metadata.tools,
229
224
  prompts: metadata.prompts,
230
225
  resources: metadata.resources,
231
- env: args.env
232
- ? args.env.reduce(
233
- (acc, { key, description }) => {
234
- acc[key] = description;
226
+ env: env
227
+ ? env.reduce(
228
+ (acc, { key, description: desc }) => {
229
+ acc[key] = desc;
235
230
  return acc;
236
231
  },
237
232
  {} as Record<string, string>,
@@ -245,9 +240,9 @@ export function registerA2bPublishMcpTool(
245
240
  // Prepare the full configuration with metadata
246
241
  const fullConfig = {
247
242
  mcpServers: {
248
- [args.toolName]: {
249
- description: args.description || "",
250
- keywords: args.keywords || [],
243
+ [toolName]: {
244
+ description: description || "",
245
+ keywords: keywords || [],
251
246
  tools: metadata.tools || [],
252
247
  prompts: metadata.prompts || [],
253
248
  resources: metadata.resources || [],
@@ -266,7 +261,7 @@ export function registerA2bPublishMcpTool(
266
261
  };
267
262
 
268
263
  // Destination for the ordinal
269
- const targetAddress = args.destinationAddress ?? walletAddress;
264
+ const targetAddress = destinationAddress ?? walletAddress;
270
265
  const destinations: Destination[] = [
271
266
  { address: targetAddress, inscription },
272
267
  ];
@@ -335,12 +330,12 @@ export function registerA2bPublishMcpTool(
335
330
  txid,
336
331
  outpoint,
337
332
  onchainUrl,
338
- toolName: args.toolName,
333
+ toolName,
339
334
  toolCount: metadata.tools.length,
340
335
  promptCount: metadata.prompts.length,
341
336
  resourceCount: metadata.resources.length,
342
337
  description:
343
- args.description || `MCP Tool: ${args.toolName}`,
338
+ description || `MCP Tool: ${toolName}`,
344
339
  address: targetAddress,
345
340
  },
346
341
  null,
@@ -1,11 +1,6 @@
1
1
  import { PrivateKey } from "@bsv/sdk";
2
2
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
4
- import type {
5
- CallToolResult,
6
- ServerNotification,
7
- ServerRequest,
8
- } from "@modelcontextprotocol/sdk/types.js";
3
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
9
4
  import type {
10
5
  ChangeResult,
11
6
  CreateOrdinalsCollectionItemMetadata,
@@ -16,10 +11,9 @@ import type {
16
11
  LocalSigner,
17
12
  PreMAP,
18
13
  } from "js-1sat-ord";
19
- import { createOrdinals, OneSatBroadcaster } from "js-1sat-ord";
20
- import { Sigma } from "sigma-protocol";
14
+ import { createOrdinals } from "js-1sat-ord";
21
15
  import { z } from "zod";
22
- import { BsocialBroadcaster, V5Broadcaster } from "../../utils/broadcaster";
16
+ import { V5Broadcaster } from "../../utils/broadcaster";
23
17
  import type { Wallet } from "./wallet";
24
18
 
25
19
  /**
@@ -53,11 +47,8 @@ export function registerCreateOrdinalsTool(server: McpServer, wallet: Wallet) {
53
47
  server.tool(
54
48
  "wallet_createOrdinals",
55
49
  "Creates and inscribes ordinals (NFTs) on the Bitcoin SV blockchain. This tool lets you mint new digital artifacts by encoding data directly into the blockchain. Supports various content types including images, text, JSON, and HTML. The tool handles transaction creation, fee calculation, and broadcasting.",
56
- { args: createOrdinalsArgsSchema },
57
- async (
58
- { args }: { args: CreateOrdinalsArgs },
59
- extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
60
- ): Promise<CallToolResult> => {
50
+ { ...createOrdinalsArgsSchema.shape },
51
+ async ({ dataB64, contentType, destinationAddress, metadata }): Promise<CallToolResult> => {
61
52
  try {
62
53
  // Load optional identity key for sigma signing
63
54
  const identityKeyWif = process.env.IDENTITY_KEY_WIF;
@@ -92,14 +83,14 @@ export function registerCreateOrdinalsTool(server: McpServer, wallet: Wallet) {
92
83
 
93
84
  // 4. Create the inscription object
94
85
  const inscription: Inscription = {
95
- dataB64: args.dataB64,
96
- contentType: args.contentType,
86
+ dataB64: dataB64,
87
+ contentType: contentType,
97
88
  };
98
89
 
99
90
  // 5. Create the destination
100
91
  const destinations: Destination[] = [
101
92
  {
102
- address: args.destinationAddress || walletAddress,
93
+ address: destinationAddress || walletAddress,
103
94
  inscription,
104
95
  },
105
96
  ];
@@ -109,7 +100,7 @@ export function registerCreateOrdinalsTool(server: McpServer, wallet: Wallet) {
109
100
  destinations,
110
101
  paymentPk,
111
102
  changeAddress: walletAddress,
112
- metaData: args.metadata as
103
+ metaData: metadata as
113
104
  | PreMAP
114
105
  | CreateOrdinalsCollectionMetadata
115
106
  | CreateOrdinalsCollectionItemMetadata,
@@ -152,8 +143,8 @@ export function registerCreateOrdinalsTool(server: McpServer, wallet: Wallet) {
152
143
  txid: changeResult.tx.id("hex"),
153
144
  spentOutpoints: changeResult.spentOutpoints,
154
145
  payChange: changeResult.payChange,
155
- inscriptionAddress: args.destinationAddress || walletAddress,
156
- contentType: args.contentType,
146
+ inscriptionAddress: destinationAddress || walletAddress,
147
+ contentType: contentType,
157
148
  }),
158
149
  },
159
150
  ],
@@ -104,7 +104,15 @@ export async function fetchPaymentUtxosFromV5(
104
104
  const url = `${V5_API_URL}/own/${address}/utxos?refresh=true&txo=true&script=true&limit=250&tags=p2pkh`;
105
105
  console.error(`Fetching UTXOs from V5: ${url}`);
106
106
  const response = await fetch(url);
107
- const data = (await response.json()) as V5Utxo[];
107
+ if (!response.ok) {
108
+ console.error(`V5 UTXO fetch failed: ${response.status} ${response.statusText}`);
109
+ return undefined;
110
+ }
111
+ const data = (await response.json()) as V5Utxo[] | null;
112
+ if (!Array.isArray(data)) {
113
+ console.error(`V5 UTXO response was not an array: ${typeof data}`);
114
+ return undefined;
115
+ }
108
116
  const utxos: Utxo[] = [];
109
117
  for (const utxo of data) {
110
118
  if (!utxo.data.p2pkh) {
@@ -133,15 +133,11 @@ export function registerGatherCollectionInfoTool(
133
133
  server.tool(
134
134
  "wallet_gatherCollectionInfo",
135
135
  "Analyzes a folder of images and gathers all necessary information for minting an ordinals collection. This includes validating images, checking wallet balance, estimating costs, and suggesting metadata. Use this before minting to ensure everything is ready.",
136
- { args: gatherCollectionInfoArgsSchema },
137
- async ({
138
- args,
139
- }: {
140
- args: GatherCollectionInfoArgs;
141
- }): Promise<CallToolResult> => {
136
+ { ...gatherCollectionInfoArgsSchema.shape },
137
+ async ({ folderPath }): Promise<CallToolResult> => {
142
138
  try {
143
139
  const analysis: CollectionAnalysis = {
144
- folderPath: args.folderPath,
140
+ folderPath,
145
141
  totalImages: 0,
146
142
  validImages: 0,
147
143
  invalidImages: 0,
@@ -172,13 +168,13 @@ export function registerGatherCollectionInfoTool(
172
168
 
173
169
  // Check if folder exists
174
170
  try {
175
- const folderStat = await fs.stat(args.folderPath);
171
+ const folderStat = await fs.stat(folderPath);
176
172
  if (!folderStat.isDirectory()) {
177
- throw new Error(`Path is not a directory: ${args.folderPath}`);
173
+ throw new Error(`Path is not a directory: ${folderPath}`);
178
174
  }
179
175
  } catch (error) {
180
176
  analysis.errors.push(
181
- `Folder not found or inaccessible: ${args.folderPath}`,
177
+ `Folder not found or inaccessible: ${folderPath}`,
182
178
  );
183
179
  return {
184
180
  content: [
@@ -222,7 +218,7 @@ export function registerGatherCollectionInfoTool(
222
218
  }
223
219
 
224
220
  // Scan folder for images
225
- const files = await fs.readdir(args.folderPath);
221
+ const files = await fs.readdir(folderPath);
226
222
  const imageExtensions = [
227
223
  ".jpg",
228
224
  ".jpeg",
@@ -233,7 +229,7 @@ export function registerGatherCollectionInfoTool(
233
229
  ];
234
230
 
235
231
  for (const file of files) {
236
- const filePath = path.join(args.folderPath, file);
232
+ const filePath = path.join(folderPath, file);
237
233
  const stat = await fs.stat(filePath);
238
234
 
239
235
  if (stat.isFile()) {
@@ -280,7 +276,7 @@ export function registerGatherCollectionInfoTool(
280
276
  }
281
277
 
282
278
  // Suggest metadata based on folder name
283
- const folderName = path.basename(args.folderPath);
279
+ const folderName = path.basename(folderPath);
284
280
  analysis.suggestedMetadata = {
285
281
  collectionName: folderName
286
282
  .replace(/[-_]/g, " ")
@@ -1,5 +1,4 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { z } from "zod";
3
2
  import type { Wallet } from "./wallet";
4
3
 
5
4
  /**
@@ -14,14 +13,7 @@ export function registerGetAddressTool(
14
13
  server.tool(
15
14
  "wallet_getAddress",
16
15
  "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.",
17
- {
18
- args: z
19
- .object({})
20
- .optional()
21
- .describe(
22
- "No parameters required - simply returns the current wallet address",
23
- ),
24
- },
16
+ {},
25
17
  async () => {
26
18
  try {
27
19
  const address = wallet.getAddress();
@@ -1,16 +1,7 @@
1
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
2
  import { toBitcoin } from "satoshi-token"; // For converting satoshis to BSV string
8
- import { z } from "zod";
9
3
  import type { Wallet } from "./wallet";
10
4
 
11
- export const walletGetBalanceArgsSchema = z.object({}).optional();
12
- export type WalletGetBalanceArgs = z.infer<typeof walletGetBalanceArgsSchema>;
13
-
14
5
  /**
15
6
  * Registers the wallet_getBalance tool
16
7
  */
@@ -21,11 +12,8 @@ export function registerWalletGetBalanceTool(
21
12
  server.tool(
22
13
  "wallet_getBalance",
23
14
  "Retrieves the current BSV balance for the wallet based on its UTXOs.",
24
- { args: walletGetBalanceArgsSchema },
25
- async (
26
- args: WalletGetBalanceArgs, // Args are empty but present for schema consistency
27
- extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
28
- ) => {
15
+ {},
16
+ async () => {
29
17
  try {
30
18
  const { paymentUtxos } = await wallet.getUtxos();
31
19
 
@@ -1,11 +1,5 @@
1
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
2
  import type { DropletClient } from "../../utils/droplet";
8
- import { emptyArgsSchema } from "./schemas";
9
3
 
10
4
  /**
11
5
  * Register the getBalance tool for Droplet API mode
@@ -17,13 +11,8 @@ export function registerWalletGetBalanceDropletTool(
17
11
  server.tool(
18
12
  "wallet_getBalance",
19
13
  "Gets the current balance of the wallet (Droplet mode)",
20
- {
21
- args: emptyArgsSchema,
22
- },
23
- async (
24
- { args }: { args: unknown },
25
- extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
26
- ) => {
14
+ {},
15
+ async () => {
27
16
  try {
28
17
  const status = await dropletClient.getFaucetStatus();
29
18
 
@@ -1,16 +1,6 @@
1
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 type { z } from "zod";
8
- import { getPublicKeyArgsSchema } from "./schemas";
9
2
  import type { Wallet } from "./wallet";
10
3
 
11
- // Use the schema imported from schemas.ts
12
- export type GetPublicKeyArgs = z.infer<typeof getPublicKeyArgsSchema>;
13
-
14
4
  /**
15
5
  * Register the getPublicKey tool
16
6
  */
@@ -18,13 +8,10 @@ export function registerGetPublicKeyTool(server: McpServer, wallet: Wallet) {
18
8
  server.tool(
19
9
  "wallet_getPublicKey",
20
10
  "Retrieves the current wallet's public key. This public key can be used for cryptographic operations like signature verification or encryption.",
21
- { args: getPublicKeyArgsSchema },
22
- async (
23
- { args }: { args: GetPublicKeyArgs },
24
- extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
25
- ) => {
11
+ {},
12
+ async () => {
26
13
  try {
27
- const result = await wallet.getPublicKey(args);
14
+ const result = await wallet.getPublicKey({});
28
15
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
29
16
  } catch (err: unknown) {
30
17
  const msg = err instanceof Error ? err.message : String(err);
@@ -2,12 +2,7 @@ import { promises as fs } from "node:fs";
2
2
  import path from "node:path";
3
3
  import { Utils } from "@bsv/sdk";
4
4
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
- import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
6
- import type {
7
- CallToolResult,
8
- ServerNotification,
9
- ServerRequest,
10
- } from "@modelcontextprotocol/sdk/types.js";
5
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
11
6
  import type {
12
7
  ChangeResult,
13
8
  CollectionItemSubTypeData,
@@ -40,10 +35,10 @@ const mintCollectionArgsSchema = z.object({
40
35
  .optional()
41
36
  .describe("Rarity labels and their percentages"),
42
37
  traits: z
43
- .record(z.array(z.string()))
38
+ .string()
44
39
  .optional()
45
40
  .describe(
46
- "Collection traits as key-value pairs where values are arrays of possible trait values",
41
+ 'Collection traits as JSON string of key-value pairs where values are arrays, e.g. \'{"Background": ["Blue", "Red"], "Eyes": ["Big", "Small"]}\'',
47
42
  ),
48
43
  skipBroadcast: z
49
44
  .boolean()
@@ -125,9 +120,11 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
125
120
  server.tool(
126
121
  "wallet_mintCollection",
127
122
  "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.",
128
- { args: mintCollectionArgsSchema },
129
- async ({ args }: { args: MintCollectionArgs }): Promise<CallToolResult> => {
123
+ { ...mintCollectionArgsSchema.shape },
124
+ async ({ folderPath, collectionName, description, rarityLabels, traits: traitsJson, skipBroadcast }): Promise<CallToolResult> => {
130
125
  try {
126
+ // Parse traits JSON string if provided
127
+ const traits: Record<string, string[]> | undefined = traitsJson ? JSON.parse(traitsJson) : undefined;
131
128
  // Get keys from wallet
132
129
  const paymentPk = wallet.getPaymentKey();
133
130
  if (!paymentPk) {
@@ -136,7 +133,7 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
136
133
  const identityPk = wallet.getIdentityKey();
137
134
 
138
135
  // Get image files
139
- const imageFiles = await getImageFiles(args.folderPath);
136
+ const imageFiles = await getImageFiles(folderPath);
140
137
  if (imageFiles.length === 0) {
141
138
  throw new Error("No image files found in the specified folder");
142
139
  }
@@ -145,14 +142,14 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
145
142
 
146
143
  // Prepare collection metadata
147
144
  const collectionSubTypeData: CollectionSubTypeData = {
148
- description: args.description,
145
+ description: description,
149
146
  quantity: imageFiles.length,
150
147
  // Transform rarity labels to correct format
151
148
  rarityLabels:
152
- args.rarityLabels?.map((r) => ({ label: r.label })) || [],
149
+ rarityLabels?.map((r) => ({ label: r.label })) || [],
153
150
  // Transform traits - need to match the CollectionTraits type
154
- traits: args.traits
155
- ? Object.entries(args.traits).reduce((acc, [key, values]) => {
151
+ traits: traits
152
+ ? Object.entries(traits).reduce((acc, [key, values]) => {
156
153
  acc[key] = {
157
154
  values,
158
155
  occurancePercentages: values.map(() =>
@@ -168,14 +165,14 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
168
165
  app: "ord",
169
166
  type: "ord",
170
167
  subType: "collection",
171
- name: args.collectionName,
168
+ name: collectionName,
172
169
  subTypeData: collectionSubTypeData,
173
170
  };
174
171
 
175
172
  // Create collection icon
176
173
  const svgString = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
177
174
  <rect width="100" height="100" fill="#f0f0f0"/>
178
- <text x="50" y="55" text-anchor="middle" font-family="Arial" font-size="16">${args.collectionName}</text>
175
+ <text x="50" y="55" text-anchor="middle" font-family="Arial" font-size="16">${collectionName}</text>
179
176
  </svg>`;
180
177
  const collectionIconData = Utils.toBase64(
181
178
  Utils.toArray(svgString, "utf8"),
@@ -217,7 +214,7 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
217
214
 
218
215
  let collectionTxid = "";
219
216
  const disableBroadcasting =
220
- args.skipBroadcast || process.env.DISABLE_BROADCASTING === "true";
217
+ skipBroadcast || process.env.DISABLE_BROADCASTING === "true";
221
218
 
222
219
  if (!disableBroadcasting) {
223
220
  const broadcaster = new V5Broadcaster();
@@ -251,7 +248,7 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
251
248
  );
252
249
 
253
250
  try {
254
- const itemTraits = generateItemTraits(i, args.traits);
251
+ const itemTraits = generateItemTraits(i, traits);
255
252
 
256
253
  const itemSubTypeData: CollectionItemSubTypeData = {
257
254
  collectionId: collectionTxid,
@@ -260,13 +257,13 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
260
257
  };
261
258
 
262
259
  // Assign rarity if labels provided
263
- if (args.rarityLabels && args.rarityLabels.length > 0) {
260
+ if (rarityLabels && rarityLabels.length > 0) {
264
261
  const rarityIndex = Math.floor(
265
- (i / imageFiles.length) * args.rarityLabels.length,
262
+ (i / imageFiles.length) * rarityLabels.length,
266
263
  );
267
264
  const rarityItem =
268
- args.rarityLabels[
269
- Math.min(rarityIndex, args.rarityLabels.length - 1)
265
+ rarityLabels[
266
+ Math.min(rarityIndex, rarityLabels.length - 1)
270
267
  ];
271
268
  if (rarityItem) {
272
269
  itemSubTypeData.rarityLabel = [
@@ -352,7 +349,7 @@ export function registerMintCollectionTool(server: McpServer, wallet: Wallet) {
352
349
  totalItems: imageFiles.length,
353
350
  errors: results.errors,
354
351
  totalCost: results.totalCost,
355
- summary: `Collection "${args.collectionName}" created with ${results.itemTxids.length}/${imageFiles.length} items successfully minted.${results.errors.length > 0 ? ` ${results.errors.length} items failed.` : ""}`,
352
+ summary: `Collection "${collectionName}" created with ${results.itemTxids.length}/${imageFiles.length} items successfully minted.${results.errors.length > 0 ? ` ${results.errors.length} items failed.` : ""}`,
356
353
  },
357
354
  null,
358
355
  2,