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
@@ -0,0 +1,84 @@
1
+ import { spawn } from "node:child_process";
2
+ import { platform } from "node:os";
3
+ import { z } from "zod";
4
+
5
+ const installAgentMasterSchema = z.object({
6
+ method: z
7
+ .enum(["go", "source", "auto"])
8
+ .optional()
9
+ .describe("Installation method"),
10
+ });
11
+
12
+ /**
13
+ * Install the Agent Master CLI tool for managing MCP server configurations
14
+ */
15
+ export async function installAgentMaster(
16
+ args: z.infer<typeof installAgentMasterSchema>,
17
+ ) {
18
+ const method = args.method || "auto";
19
+
20
+ return new Promise((resolve, reject) => {
21
+ let command: string;
22
+ let commandArgs: string[] = [];
23
+
24
+ if (method === "auto" || method === "go") {
25
+ // Try go install first
26
+ command = "go";
27
+ commandArgs = ["install", "github.com/b-open-io/agent-master-cli@latest"];
28
+ } else if (method === "source") {
29
+ // Install from source
30
+ reject(
31
+ new Error(
32
+ "Source installation requires manual steps. Please run:\ngit clone https://github.com/b-open-io/agent-master-cli.git\ncd agent-master-cli\nmake deps && make build && make install",
33
+ ),
34
+ );
35
+ return;
36
+ }
37
+
38
+ console.error(`🔧 Installing Agent Master CLI using ${method} method...`);
39
+
40
+ const install = spawn(command, commandArgs, {
41
+ stdio: "inherit",
42
+ shell: true,
43
+ });
44
+
45
+ install.on("error", (error) => {
46
+ if (method === "auto" && command === "go") {
47
+ // If go install fails in auto mode, provide instructions
48
+ reject(
49
+ new Error(
50
+ "Go installation failed. Please ensure Go is installed or try manual installation:\n\n1. Install Go from https://golang.org/dl/\n2. Run: go install github.com/b-open-io/agent-master-cli@latest\n\nOr install from source:\ngit clone https://github.com/b-open-io/agent-master-cli.git\ncd agent-master-cli\nmake deps && make build && make install",
51
+ ),
52
+ );
53
+ } else {
54
+ reject(error);
55
+ }
56
+ });
57
+
58
+ install.on("close", (code) => {
59
+ if (code !== 0) {
60
+ reject(new Error(`Installation failed with code ${code}`));
61
+ } else {
62
+ resolve({
63
+ success: true,
64
+ message:
65
+ "✅ Agent Master CLI installed successfully!\n\nGet started with:\n agent-master init --with-demo\n agent-master list\n agent-master sync --preset claude",
66
+ nextSteps: [
67
+ "Initialize configuration: agent-master init --with-demo",
68
+ "List servers: agent-master list",
69
+ 'Add BSV MCP: agent-master add bsv-mcp --transport stdio --command "bunx" --args "bsv-mcp@latest"',
70
+ "Sync to Claude: agent-master sync --preset claude",
71
+ ],
72
+ });
73
+ }
74
+ });
75
+ });
76
+ }
77
+
78
+ export const installAgentMasterTool = {
79
+ name: "utils_installAgentMaster",
80
+ description:
81
+ "Install the Agent Master CLI tool for managing MCP server configurations across multiple platforms (Claude, VS Code, Cursor, etc.)",
82
+ inputSchema: installAgentMasterSchema,
83
+ handler: installAgentMaster,
84
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Simple logger utility for consistent output formatting
3
+ */
4
+ export const logger = {
5
+ info: (message: string) => console.error(`ℹ️ ${message}`),
6
+ success: (message: string) => console.error(`✅ ${message}`),
7
+ warn: (message: string) => console.error(`⚠️ ${message}`),
8
+ error: (message: string, error?: unknown) => {
9
+ if (error) {
10
+ console.error(`❌ ${message}:`, error);
11
+ } else {
12
+ console.error(`❌ ${message}`);
13
+ }
14
+ },
15
+ debug: (message: string, ...args: unknown[]) => {
16
+ if (process.env.DEBUG === "true") {
17
+ console.error(`🐛 ${message}`, ...args);
18
+ }
19
+ },
20
+ };
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Tool category configuration
3
+ */
4
+ export interface ToolCategory {
5
+ name: string;
6
+ envVar: string;
7
+ defaultEnabled: boolean;
8
+ register: (server: unknown, config?: unknown) => void;
9
+ dependencies?: string[]; // Other categories this depends on
10
+ }
11
+
12
+ /**
13
+ * Check if a tool category is enabled based on environment and config
14
+ */
15
+ export function isToolEnabled(
16
+ category: ToolCategory,
17
+ config: Record<string, boolean | undefined> = {},
18
+ ): boolean {
19
+ const configKey = `enable${category.name}Tools`;
20
+
21
+ // Check config override first
22
+ if (configKey in config && config[configKey] !== undefined) {
23
+ return config[configKey] as boolean;
24
+ }
25
+
26
+ // Check environment variable
27
+ const envValue = process.env[category.envVar];
28
+ if (envValue !== undefined) {
29
+ // For ENABLE_* vars, check if === "true"
30
+ // For DISABLE_* vars, check if !== "true"
31
+ if (category.envVar.startsWith("ENABLE_")) {
32
+ return envValue === "true";
33
+ }
34
+ return envValue !== "true";
35
+ }
36
+
37
+ // Return default
38
+ return category.defaultEnabled;
39
+ }
40
+
41
+ /**
42
+ * Register multiple tool categories with their dependencies
43
+ */
44
+ export function registerToolCategories(
45
+ server: unknown,
46
+ categories: ToolCategory[],
47
+ config: Record<string, boolean | undefined> = {},
48
+ ): void {
49
+ const enabled: Set<string> = new Set();
50
+
51
+ // First pass: determine what's enabled
52
+ for (const category of categories) {
53
+ if (isToolEnabled(category, config)) {
54
+ enabled.add(category.name);
55
+ }
56
+ }
57
+
58
+ // Second pass: register enabled categories
59
+ for (const category of categories) {
60
+ if (enabled.has(category.name)) {
61
+ // Check dependencies
62
+ const missingDeps =
63
+ category.dependencies?.filter((dep) => !enabled.has(dep)) || [];
64
+ if (missingDeps.length > 0) {
65
+ console.warn(
66
+ `⚠️ ${category.name} tools not registered (missing dependencies: ${missingDeps.join(", ")})`,
67
+ );
68
+ continue;
69
+ }
70
+
71
+ // Register the category
72
+ try {
73
+ category.register(server, config);
74
+ console.error(`✅ Registered ${category.name} tools`);
75
+ } catch (error) {
76
+ console.error(`❌ Failed to register ${category.name} tools:`, error);
77
+ }
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Common tool registration utilities for the BSV MCP server
3
+ */
4
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import type { z } from "zod";
6
+
7
+ export interface ToolConfig<TArgs = Record<string, unknown>> {
8
+ name: string;
9
+ description: string;
10
+ schema: z.ZodSchema<TArgs>;
11
+ handler: (args: TArgs) => Promise<ToolResponse>;
12
+ }
13
+
14
+ export interface ToolResponse {
15
+ content: Array<{
16
+ type: "text";
17
+ text: string;
18
+ }>;
19
+ isError?: boolean;
20
+ }
21
+
22
+ /**
23
+ * Register a tool with standard error handling and response formatting
24
+ */
25
+ export function registerTool<TArgs = Record<string, unknown>>(
26
+ server: McpServer,
27
+ config: ToolConfig<TArgs>,
28
+ ): void {
29
+ server.tool(config.name, config.schema, async (args: TArgs) => {
30
+ try {
31
+ return await config.handler(args);
32
+ } catch (error) {
33
+ return {
34
+ content: [
35
+ {
36
+ type: "text" as const,
37
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
38
+ },
39
+ ],
40
+ isError: true,
41
+ };
42
+ }
43
+ });
44
+ }
45
+
46
+ /**
47
+ * Helper function to create a simple tool registration function
48
+ */
49
+ export function createToolRegistration<TDeps = undefined>(
50
+ toolName: string,
51
+ description: string,
52
+ schema: z.ZodSchema<Record<string, unknown>>,
53
+ handler: (
54
+ args: Record<string, unknown>,
55
+ deps?: TDeps,
56
+ ) => Promise<ToolResponse>,
57
+ ) {
58
+ return (server: McpServer, deps?: TDeps) => {
59
+ registerTool(server, {
60
+ name: toolName,
61
+ description,
62
+ schema,
63
+ handler: (args) => handler(args, deps),
64
+ });
65
+ };
66
+ }
@@ -0,0 +1,196 @@
1
+ import {
2
+ isBroadcastFailure,
3
+ isBroadcastResponse,
4
+ P2PKH,
5
+ type PrivateKey,
6
+ Script,
7
+ Transaction,
8
+ Utils,
9
+ } from "@bsv/sdk";
10
+ import { V5Broadcaster } from "../../utils/broadcaster";
11
+ import type { Utxo } from "../wallet/utxo";
12
+
13
+ const DEFAULT_SAT_PER_BYTE = 0.05;
14
+ const DUST_LIMIT = 546;
15
+
16
+ interface TransactionBuilderConfig {
17
+ outputs: Array<{
18
+ script?: Script;
19
+ address?: string;
20
+ satoshis: number;
21
+ }>;
22
+ utxos: Utxo[];
23
+ changeAddress: string;
24
+ paymentKey: PrivateKey;
25
+ feePerByte?: number;
26
+ }
27
+
28
+ interface TransactionResult {
29
+ success: boolean;
30
+ txid?: string;
31
+ rawTx?: string;
32
+ error?: string;
33
+ fee?: number;
34
+ }
35
+
36
+ /**
37
+ * Build and optionally broadcast a transaction with automatic UTXO selection and fee calculation
38
+ */
39
+ export async function buildAndSendTransaction(
40
+ config: TransactionBuilderConfig,
41
+ broadcast = true,
42
+ ): Promise<TransactionResult> {
43
+ const {
44
+ outputs,
45
+ utxos,
46
+ changeAddress,
47
+ paymentKey,
48
+ feePerByte = DEFAULT_SAT_PER_BYTE,
49
+ } = config;
50
+
51
+ if (!utxos || utxos.length === 0) {
52
+ return {
53
+ success: false,
54
+ error: "No UTXOs available to fund transaction",
55
+ };
56
+ }
57
+
58
+ const tx = new Transaction();
59
+ const p2pkh = new P2PKH();
60
+
61
+ // Add all outputs
62
+ for (const output of outputs) {
63
+ if (output.script) {
64
+ tx.addOutput({
65
+ lockingScript: output.script,
66
+ satoshis: output.satoshis,
67
+ });
68
+ } else if (output.address) {
69
+ tx.addOutput({
70
+ lockingScript: p2pkh.lock(output.address),
71
+ satoshis: output.satoshis,
72
+ });
73
+ }
74
+ }
75
+
76
+ // Calculate total output amount
77
+ const totalOutputSatoshis = outputs.reduce(
78
+ (sum, out) => sum + out.satoshis,
79
+ 0,
80
+ );
81
+
82
+ // Select UTXOs and add inputs
83
+ let totalInputSatoshis = 0;
84
+ const selectedUtxos: Utxo[] = [];
85
+
86
+ // Sort UTXOs by value (ascending) to minimize the number of inputs
87
+ const sortedUtxos = [...utxos].sort((a, b) => a.satoshis - b.satoshis);
88
+
89
+ for (const utxo of sortedUtxos) {
90
+ selectedUtxos.push(utxo);
91
+ totalInputSatoshis += utxo.satoshis;
92
+
93
+ const input = {
94
+ sourceTransaction: utxo.tx,
95
+ sourceOutputIndex: utxo.vout,
96
+ unlockingScriptTemplate: p2pkh.unlock(paymentKey),
97
+ };
98
+ tx.addInput(input);
99
+
100
+ // Estimate fee with current inputs
101
+ const estimatedSize = tx.toHex().length / 2 + 150; // rough estimate for unsigned tx
102
+ const estimatedFee = Math.ceil(estimatedSize * feePerByte);
103
+
104
+ // Check if we have enough to cover outputs + fee + potential change
105
+ if (totalInputSatoshis >= totalOutputSatoshis + estimatedFee + DUST_LIMIT) {
106
+ break;
107
+ }
108
+ }
109
+
110
+ // Calculate final fee
111
+ const estimatedSize = tx.toHex().length / 2 + 35; // more accurate with all inputs
112
+ const fee = Math.ceil(estimatedSize * feePerByte);
113
+
114
+ // Check if we have enough funds
115
+ if (totalInputSatoshis < totalOutputSatoshis + fee) {
116
+ return {
117
+ success: false,
118
+ error: `Insufficient funds. Have ${totalInputSatoshis} sats, need ${totalOutputSatoshis + fee} sats`,
119
+ };
120
+ }
121
+
122
+ // Add change output if needed
123
+ const change = totalInputSatoshis - totalOutputSatoshis - fee;
124
+ if (change >= DUST_LIMIT) {
125
+ tx.addOutput({
126
+ lockingScript: p2pkh.lock(changeAddress),
127
+ satoshis: change,
128
+ });
129
+ }
130
+
131
+ // Sign the transaction
132
+ await tx.sign();
133
+
134
+ const rawTx = tx.toHex();
135
+ const txid = tx.id("hex") as string;
136
+
137
+ // Check if broadcasting is disabled
138
+ if (process.env.DISABLE_BROADCASTING === "true" || !broadcast) {
139
+ return {
140
+ success: true,
141
+ txid,
142
+ rawTx,
143
+ fee,
144
+ };
145
+ }
146
+
147
+ // Broadcast the transaction
148
+ try {
149
+ const broadcaster = new V5Broadcaster();
150
+ const broadcastResult = await tx.broadcast(broadcaster);
151
+
152
+ if (isBroadcastResponse(broadcastResult)) {
153
+ return {
154
+ success: true,
155
+ txid: broadcastResult.txid || txid,
156
+ rawTx,
157
+ fee,
158
+ };
159
+ }
160
+ if (isBroadcastFailure(broadcastResult)) {
161
+ return {
162
+ success: true,
163
+ txid,
164
+ rawTx,
165
+ fee,
166
+ error: `Transaction created but broadcast failed: ${broadcastResult.description}`,
167
+ };
168
+ }
169
+ return {
170
+ success: true,
171
+ txid,
172
+ rawTx,
173
+ fee,
174
+ error: "Transaction created but broadcast status uncertain",
175
+ };
176
+ } catch (error) {
177
+ return {
178
+ success: true,
179
+ txid,
180
+ rawTx,
181
+ fee,
182
+ error: `Transaction created but broadcast failed: ${error instanceof Error ? error.message : String(error)}`,
183
+ };
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Build OP_RETURN script from data arrays
189
+ */
190
+ export function buildOpReturnScript(dataArrays: Uint8Array[]): Script {
191
+ return new Script([
192
+ { op: 0 }, // OP_0
193
+ { op: 106 }, // OP_RETURN
194
+ ...dataArrays.map((data) => ({ data })),
195
+ ]);
196
+ }
@@ -5,7 +5,6 @@ import type {
5
5
  ServerNotification,
6
6
  ServerRequest,
7
7
  } from "@modelcontextprotocol/sdk/types.js";
8
- import { createOrdinals } from "js-1sat-ord";
9
8
  import type {
10
9
  ChangeResult,
11
10
  CreateOrdinalsConfig,
@@ -14,9 +13,13 @@ import type {
14
13
  LocalSigner,
15
14
  PreMAP,
16
15
  } from "js-1sat-ord";
16
+ import { createOrdinals } from "js-1sat-ord";
17
17
  import { Sigma } from "sigma-protocol";
18
18
  import { z } from "zod";
19
+ import packageJson from "../../package.json";
20
+ import { V5Broadcaster } from "../../utils/broadcaster";
19
21
  import type { Wallet } from "./wallet";
22
+
20
23
  const { toArray, toBase64 } = Utils;
21
24
 
22
25
  // https://raw.githubusercontent.com/google/A2A/refs/heads/main/specification/json/a2a.json
@@ -158,7 +161,7 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
158
161
  extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
159
162
  ) => {
160
163
  try {
161
- const paymentPk = wallet.getPrivateKey();
164
+ const paymentPk = wallet.getPaymentKey();
162
165
  if (!paymentPk) throw new Error("No private key available");
163
166
  const { paymentUtxos } = await wallet.getUtxos();
164
167
  if (!paymentUtxos?.length)
@@ -219,7 +222,7 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
219
222
  url: args.providerUrl,
220
223
  }
221
224
  : null,
222
- version: args.version ?? "1.0.0",
225
+ version: args.version ?? packageJson.version,
223
226
  documentationUrl: args.documentationUrl ?? null,
224
227
  capabilities: {
225
228
  streaming: args.streaming,
@@ -272,7 +275,8 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
272
275
 
273
276
  const disableBroadcasting = process.env.DISABLE_BROADCASTING === "true";
274
277
  if (!disableBroadcasting) {
275
- await changeResult.tx.broadcast();
278
+ const broadcaster = new V5Broadcaster();
279
+ await changeResult.tx.broadcast(broadcaster);
276
280
 
277
281
  // Refresh UTXOs
278
282
  try {
@@ -1,4 +1,5 @@
1
- import { PrivateKey, Utils } from "@bsv/sdk";
1
+ import type { PrivateKey, WalletInterface } from "@bsv/sdk";
2
+ import { Utils } from "@bsv/sdk";
2
3
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
4
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
4
5
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -9,7 +10,6 @@ import type {
9
10
  ServerNotification,
10
11
  ServerRequest,
11
12
  } from "@modelcontextprotocol/sdk/types.js";
12
- import { createOrdinals } from "js-1sat-ord";
13
13
  import type {
14
14
  ChangeResult,
15
15
  CreateOrdinalsConfig,
@@ -18,9 +18,13 @@ import type {
18
18
  LocalSigner,
19
19
  PreMAP,
20
20
  } from "js-1sat-ord";
21
+ import { createOrdinals } from "js-1sat-ord";
21
22
  import { Sigma } from "sigma-protocol";
22
23
  import { z } from "zod";
24
+ import packageJson from "../../package.json";
25
+ import { BsocialBroadcaster, V5Broadcaster } from "../../utils/broadcaster";
23
26
  import type { Wallet } from "./wallet";
27
+
24
28
  const { toArray, toBase64 } = Utils;
25
29
 
26
30
  // API endpoint for the A2B Overlay service
@@ -134,7 +138,7 @@ async function fetchMcpMetadata(
134
138
  // Create and connect a client
135
139
  client = new Client({
136
140
  name: "metadata-fetcher",
137
- version: "1.0.0",
141
+ version: packageJson.version,
138
142
  });
139
143
 
140
144
  await client.connect(transport);
@@ -186,6 +190,7 @@ async function fetchMcpMetadata(
186
190
  export function registerA2bPublishMcpTool(
187
191
  server: McpServer,
188
192
  wallet: Wallet,
193
+ identityPk: PrivateKey | undefined,
189
194
  config: { disableBroadcasting: boolean },
190
195
  ) {
191
196
  server.tool(
@@ -197,22 +202,14 @@ export function registerA2bPublishMcpTool(
197
202
  extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
198
203
  ) => {
199
204
  try {
200
- // Load optional identity key for sigma signing
201
- const identityKeyWif = process.env.IDENTITY_KEY_WIF;
202
- let identityPk: PrivateKey | undefined;
203
- if (identityKeyWif) {
204
- try {
205
- identityPk = PrivateKey.fromWif(identityKeyWif);
206
- } catch (e) {
207
- console.warn(
208
- "Warning: Invalid IDENTITY_KEY_WIF environment variable; sigma signing disabled",
209
- e,
210
- );
211
- }
205
+ if (!identityPk) {
206
+ console.warn(
207
+ "Warning: No identity key provided; sigma signing disabled for A2B MCP publish",
208
+ );
212
209
  }
213
210
 
214
- const paymentPk = wallet.getPrivateKey();
215
- if (!paymentPk) throw new Error("No private key available");
211
+ const paymentPk = wallet.getPaymentKey();
212
+ if (!paymentPk) throw new Error("No payment private key available");
216
213
 
217
214
  const { paymentUtxos } = await wallet.getUtxos();
218
215
  if (!paymentUtxos?.length)
@@ -284,20 +281,27 @@ export function registerA2bPublishMcpTool(
284
281
  changeAddress: walletAddress,
285
282
  metaData,
286
283
  } as CreateOrdinalsConfig;
284
+
285
+ // Use the passed identityPk for signing if available
287
286
  if (identityPk) {
288
287
  createOrdinalsConfig.signer = {
289
288
  idKey: identityPk,
290
289
  } as LocalSigner;
291
290
  }
292
- // Inscribe the ordinal on-chain via js-1sat-ord
293
- const result = await createOrdinals(createOrdinalsConfig);
294
291
 
295
- const changeResult = result as ChangeResult;
292
+ // Inscribe the ordinal on-chain via js-1sat-ord
293
+ let result: ChangeResult | undefined;
294
+ if (!config.disableBroadcasting) {
295
+ result = await createOrdinals(createOrdinalsConfig);
296
+ } else {
297
+ console.warn("Broadcasting disabled. Transaction not created.");
298
+ }
296
299
 
297
300
  // Broadcast the transaction
298
- if (!config.disableBroadcasting) {
299
- await changeResult.tx.broadcast();
300
- const txid = changeResult.tx.id("hex");
301
+ if (!config.disableBroadcasting && result) {
302
+ const broadcaster = new V5Broadcaster();
303
+ await result.tx.broadcast(broadcaster);
304
+ const txid = result.tx.id("hex");
301
305
 
302
306
  setTimeout(async () => {
303
307
  // Call the ingest endpoint to process the transaction
@@ -350,7 +354,7 @@ export function registerA2bPublishMcpTool(
350
354
  content: [
351
355
  {
352
356
  type: "text",
353
- text: changeResult.tx.toHex(),
357
+ text: result?.tx.toHex() || "",
354
358
  },
355
359
  ],
356
360
  };
@@ -6,7 +6,6 @@ import type {
6
6
  ServerNotification,
7
7
  ServerRequest,
8
8
  } from "@modelcontextprotocol/sdk/types.js";
9
- import { createOrdinals } from "js-1sat-ord";
10
9
  import type {
11
10
  ChangeResult,
12
11
  CreateOrdinalsCollectionItemMetadata,
@@ -17,8 +16,10 @@ import type {
17
16
  LocalSigner,
18
17
  PreMAP,
19
18
  } from "js-1sat-ord";
19
+ import { createOrdinals, OneSatBroadcaster } from "js-1sat-ord";
20
20
  import { Sigma } from "sigma-protocol";
21
21
  import { z } from "zod";
22
+ import { BsocialBroadcaster, V5Broadcaster } from "../../utils/broadcaster";
22
23
  import type { Wallet } from "./wallet";
23
24
 
24
25
  /**
@@ -129,7 +130,8 @@ export function registerCreateOrdinalsTool(server: McpServer, wallet: Wallet) {
129
130
 
130
131
  const disableBroadcasting = process.env.DISABLE_BROADCASTING === "true";
131
132
  if (!disableBroadcasting) {
132
- await changeResult.tx.broadcast();
133
+ const broadcaster = new V5Broadcaster();
134
+ await changeResult.tx.broadcast(broadcaster);
133
135
 
134
136
  // 8. Refresh the wallet's UTXOs after spending
135
137
  try {