bsv-mcp 0.0.36 → 0.2.7

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 (78) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/README.md +233 -4
  3. package/dist/index.js +120082 -54669
  4. package/index.ts +1196 -88
  5. package/next-env.d.ts +6 -0
  6. package/package.json +58 -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/a2b/discover.ts +13 -13
  16. package/tools/bap/friend.ts +266 -0
  17. package/tools/bap/generate.test.ts +350 -0
  18. package/tools/bap/generate.ts +431 -0
  19. package/tools/bap/getCurrentAddress.ts +69 -0
  20. package/tools/bap/getId.test.ts +121 -0
  21. package/tools/bap/getId.ts +169 -0
  22. package/tools/bap/index.ts +111 -0
  23. package/tools/bap/types.ts +66 -0
  24. package/tools/bap/utils.ts +33 -0
  25. package/tools/bsocial/bmapFollow.ts +121 -0
  26. package/tools/bsocial/bmapLikes.ts +111 -0
  27. package/tools/bsocial/bmapReadPosts.ts +148 -0
  28. package/tools/bsocial/createPost.ts +136 -0
  29. package/tools/bsocial/index.ts +45 -0
  30. package/tools/bsocial/readPosts.ts +255 -0
  31. package/tools/bsv/decodeTransaction.ts +7 -6
  32. package/tools/bsv/explore.ts +2 -3
  33. package/tools/bsv/getPrice.ts +1 -9
  34. package/tools/bsv/token.ts +14 -26
  35. package/tools/constants.ts +21 -0
  36. package/tools/index.ts +91 -18
  37. package/tools/mnee/getBalance.ts +2 -4
  38. package/tools/mnee/index.ts +8 -0
  39. package/tools/mnee/parseTx.ts +4 -4
  40. package/tools/mnee/sendMnee.ts +6 -6
  41. package/tools/ordinals/getInscription.ts +2 -3
  42. package/tools/ordinals/getTokenByIdOrTicker.ts +6 -3
  43. package/tools/ordinals/marketListings.ts +2 -18
  44. package/tools/ordinals/marketSales.ts +2 -4
  45. package/tools/ordinals/searchInscriptions.ts +2 -4
  46. package/tools/utils/aip.ts +46 -0
  47. package/tools/utils/conversion.ts +1 -0
  48. package/tools/utils/errorHandler.ts +76 -0
  49. package/tools/utils/index.ts +56 -14
  50. package/tools/utils/installAgentMaster.ts +84 -0
  51. package/tools/utils/logger.ts +20 -0
  52. package/tools/utils/toolConfig.ts +80 -0
  53. package/tools/utils/toolRegistration.ts +66 -0
  54. package/tools/utils/transactionBuilder.ts +196 -0
  55. package/tools/wallet/a2bPublishAgent.ts +25 -30
  56. package/tools/wallet/a2bPublishMcp.ts +43 -44
  57. package/tools/wallet/createOrdinals.ts +13 -20
  58. package/tools/wallet/fetchPaymentUtxos.ts +48 -39
  59. package/tools/wallet/gatherCollectionInfo.ts +370 -0
  60. package/tools/wallet/getAddress.ts +14 -30
  61. package/tools/wallet/getBalance.ts +54 -0
  62. package/tools/wallet/getBalanceDroplet.ts +48 -0
  63. package/tools/wallet/getPublicKey.ts +3 -16
  64. package/tools/wallet/integratedWallet.ts +120 -0
  65. package/tools/wallet/mintCollection.ts +373 -0
  66. package/tools/wallet/purchaseListing.ts +21 -31
  67. package/tools/wallet/refreshUtxos.ts +2 -14
  68. package/tools/wallet/schemas.ts +18 -249
  69. package/tools/wallet/sendOrdinals.ts +14 -21
  70. package/tools/wallet/sendToAddress.ts +2 -18
  71. package/tools/wallet/setupDroplet.ts +161 -0
  72. package/tools/wallet/tools.ts +55 -210
  73. package/tools/wallet/transactionHelper.ts +121 -0
  74. package/tools/wallet/transferOrdToken.ts +19 -24
  75. package/tools/wallet/utxo.ts +62 -0
  76. package/tools/wallet/wallet.ts +237 -234
  77. package/vite.config.ts +15 -0
  78. package/tools/a2b/call.ts +0 -32
