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.
- package/CHANGELOG.md +112 -1
- package/README.md +233 -4
- package/dist/index.js +111762 -0
- package/index.ts +804 -86
- package/next-env.d.ts +6 -0
- package/package.json +57 -15
- package/prompts/bsvSdk/index.ts +5 -5
- package/prompts/bsvSdk/transaction.ts +2 -2
- package/prompts/bsvSdk/wallet.ts +1 -1
- package/prompts/index.ts +1 -1
- package/resources/bitcom.ts +132 -0
- package/resources/resources.ts +7 -3
- package/smithery.yaml +3 -0
- package/test-mcp-server.ts +157 -0
- package/tools/bap/friend.ts +267 -0
- package/tools/bap/generate.test.ts +350 -0
- package/tools/bap/generate.ts +433 -0
- package/tools/bap/getCurrentAddress.ts +76 -0
- package/tools/bap/getId.test.ts +121 -0
- package/tools/bap/getId.ts +169 -0
- package/tools/bap/index.ts +111 -0
- package/tools/bap/types.ts +66 -0
- package/tools/bap/utils.ts +33 -0
- package/tools/bigblocks/components.ts +304 -0
- package/tools/bigblocks/docs.ts +488 -0
- package/tools/bigblocks/examples.ts +527 -0
- package/tools/bigblocks/generator.ts +485 -0
- package/tools/bigblocks/index.ts +23 -0
- package/tools/bsocial/bigblocksApiClient.ts +189 -0
- package/tools/bsocial/bmapFollow.ts +125 -0
- package/tools/bsocial/bmapLikes.ts +111 -0
- package/tools/bsocial/bmapReadPosts.ts +148 -0
- package/tools/bsocial/createPost.ts +136 -0
- package/tools/bsocial/index.ts +45 -0
- package/tools/bsocial/readPosts.ts +255 -0
- package/tools/bsv/decodeTransaction.ts +5 -1
- package/tools/constants.ts +21 -0
- package/tools/index.ts +103 -17
- package/tools/mnee/index.ts +8 -0
- package/tools/mnee/parseTx.ts +1 -1
- package/tools/mnee/sendMnee.ts +1 -1
- package/tools/utils/aip.ts +46 -0
- package/tools/utils/conversion.ts +1 -0
- package/tools/utils/errorHandler.ts +76 -0
- package/tools/utils/index.ts +45 -1
- package/tools/utils/installAgentMaster.ts +84 -0
- package/tools/utils/logger.ts +20 -0
- package/tools/utils/toolConfig.ts +80 -0
- package/tools/utils/toolRegistration.ts +66 -0
- package/tools/utils/transactionBuilder.ts +196 -0
- package/tools/wallet/a2bPublishAgent.ts +8 -4
- package/tools/wallet/a2bPublishMcp.ts +28 -24
- package/tools/wallet/createOrdinals.ts +4 -2
- package/tools/wallet/fetchPaymentUtxos.ts +44 -43
- package/tools/wallet/gatherCollectionInfo.ts +374 -0
- package/tools/wallet/getAddress.ts +13 -21
- package/tools/wallet/getBalance.ts +66 -0
- package/tools/wallet/getBalanceDroplet.ts +59 -0
- package/tools/wallet/integratedWallet.ts +120 -0
- package/tools/wallet/mintCollection.ts +378 -0
- package/tools/wallet/purchaseListing.ts +4 -4
- package/tools/wallet/schemas.ts +18 -249
- package/tools/wallet/sendOrdinals.ts +4 -2
- package/tools/wallet/sendToAddress.ts +5 -1
- package/tools/wallet/setupDroplet.ts +172 -0
- package/tools/wallet/tools.ts +71 -156
- package/tools/wallet/transactionHelper.ts +121 -0
- package/tools/wallet/transferOrdToken.ts +7 -4
- package/tools/wallet/utxo.ts +62 -0
- package/tools/wallet/wallet.ts +237 -234
- 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.
|
|
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 ??
|
|
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
|
-
|
|
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,
|
|
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:
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
300
|
-
|
|
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:
|
|
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
|
-
|
|
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 {
|