bsv-mcp 0.2.15 → 0.3.1
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 +94 -10
- package/README.md +95 -13
- package/dist/app.html +483 -106
- package/dist/index.js +227724 -117380
- package/index.ts +523 -63
- package/package.json +24 -15
- package/prompts/bsvSdk/auth.ts +1 -1
- package/prompts/bsvSdk/cryptography.ts +1 -1
- package/prompts/bsvSdk/overview.ts +1 -1
- package/prompts/bsvSdk/primitives.ts +1 -1
- package/prompts/bsvSdk/script.ts +1 -1
- package/prompts/bsvSdk/transaction.ts +1 -1
- package/prompts/bsvSdk/wallet.ts +1 -1
- package/prompts/ordinals.ts +1 -1
- package/tools/a2b/discover.ts +2 -2
- package/tools/bap/friend.ts +17 -24
- package/tools/bap/generate.test.ts +34 -32
- package/tools/bap/generate.ts +48 -43
- package/tools/bap/getCurrentAddress.ts +1 -3
- package/tools/bap/getId.test.ts +18 -10
- package/tools/bap/getId.ts +8 -6
- package/tools/bap/utils.ts +1 -1
- package/tools/bsocial/bmapReadPosts.ts +16 -2
- package/tools/bsocial/createPost.ts +21 -10
- package/tools/bsocial/readPosts.ts +10 -4
- package/tools/bsv/decodeTransaction.ts +1 -1
- package/tools/bsv/explore.ts +0 -4
- package/tools/bsv/getPrice.ts +1 -1
- package/tools/bsv/token.ts +14 -6
- package/tools/constants.ts +6 -2
- package/tools/index.ts +22 -13
- package/tools/mnee/getBalance.ts +1 -1
- package/tools/mnee/parseTx.ts +1 -1
- package/tools/mnee/sendMnee.ts +30 -8
- package/tools/ordinals/getInscription.ts +1 -3
- package/tools/ordinals/getTokenByIdOrTicker.ts +1 -3
- package/tools/ordinals/index.ts +4 -1
- package/tools/ordinals/marketListings.ts +1 -1
- package/tools/ordinals/marketSales.ts +1 -1
- package/tools/ordinals/searchInscriptions.ts +1 -1
- package/tools/utils/aip.ts +31 -22
- package/tools/utils/installAgentMaster.ts +8 -9
- package/tools/utils/toolRegistration.ts +21 -22
- package/tools/utils/transactionBuilder.ts +21 -14
- package/tools/wallet/a2bPublishMcp.ts +15 -5
- package/tools/wallet/brc100.ts +567 -312
- package/tools/wallet/cancelListing.ts +29 -37
- package/tools/wallet/createOrdinals.ts +43 -27
- package/tools/wallet/droplit.ts +124 -0
- package/tools/wallet/fetchPaymentUtxos.ts +7 -5
- package/tools/wallet/gatherCollectionInfo.ts +3 -5
- package/tools/wallet/getAddress.ts +1 -4
- package/tools/wallet/getBalance.ts +15 -15
- package/tools/wallet/{getBalanceDroplet.ts → getBalanceDroplit.ts} +6 -6
- package/tools/wallet/getBsv21Balances.ts +20 -14
- package/tools/wallet/getLockData.ts +11 -11
- package/tools/wallet/getOrdinals.ts +26 -20
- package/tools/wallet/integratedWallet.ts +53 -53
- package/tools/wallet/listOrdinal.ts +40 -39
- package/tools/wallet/listTokens.ts +18 -17
- package/tools/wallet/lockBsv.ts +36 -22
- package/tools/wallet/mintCollection.ts +15 -10
- package/tools/wallet/opnsDeregister.ts +29 -39
- package/tools/wallet/opnsRegister.ts +29 -39
- package/tools/wallet/purchaseListing.test.ts +27 -0
- package/tools/wallet/purchaseListing.ts +59 -40
- package/tools/wallet/refreshUtxos.ts +1 -1
- package/tools/wallet/schemas.ts +0 -13
- package/tools/wallet/sendAllBsv.ts +26 -20
- package/tools/wallet/sendBsv.ts +107 -0
- package/tools/wallet/setupDroplit.ts +151 -0
- package/tools/wallet/signBsm.ts +18 -18
- package/tools/wallet/sweepBsv.ts +48 -27
- package/tools/wallet/sweepBsv21.ts +42 -28
- package/tools/wallet/sweepOrdinals.ts +38 -26
- package/tools/wallet/tools.ts +17 -17
- package/tools/wallet/transactionHelper.ts +13 -5
- package/tools/wallet/transferOrdToken.ts +72 -84
- package/tools/wallet/unlockBsv.ts +23 -17
- package/tools/wallet/utxo.ts +1 -0
- package/tools/wallet/wallet.ts +1 -13
- package/test-mcp-server.ts +0 -157
- package/tools/wallet/sendToAddress.ts +0 -74
- package/tools/wallet/setupDroplet.ts +0 -161
|
@@ -1,31 +1,21 @@
|
|
|
1
|
-
import type { OneSatContext } from
|
|
2
|
-
import { sendBsv21,
|
|
3
|
-
import type { McpServer } from
|
|
4
|
-
import { z } from
|
|
5
|
-
|
|
6
|
-
const walletOutputSchema = z.object({
|
|
7
|
-
outpoint: z.string(),
|
|
8
|
-
satoshis: z.number().optional(),
|
|
9
|
-
tags: z.array(z.string()).optional(),
|
|
10
|
-
customInstructions: z.string().optional(),
|
|
11
|
-
lockingScript: z.string().optional(),
|
|
12
|
-
})
|
|
1
|
+
import type { OneSatContext } from "@1sat/actions";
|
|
2
|
+
import { sendBsv21, sendOrdinals } from "@1sat/actions";
|
|
3
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { assertBroadcastAllowed } from "../../utils/broadcastGuard";
|
|
13
6
|
|
|
14
7
|
export const transferOrdTokenArgsSchema = z.object({
|
|
15
|
-
type: z
|
|
16
|
-
"
|
|
17
|
-
),
|
|
18
|
-
// ordinal fields
|
|
19
|
-
ordinal: walletOutputSchema
|
|
20
|
-
.optional()
|
|
8
|
+
type: z
|
|
9
|
+
.enum(["ordinal", "bsv21"])
|
|
21
10
|
.describe(
|
|
22
|
-
"
|
|
11
|
+
"'ordinal' to transfer an inscription/NFT, 'bsv21' to send fungible BSV21 tokens",
|
|
23
12
|
),
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
// ordinal fields
|
|
14
|
+
id: z
|
|
15
|
+
.string()
|
|
26
16
|
.optional()
|
|
27
17
|
.describe(
|
|
28
|
-
"
|
|
18
|
+
"Tracking id of the ordinal in the ordinals basket (the 'id:' tag from wallet_getOrdinals). Required when type='ordinal'",
|
|
29
19
|
),
|
|
30
20
|
// bsv21 fields
|
|
31
21
|
tokenId: z
|
|
@@ -35,130 +25,128 @@ export const transferOrdTokenArgsSchema = z.object({
|
|
|
35
25
|
amount: z
|
|
36
26
|
.string()
|
|
37
27
|
.optional()
|
|
38
|
-
.describe(
|
|
28
|
+
.describe(
|
|
29
|
+
"Amount of tokens to send as a string integer. Required when type='bsv21'",
|
|
30
|
+
),
|
|
39
31
|
// shared destination fields
|
|
40
|
-
address: z.string().optional().describe(
|
|
32
|
+
address: z.string().optional().describe("Recipient P2PKH address"),
|
|
41
33
|
counterparty: z
|
|
42
34
|
.string()
|
|
43
35
|
.optional()
|
|
44
|
-
.describe(
|
|
45
|
-
})
|
|
36
|
+
.describe("Recipient identity public key (hex)"),
|
|
37
|
+
});
|
|
46
38
|
|
|
47
|
-
export type TransferOrdTokenArgs = z.infer<typeof transferOrdTokenArgsSchema
|
|
39
|
+
export type TransferOrdTokenArgs = z.infer<typeof transferOrdTokenArgsSchema>;
|
|
48
40
|
|
|
49
41
|
export function registerTransferOrdTokenTool(
|
|
50
42
|
server: McpServer,
|
|
51
43
|
ctx: OneSatContext | undefined,
|
|
52
44
|
) {
|
|
53
45
|
server.tool(
|
|
54
|
-
|
|
55
|
-
"Transfer an ordinal inscription or send BSV21 fungible tokens. Use type='ordinal' to transfer an NFT/inscription
|
|
46
|
+
"wallet_transferOrdToken",
|
|
47
|
+
"Transfer an ordinal inscription or send BSV21 fungible tokens. Use type='ordinal' to transfer an NFT/inscription by its ordinals-basket tracking id (from wallet_getOrdinals). Use type='bsv21' to send fungible tokens by token ID and amount.",
|
|
56
48
|
{ ...transferOrdTokenArgsSchema.shape },
|
|
57
|
-
async ({ type,
|
|
49
|
+
async ({ type, id, tokenId, amount, address, counterparty }) => {
|
|
58
50
|
if (!ctx) {
|
|
59
51
|
return {
|
|
60
52
|
content: [
|
|
61
53
|
{
|
|
62
|
-
type:
|
|
63
|
-
text:
|
|
54
|
+
type: "text",
|
|
55
|
+
text: "Wallet not initialized. Please configure a wallet before transferring.",
|
|
64
56
|
},
|
|
65
57
|
],
|
|
66
58
|
isError: true,
|
|
67
|
-
}
|
|
59
|
+
};
|
|
68
60
|
}
|
|
69
61
|
|
|
70
62
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
if (!address && !counterparty) {
|
|
63
|
+
assertBroadcastAllowed("wallet_transferOrdToken");
|
|
64
|
+
if (!address && !counterparty) {
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{ type: "text", text: "address or counterparty is required" },
|
|
68
|
+
],
|
|
69
|
+
isError: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (type === "ordinal") {
|
|
74
|
+
if (!id) {
|
|
85
75
|
return {
|
|
86
|
-
content: [
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: "text",
|
|
79
|
+
text: "id is required when type='ordinal'",
|
|
80
|
+
},
|
|
81
|
+
],
|
|
87
82
|
isError: true,
|
|
88
|
-
}
|
|
83
|
+
};
|
|
89
84
|
}
|
|
90
85
|
|
|
91
|
-
const result = await
|
|
92
|
-
transfers: [
|
|
93
|
-
|
|
94
|
-
ordinal: ordinal as Parameters<typeof transferOrdinals.execute>[1]['transfers'][0]['ordinal'],
|
|
95
|
-
address,
|
|
96
|
-
counterparty,
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
inputBEEF,
|
|
100
|
-
})
|
|
86
|
+
const result = await sendOrdinals.execute(ctx, {
|
|
87
|
+
transfers: [{ id, address, counterparty }],
|
|
88
|
+
});
|
|
101
89
|
|
|
102
90
|
if (result.error) {
|
|
103
91
|
return {
|
|
104
|
-
content: [{ type:
|
|
92
|
+
content: [{ type: "text", text: result.error }],
|
|
105
93
|
isError: true,
|
|
106
|
-
}
|
|
94
|
+
};
|
|
107
95
|
}
|
|
108
96
|
|
|
109
97
|
return {
|
|
110
|
-
content: [
|
|
111
|
-
|
|
98
|
+
content: [
|
|
99
|
+
{ type: "text", text: JSON.stringify({ txid: result.txid }) },
|
|
100
|
+
],
|
|
101
|
+
};
|
|
112
102
|
}
|
|
113
103
|
|
|
114
104
|
// bsv21
|
|
115
105
|
if (!tokenId) {
|
|
116
106
|
return {
|
|
117
|
-
content: [
|
|
107
|
+
content: [
|
|
108
|
+
{ type: "text", text: "tokenId is required when type='bsv21'" },
|
|
109
|
+
],
|
|
118
110
|
isError: true,
|
|
119
|
-
}
|
|
111
|
+
};
|
|
120
112
|
}
|
|
121
113
|
if (!amount) {
|
|
122
114
|
return {
|
|
123
|
-
content: [
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
if (!address && !counterparty) {
|
|
128
|
-
return {
|
|
129
|
-
content: [{ type: 'text', text: 'address or counterparty is required' }],
|
|
115
|
+
content: [
|
|
116
|
+
{ type: "text", text: "amount is required when type='bsv21'" },
|
|
117
|
+
],
|
|
130
118
|
isError: true,
|
|
131
|
-
}
|
|
119
|
+
};
|
|
132
120
|
}
|
|
133
121
|
|
|
134
122
|
const result = await sendBsv21.execute(ctx, {
|
|
135
123
|
tokenId,
|
|
136
|
-
amount,
|
|
137
|
-
|
|
138
|
-
counterparty,
|
|
139
|
-
})
|
|
124
|
+
recipients: [{ amount, destination: { address, counterparty } }],
|
|
125
|
+
});
|
|
140
126
|
|
|
141
127
|
if (result.error) {
|
|
142
128
|
return {
|
|
143
|
-
content: [{ type:
|
|
129
|
+
content: [{ type: "text", text: result.error }],
|
|
144
130
|
isError: true,
|
|
145
|
-
}
|
|
131
|
+
};
|
|
146
132
|
}
|
|
147
133
|
|
|
148
134
|
return {
|
|
149
|
-
content: [
|
|
150
|
-
|
|
135
|
+
content: [
|
|
136
|
+
{ type: "text", text: JSON.stringify({ txid: result.txid }) },
|
|
137
|
+
],
|
|
138
|
+
};
|
|
151
139
|
} catch (err: unknown) {
|
|
152
140
|
return {
|
|
153
141
|
content: [
|
|
154
142
|
{
|
|
155
|
-
type:
|
|
143
|
+
type: "text",
|
|
156
144
|
text: err instanceof Error ? err.message : String(err),
|
|
157
145
|
},
|
|
158
146
|
],
|
|
159
147
|
isError: true,
|
|
160
|
-
}
|
|
148
|
+
};
|
|
161
149
|
}
|
|
162
150
|
},
|
|
163
|
-
)
|
|
151
|
+
);
|
|
164
152
|
}
|
|
@@ -1,57 +1,63 @@
|
|
|
1
|
-
import type { OneSatContext } from
|
|
2
|
-
import { unlockBsv } from
|
|
3
|
-
import type { McpServer } from
|
|
1
|
+
import type { OneSatContext } from "@1sat/actions";
|
|
2
|
+
import { unlockBsv } from "@1sat/actions";
|
|
3
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { assertBroadcastAllowed } from "../../utils/broadcastGuard";
|
|
4
5
|
|
|
5
6
|
export function registerUnlockBsvTool(
|
|
6
7
|
server: McpServer,
|
|
7
8
|
ctx: OneSatContext | undefined,
|
|
8
9
|
) {
|
|
9
10
|
server.tool(
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
"wallet_unlockBsv",
|
|
12
|
+
"Unlock all matured time-locked BSV",
|
|
12
13
|
{},
|
|
13
14
|
async () => {
|
|
14
15
|
if (!ctx) {
|
|
15
16
|
return {
|
|
16
17
|
content: [
|
|
17
18
|
{
|
|
18
|
-
type:
|
|
19
|
-
text:
|
|
19
|
+
type: "text",
|
|
20
|
+
text: "Wallet not initialized. Please configure a wallet before unlocking.",
|
|
20
21
|
},
|
|
21
22
|
],
|
|
22
23
|
isError: true,
|
|
23
|
-
}
|
|
24
|
+
};
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
try {
|
|
27
|
-
|
|
28
|
+
assertBroadcastAllowed("wallet_unlockBsv");
|
|
29
|
+
const result = await unlockBsv.execute(ctx, {});
|
|
28
30
|
|
|
29
31
|
if (result.error) {
|
|
30
32
|
return {
|
|
31
|
-
content: [{ type:
|
|
33
|
+
content: [{ type: "text", text: result.error }],
|
|
32
34
|
isError: true,
|
|
33
|
-
}
|
|
35
|
+
};
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
return {
|
|
37
39
|
content: [
|
|
38
40
|
{
|
|
39
|
-
type:
|
|
40
|
-
text: JSON.stringify(
|
|
41
|
+
type: "text",
|
|
42
|
+
text: JSON.stringify(
|
|
43
|
+
result,
|
|
44
|
+
(_, v) => (typeof v === "bigint" ? v.toString() : v),
|
|
45
|
+
2,
|
|
46
|
+
),
|
|
41
47
|
},
|
|
42
48
|
],
|
|
43
|
-
}
|
|
49
|
+
};
|
|
44
50
|
} catch (err: unknown) {
|
|
45
51
|
return {
|
|
46
52
|
content: [
|
|
47
53
|
{
|
|
48
|
-
type:
|
|
54
|
+
type: "text",
|
|
49
55
|
text: err instanceof Error ? err.message : String(err),
|
|
50
56
|
},
|
|
51
57
|
],
|
|
52
58
|
isError: true,
|
|
53
|
-
}
|
|
59
|
+
};
|
|
54
60
|
}
|
|
55
61
|
},
|
|
56
|
-
)
|
|
62
|
+
);
|
|
57
63
|
}
|
package/tools/wallet/utxo.ts
CHANGED
package/tools/wallet/wallet.ts
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
import type { GetPublicKeyArgs, GetPublicKeyResult, PubKeyHex } from "@bsv/sdk";
|
|
10
10
|
import {
|
|
11
|
-
Beef,
|
|
12
11
|
type BroadcastFailure,
|
|
13
12
|
type BroadcastResponse,
|
|
14
13
|
fromUtxo,
|
|
@@ -16,7 +15,6 @@ import {
|
|
|
16
15
|
isBroadcastResponse,
|
|
17
16
|
P2PKH,
|
|
18
17
|
PrivateKey,
|
|
19
|
-
type PublicKey,
|
|
20
18
|
SatoshisPerKilobyte,
|
|
21
19
|
Script,
|
|
22
20
|
Transaction,
|
|
@@ -26,16 +24,6 @@ import { fetchNftUtxos, type NftUtxo, type Utxo } from "js-1sat-ord";
|
|
|
26
24
|
import { V5Broadcaster } from "../../utils/broadcaster";
|
|
27
25
|
import { fetchPaymentUtxosFromV5 } from "./fetchPaymentUtxos";
|
|
28
26
|
|
|
29
|
-
// Local interface for what encrypt/decrypt expect, will be mapped from Zod schema
|
|
30
|
-
interface InternalEncryptionArgs {
|
|
31
|
-
data: number[];
|
|
32
|
-
recipientPublicKey?: PublicKey; // For encryption
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
interface InternalDecryptionArgs {
|
|
36
|
-
data: number[];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
27
|
export class Wallet {
|
|
40
28
|
private paymentUtxos: Utxo[] = [];
|
|
41
29
|
private nftUtxos: NftUtxo[] = [];
|
|
@@ -146,7 +134,7 @@ export class Wallet {
|
|
|
146
134
|
return this.getPaymentKey()?.toAddress();
|
|
147
135
|
}
|
|
148
136
|
|
|
149
|
-
async getPublicKey(
|
|
137
|
+
async getPublicKey(_args?: GetPublicKeyArgs): Promise<GetPublicKeyResult> {
|
|
150
138
|
const currentPaymentKey = this.getPaymentKey();
|
|
151
139
|
if (!currentPaymentKey) {
|
|
152
140
|
throw new Error("No payment key available to derive public key.");
|
package/test-mcp-server.ts
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3
|
-
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
4
|
-
|
|
5
|
-
async function testMCPServer() {
|
|
6
|
-
console.log("🧪 Testing BSV MCP Server...\n");
|
|
7
|
-
|
|
8
|
-
// Create transport
|
|
9
|
-
const transport = new StdioClientTransport({
|
|
10
|
-
command: "bun",
|
|
11
|
-
args: ["run", "./index.ts"],
|
|
12
|
-
env: {
|
|
13
|
-
...process.env,
|
|
14
|
-
TRANSPORT: "stdio",
|
|
15
|
-
DISABLE_BROADCASTING: "true", // Don't broadcast test transactions
|
|
16
|
-
USE_DROPLET_API: "false", // Use local mode to test BSocial
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
// Create client
|
|
21
|
-
const client = new Client(
|
|
22
|
-
{ name: "test-client", version: "1.0.0" },
|
|
23
|
-
{
|
|
24
|
-
capabilities: {},
|
|
25
|
-
},
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
// Connect
|
|
30
|
-
console.log("📡 Connecting to server...");
|
|
31
|
-
await client.connect(transport);
|
|
32
|
-
console.log("✅ Connected successfully\n");
|
|
33
|
-
|
|
34
|
-
// List available tools
|
|
35
|
-
console.log("🔧 Available tools:");
|
|
36
|
-
const tools = await client.listTools();
|
|
37
|
-
console.log(`Found ${tools.tools.length} tools:`);
|
|
38
|
-
|
|
39
|
-
// Group tools by category
|
|
40
|
-
const categories = new Map<string, string[]>();
|
|
41
|
-
for (const tool of tools.tools) {
|
|
42
|
-
const prefix = tool.name.split("_")[0];
|
|
43
|
-
if (!categories.has(prefix)) {
|
|
44
|
-
categories.set(prefix, []);
|
|
45
|
-
}
|
|
46
|
-
const categoryTools = categories.get(prefix);
|
|
47
|
-
if (categoryTools) {
|
|
48
|
-
categoryTools.push(tool.name);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Display by category
|
|
53
|
-
for (const [category, toolNames] of categories) {
|
|
54
|
-
console.log(`\n${category}:`);
|
|
55
|
-
for (const name of toolNames) {
|
|
56
|
-
console.log(` - ${name}`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Test a few tools
|
|
61
|
-
console.log("\n🧪 Testing tools:\n");
|
|
62
|
-
|
|
63
|
-
// 1. Test BSV price tool
|
|
64
|
-
console.log("1. Testing bsv_getPrice:");
|
|
65
|
-
try {
|
|
66
|
-
const priceResult = await client.callTool({
|
|
67
|
-
name: "bsv_getPrice",
|
|
68
|
-
arguments: {},
|
|
69
|
-
});
|
|
70
|
-
const content = priceResult.content[0] as { text: string };
|
|
71
|
-
console.log("✅", content.text);
|
|
72
|
-
} catch (error) {
|
|
73
|
-
console.log("❌ Error:", error);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// 2. Test utils conversion
|
|
77
|
-
console.log("\n2. Testing utils_convertData:");
|
|
78
|
-
try {
|
|
79
|
-
const convertResult = await client.callTool({
|
|
80
|
-
name: "utils_convertData",
|
|
81
|
-
arguments: {
|
|
82
|
-
args: {
|
|
83
|
-
data: "Hello BSV!",
|
|
84
|
-
from: "utf8",
|
|
85
|
-
to: "hex",
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
const content = convertResult.content[0] as { text: string };
|
|
90
|
-
console.log("✅ Converted:", content.text);
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.log("❌ Error:", error);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// 3. Test bsocial_readPosts
|
|
96
|
-
console.log("\n3. Testing bsocial_readPosts:");
|
|
97
|
-
try {
|
|
98
|
-
const postsResult = await client.callTool({
|
|
99
|
-
name: "bsocial_readPosts",
|
|
100
|
-
arguments: {
|
|
101
|
-
args: {
|
|
102
|
-
limit: 5,
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
const content = postsResult.content[0] as { text: string };
|
|
107
|
-
console.log("✅ Read posts (showing first 200 chars):");
|
|
108
|
-
console.log(`${content.text.substring(0, 200)}...`);
|
|
109
|
-
} catch (error) {
|
|
110
|
-
console.log("❌ Error:", error);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// 4. Test ordinals search
|
|
114
|
-
console.log("\n4. Testing ordinals_searchInscriptions:");
|
|
115
|
-
try {
|
|
116
|
-
const ordinalsResult = await client.callTool({
|
|
117
|
-
name: "ordinals_searchInscriptions",
|
|
118
|
-
arguments: {
|
|
119
|
-
args: {
|
|
120
|
-
query: "test",
|
|
121
|
-
limit: 3,
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
const content = ordinalsResult.content[0] as { text: string };
|
|
126
|
-
const response = JSON.parse(content.text);
|
|
127
|
-
console.log(`✅ Found ${response.total || 0} inscriptions`);
|
|
128
|
-
} catch (error) {
|
|
129
|
-
console.log("❌ Error:", error);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// List resources
|
|
133
|
-
console.log("\n📚 Available resources:");
|
|
134
|
-
const resources = await client.listResources();
|
|
135
|
-
console.log(`Found ${resources.resources.length} resources`);
|
|
136
|
-
for (const resource of resources.resources) {
|
|
137
|
-
console.log(` - ${resource.name}`);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// List prompts
|
|
141
|
-
console.log("\n💭 Available prompts:");
|
|
142
|
-
const prompts = await client.listPrompts();
|
|
143
|
-
console.log(`Found ${prompts.prompts.length} prompts`);
|
|
144
|
-
for (const prompt of prompts.prompts) {
|
|
145
|
-
console.log(` - ${prompt.name}`);
|
|
146
|
-
}
|
|
147
|
-
} catch (error) {
|
|
148
|
-
console.error("❌ Test failed:", error);
|
|
149
|
-
} finally {
|
|
150
|
-
console.log("\n🔌 Disconnecting...");
|
|
151
|
-
await client.close();
|
|
152
|
-
process.exit(0);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Run the test
|
|
157
|
-
testMCPServer().catch(console.error);
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import type { OneSatContext } from '@1sat/actions'
|
|
2
|
-
import { sendBsv } from '@1sat/actions'
|
|
3
|
-
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
4
|
-
import { toSatoshi } from 'satoshi-token'
|
|
5
|
-
import { getBsvPriceWithCache } from '../bsv/getPrice'
|
|
6
|
-
import { sendToAddressArgsSchema } from './schemas'
|
|
7
|
-
|
|
8
|
-
export function registerSendToAddressTool(
|
|
9
|
-
server: McpServer,
|
|
10
|
-
ctx: OneSatContext | undefined,
|
|
11
|
-
) {
|
|
12
|
-
server.tool(
|
|
13
|
-
'wallet_sendToAddress',
|
|
14
|
-
'Sends Bitcoin SV (BSV) to a specified address. This tool supports payments in both BSV and USD amounts (with automatic conversion using current exchange rates). Transaction fees are automatically calculated and a confirmation with transaction ID is returned upon success.',
|
|
15
|
-
{ ...sendToAddressArgsSchema.shape },
|
|
16
|
-
async ({ address, amount, currency = 'BSV', description = 'Send to address' }) => {
|
|
17
|
-
if (!ctx) {
|
|
18
|
-
return {
|
|
19
|
-
content: [
|
|
20
|
-
{
|
|
21
|
-
type: 'text',
|
|
22
|
-
text: 'Wallet not initialized. Please configure a wallet before sending.',
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
isError: true,
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
let satoshis: number
|
|
31
|
-
if (currency === 'USD') {
|
|
32
|
-
const bsvPriceUsd = await getBsvPriceWithCache()
|
|
33
|
-
satoshis = toSatoshi(amount / bsvPriceUsd)
|
|
34
|
-
} else {
|
|
35
|
-
satoshis = toSatoshi(amount)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const result = await sendBsv.execute(ctx, {
|
|
39
|
-
requests: [{ address, satoshis }],
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
if (result.error) {
|
|
43
|
-
return {
|
|
44
|
-
content: [{ type: 'text', text: result.error }],
|
|
45
|
-
isError: true,
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
content: [
|
|
51
|
-
{
|
|
52
|
-
type: 'text',
|
|
53
|
-
text: JSON.stringify({
|
|
54
|
-
status: 'success',
|
|
55
|
-
txid: result.txid,
|
|
56
|
-
satoshis,
|
|
57
|
-
}),
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
}
|
|
61
|
-
} catch (error) {
|
|
62
|
-
return {
|
|
63
|
-
content: [
|
|
64
|
-
{
|
|
65
|
-
type: 'text',
|
|
66
|
-
text: error instanceof Error ? error.message : String(error),
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
isError: true,
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
)
|
|
74
|
-
}
|