@@ -1,14 +1,50 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { z } from "zod";
3
3
  import { convertData } from "./conversion";
4
+ import { installAgentMasterTool } from "./installAgentMaster";
4
5
 
5
6
  const encodingSchema = z.enum(["utf8", "hex", "base64", "binary"]);
6
7
 
7
8
  /**
8
- * Register the unified conversion tool with the MCP server
9
+ * Register utility tools with the MCP server
9
10
  * @param server The MCP server instance
10
11
  */
11
12
  export function registerUtilsTools(server: McpServer): void {
13
+ // Register install agent master tool
14
+ server.tool(
15
+ installAgentMasterTool.name,
16
+ installAgentMasterTool.description,
17
+ { ...installAgentMasterTool.inputSchema.shape },
18
+ async (params) => {
19
+ try {
20
+ const result = await installAgentMasterTool.handler(params);
21
+ return {
22
+ content: [
23
+ {
24
+ type: "text",
25
+ text:
26
+ typeof result === "string"
27
+ ? result
28
+ : JSON.stringify(result, null, 2),
29
+ },
30
+ ],
31
+ };
32
+ } catch (err: unknown) {
33
+ const msg = err instanceof Error ? err.message : String(err);
34
+ return {
35
+ content: [
36
+ {
37
+ type: "text",
38
+ text: `Error: ${msg}`,
39
+ },
40
+ ],
41
+ isError: true,
42
+ };
43
+ }
44
+ },
45
+ );
46
+
47
+ // Register conversion tool
12
48
  server.tool(
13
49
  "utils_convertData",
14
50
  "Converts data between different encodings (utf8, hex, base64, binary). Useful for transforming data formats when working with blockchain data, encryption, or file processing.\n\n" +
@@ -26,22 +62,20 @@ export function registerUtilsTools(server: McpServer): void {
26
62
  "- The tool returns the converted data as a string\n" +
27
63
  "- For binary conversion, data is represented as an array of byte values",
28
64
  {
29
- args: z.object({
30
- data: z.string().describe("The data string to be converted"),
31
- from: encodingSchema.describe(
32
- "Source encoding format (utf8, hex, base64, or binary)",
33
- ),
34
- to: encodingSchema.describe(
35
- "Target encoding format to convert to (utf8, hex, base64, or binary)",
36
- ),
37
- }),
65
+ data: z.string().describe("The data string to be converted"),
66
+ from: encodingSchema.describe(
67
+ "Source encoding format (utf8, hex, base64, or binary)",
68
+ ),
69
+ to: encodingSchema.describe(
70
+ "Target encoding format to convert to (utf8, hex, base64, or binary)",
71
+ ),
38
72
  },
39
- async ({ args }) => {
73
+ async ({ data, from, to }) => {
40
74
  try {
41
75
  const result = convertData({
42
- data: args.data,
43
- from: args.from,
44
- to: args.to,
76
+ data,
77
+ from,
78
+ to,
45
79
  });
46
80
  return {
47
81
  content: [
@@ -66,3 +100,11 @@ export function registerUtilsTools(server: McpServer): void {
66
100
  },
67
101
  );
68
102
  }
103
+
104
+ export * from "./aip";
105
+ // Export all utilities for use by other tools
106
+ export * from "./errorHandler";
107
+ export * from "./logger";
108
+ export * from "./toolConfig";
109
+ export * from "./toolRegistration";
110
+ export * from "./transactionBuilder";
@@ -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
+ }
@@ -1,11 +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
- import { createOrdinals } from "js-1sat-ord";
9
3
  import type {
10
4
  ChangeResult,
11
5
  CreateOrdinalsConfig,
@@ -14,9 +8,12 @@ import type {
14
8
  LocalSigner,
15
9
  PreMAP,
16
10
  } from "js-1sat-ord";
17
- import { Sigma } from "sigma-protocol";
11
+ import { createOrdinals } from "js-1sat-ord";
18
12
  import { z } from "zod";
13
+ import packageJson from "../../package.json";
14
+ import { V5Broadcaster } from "../../utils/broadcaster";
19
15
  import type { Wallet } from "./wallet";
16
+
20
17
  const { toArray, toBase64 } = Utils;
21
18
 
22
19
  // https://raw.githubusercontent.com/google/A2A/refs/heads/main/specification/json/a2a.json
@@ -152,19 +149,16 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
152
149
  server.tool(
153
150
  "wallet_a2bPublish",
154
151
  "Publish an agent.json record on-chain via Ordinal inscription",
155
- { args: a2bPublishArgsSchema },
156
- async (
157
- { args }: { args: A2bPublishArgs },
158
- extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
159
- ) => {
152
+ { ...a2bPublishArgsSchema.shape },
153
+ async ({ agentUrl, agentName, description, providerOrganization, providerUrl, version, documentationUrl, streaming, pushNotifications, stateTransitionHistory, defaultInputModes, defaultOutputModes, skills, destinationAddress }) => {
160
154
  try {
161
- const paymentPk = wallet.getPrivateKey();
155
+ const paymentPk = wallet.getPaymentKey();
162
156
  if (!paymentPk) throw new Error("No private key available");
163
157
  const { paymentUtxos } = await wallet.getUtxos();
164
158
  if (!paymentUtxos?.length)
165
159
  throw new Error("No payment UTXOs available to fund inscription");
166
160
 
167
- // 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
168
162
  const walletAddress = paymentPk.toAddress().toString();
169
163
 
170
164
  // Create pricing plans using the new schema
@@ -209,27 +203,27 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
209
203
 
210
204
  // Assemble AgentCard with defaults and user overrides
211
205
  const agentCard = {
212
- name: args.agentName,
213
- description: args.description ?? null,
214
- url: args.agentUrl,
206
+ name: agentName,
207
+ description: description ?? null,
208
+ url: agentUrl,
215
209
  provider:
216
- args.providerOrganization && args.providerUrl
210
+ providerOrganization && providerUrl
217
211
  ? {
218
- organization: args.providerOrganization,
219
- url: args.providerUrl,
212
+ organization: providerOrganization,
213
+ url: providerUrl,
220
214
  }
221
215
  : null,
222
- version: args.version ?? "1.0.0",
223
- documentationUrl: args.documentationUrl ?? null,
216
+ version: version ?? packageJson.version,
217
+ documentationUrl: documentationUrl ?? null,
224
218
  capabilities: {
225
- streaming: args.streaming,
226
- pushNotifications: args.pushNotifications,
227
- stateTransitionHistory: args.stateTransitionHistory,
219
+ streaming,
220
+ pushNotifications,
221
+ stateTransitionHistory,
228
222
  },
229
223
  authentication: null,
230
- defaultInputModes: args.defaultInputModes,
231
- defaultOutputModes: args.defaultOutputModes,
232
- skills: args.skills,
224
+ defaultInputModes,
225
+ defaultOutputModes,
226
+ skills,
233
227
  "x-payment-config": pricingConfig,
234
228
  };
235
229
  // Validate compliance
@@ -242,7 +236,7 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
242
236
  contentType: "application/json",
243
237
  };
244
238
  // Destination for the ordinal
245
- const targetAddress = args.destinationAddress ?? walletAddress;
239
+ const targetAddress = destinationAddress ?? walletAddress;
246
240
  const destinations: Destination[] = [
247
241
  { address: targetAddress, inscription },
248
242
  ];
@@ -272,7 +266,8 @@ export function registerA2bPublishAgentTool(server: McpServer, wallet: Wallet) {
272
266
 
273
267
  const disableBroadcasting = process.env.DISABLE_BROADCASTING === "true";
274
268
  if (!disableBroadcasting) {
275
- await changeResult.tx.broadcast();
269
+ const broadcaster = new V5Broadcaster();
270
+ await changeResult.tx.broadcast(broadcaster);
276
271
 
277
272
  // Refresh UTXOs
278
273
  try {