bsv-mcp 0.2.9 → 0.2.11
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 +19 -0
- package/README.md +26 -2
- package/dist/index.js +6777 -126216
- package/index.ts +287 -265
- package/package.json +4 -3
- package/tools/bap/generate.test.ts +17 -16
- package/tools/index.ts +8 -3
- package/tools/ordinals/getInscription.ts +15 -65
- package/tools/ordinals/getTokenByIdOrTicker.ts +14 -80
- package/tools/ordinals/index.ts +8 -7
- package/tools/ordinals/marketListings.ts +21 -188
- package/tools/ordinals/marketSales.ts +21 -127
- package/tools/ordinals/searchInscriptions.ts +21 -108
- package/tools/wallet/brc100.ts +572 -0
- package/tools/wallet/cancelListing.ts +80 -0
- package/tools/wallet/createOrdinals.ts +62 -143
- package/tools/wallet/getAddress.ts +19 -13
- package/tools/wallet/getBalance.ts +29 -25
- package/tools/wallet/getBsv21Balances.ts +28 -0
- package/tools/wallet/getLockData.ts +25 -0
- package/tools/wallet/getOrdinals.ts +35 -0
- package/tools/wallet/listOrdinal.ts +86 -0
- package/tools/wallet/listTokens.ts +28 -0
- package/tools/wallet/lockBsv.ts +69 -0
- package/tools/wallet/opnsDeregister.ts +80 -0
- package/tools/wallet/opnsRegister.ts +80 -0
- package/tools/wallet/purchaseListing.ts +89 -290
- package/tools/wallet/refreshUtxos.ts +21 -32
- package/tools/wallet/schemas.ts +7 -11
- package/tools/wallet/sendAllBsv.ts +64 -0
- package/tools/wallet/sendToAddress.ts +46 -47
- package/tools/wallet/signBsm.ts +29 -0
- package/tools/wallet/sweepBsv.ts +70 -0
- package/tools/wallet/sweepBsv21.ts +71 -0
- package/tools/wallet/sweepOrdinals.ts +69 -0
- package/tools/wallet/tools.ts +50 -88
- package/tools/wallet/transferOrdToken.ts +137 -129
- package/tools/wallet/unlockBsv.ts +57 -0
- package/tools/wallet/a2bPublishAgent.ts +0 -307
- package/tools/wallet/sendOrdinals.ts +0 -160
|
@@ -1,168 +1,87 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
CreateOrdinalsCollectionItemMetadata,
|
|
7
|
-
CreateOrdinalsCollectionMetadata,
|
|
8
|
-
CreateOrdinalsConfig,
|
|
9
|
-
Destination,
|
|
10
|
-
Inscription,
|
|
11
|
-
LocalSigner,
|
|
12
|
-
PreMAP,
|
|
13
|
-
} from "js-1sat-ord";
|
|
14
|
-
import { createOrdinals } from "js-1sat-ord";
|
|
15
|
-
import { z } from "zod";
|
|
16
|
-
import { V5Broadcaster } from "../../utils/broadcaster";
|
|
17
|
-
import type { Wallet } from "./wallet";
|
|
1
|
+
import type { OneSatContext } from '@1sat/actions'
|
|
2
|
+
import { inscribe } from '@1sat/actions'
|
|
3
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
4
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'
|
|
5
|
+
import { z } from 'zod'
|
|
18
6
|
|
|
19
|
-
/**
|
|
20
|
-
* Schema for the createOrdinals tool arguments.
|
|
21
|
-
* This is a simplified interface compared to the full CreateOrdinalsConfig
|
|
22
|
-
* in js-1sat-ord. The wallet will provide UTXOs, private key, etc.
|
|
23
|
-
*/
|
|
24
7
|
export const createOrdinalsArgsSchema = z.object({
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// Content type (e.g., "image/jpeg", "text/plain", etc.)
|
|
28
|
-
contentType: z.string().describe("MIME type of the content"),
|
|
29
|
-
// Optional destination address (if not provided, uses the wallet's address)
|
|
8
|
+
dataB64: z.string().describe('Base64-encoded content to inscribe'),
|
|
9
|
+
contentType: z.string().describe('MIME type of the content'),
|
|
30
10
|
destinationAddress: z
|
|
31
11
|
.string()
|
|
32
12
|
.optional()
|
|
33
|
-
.describe(
|
|
34
|
-
// Optional metadata for the inscription
|
|
13
|
+
.describe('Optional destination address for the ordinal'),
|
|
35
14
|
metadata: z
|
|
36
|
-
.
|
|
15
|
+
.record(z.string(), z.string())
|
|
37
16
|
.optional()
|
|
38
|
-
.describe(
|
|
39
|
-
|
|
17
|
+
.describe('Optional MAP metadata for the inscription'),
|
|
18
|
+
signWithBAP: z
|
|
19
|
+
.boolean()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Sign with BAP identity (Sigma protocol). Uses anchor+inscription two-step flow.'),
|
|
22
|
+
})
|
|
40
23
|
|
|
41
|
-
export type CreateOrdinalsArgs = z.infer<typeof createOrdinalsArgsSchema
|
|
24
|
+
export type CreateOrdinalsArgs = z.infer<typeof createOrdinalsArgsSchema>
|
|
42
25
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
26
|
+
export function registerCreateOrdinalsTool(
|
|
27
|
+
server: McpServer,
|
|
28
|
+
ctx: OneSatContext | undefined,
|
|
29
|
+
) {
|
|
47
30
|
server.tool(
|
|
48
|
-
|
|
49
|
-
|
|
31
|
+
'wallet_createOrdinals',
|
|
32
|
+
'Creates and inscribes ordinals (NFTs) on the Bitcoin SV blockchain. This tool lets you mint new digital artifacts by encoding data directly into the blockchain. Supports various content types including images, text, JSON, and HTML. The tool handles transaction creation, fee calculation, and broadcasting.',
|
|
50
33
|
{ ...createOrdinalsArgsSchema.shape },
|
|
51
|
-
async ({ dataB64, contentType, destinationAddress, metadata }): Promise<CallToolResult> => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"Warning: Invalid IDENTITY_KEY_WIF environment variable; sigma signing disabled",
|
|
62
|
-
e,
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// 1. Get private key from wallet
|
|
68
|
-
const paymentPk = wallet.getPrivateKey();
|
|
69
|
-
if (!paymentPk) {
|
|
70
|
-
throw new Error("No private key available in wallet");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// 2. Get payment UTXOs from wallet
|
|
74
|
-
const { paymentUtxos } = await wallet.getUtxos();
|
|
75
|
-
if (!paymentUtxos || paymentUtxos.length === 0) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
"No payment UTXOs available to fund this inscription",
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// 3. Get the wallet address for change/destination if not provided
|
|
82
|
-
const walletAddress = paymentPk.toAddress().toString();
|
|
83
|
-
|
|
84
|
-
// 4. Create the inscription object
|
|
85
|
-
const inscription: Inscription = {
|
|
86
|
-
dataB64: dataB64,
|
|
87
|
-
contentType: contentType,
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
// 5. Create the destination
|
|
91
|
-
const destinations: Destination[] = [
|
|
92
|
-
{
|
|
93
|
-
address: destinationAddress || walletAddress,
|
|
94
|
-
inscription,
|
|
95
|
-
},
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
const createOrdinalsConfig: CreateOrdinalsConfig = {
|
|
99
|
-
utxos: paymentUtxos,
|
|
100
|
-
destinations,
|
|
101
|
-
paymentPk,
|
|
102
|
-
changeAddress: walletAddress,
|
|
103
|
-
metaData: metadata as
|
|
104
|
-
| PreMAP
|
|
105
|
-
| CreateOrdinalsCollectionMetadata
|
|
106
|
-
| CreateOrdinalsCollectionItemMetadata,
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
if (identityPk) {
|
|
110
|
-
createOrdinalsConfig.signer = {
|
|
111
|
-
idKey: identityPk,
|
|
112
|
-
} as LocalSigner;
|
|
34
|
+
async ({ dataB64, contentType, destinationAddress, metadata, signWithBAP }): Promise<CallToolResult> => {
|
|
35
|
+
if (!ctx) {
|
|
36
|
+
return {
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: 'text',
|
|
40
|
+
text: 'Wallet not initialized. Please configure a wallet before creating ordinals.',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
isError: true,
|
|
113
44
|
}
|
|
45
|
+
}
|
|
114
46
|
|
|
115
|
-
|
|
116
|
-
const result = await
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (
|
|
124
|
-
const broadcaster = new V5Broadcaster();
|
|
125
|
-
await changeResult.tx.broadcast(broadcaster);
|
|
126
|
-
|
|
127
|
-
// 8. Refresh the wallet's UTXOs after spending
|
|
128
|
-
try {
|
|
129
|
-
await wallet.refreshUtxos();
|
|
130
|
-
} catch (refreshError) {
|
|
131
|
-
console.warn(
|
|
132
|
-
"Failed to refresh UTXOs after transaction:",
|
|
133
|
-
refreshError,
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// 9. Return transaction details
|
|
47
|
+
try {
|
|
48
|
+
const result = await inscribe.execute(ctx, {
|
|
49
|
+
base64Content: dataB64,
|
|
50
|
+
contentType,
|
|
51
|
+
map: metadata,
|
|
52
|
+
signWithBAP,
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if (result.error) {
|
|
138
56
|
return {
|
|
139
|
-
content: [
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
text: JSON.stringify({
|
|
143
|
-
txid: changeResult.tx.id("hex"),
|
|
144
|
-
spentOutpoints: changeResult.spentOutpoints,
|
|
145
|
-
payChange: changeResult.payChange,
|
|
146
|
-
inscriptionAddress: destinationAddress || walletAddress,
|
|
147
|
-
contentType: contentType,
|
|
148
|
-
}),
|
|
149
|
-
},
|
|
150
|
-
],
|
|
151
|
-
};
|
|
57
|
+
content: [{ type: 'text', text: result.error }],
|
|
58
|
+
isError: true,
|
|
59
|
+
}
|
|
152
60
|
}
|
|
153
61
|
|
|
154
62
|
return {
|
|
155
63
|
content: [
|
|
156
64
|
{
|
|
157
|
-
type:
|
|
158
|
-
text:
|
|
65
|
+
type: 'text',
|
|
66
|
+
text: JSON.stringify({
|
|
67
|
+
txid: result.txid,
|
|
68
|
+
rawtx: result.rawtx,
|
|
69
|
+
contentType,
|
|
70
|
+
}),
|
|
159
71
|
},
|
|
160
72
|
],
|
|
161
|
-
}
|
|
73
|
+
}
|
|
162
74
|
} catch (err: unknown) {
|
|
163
|
-
|
|
164
|
-
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
text: err instanceof Error ? err.message : String(err),
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
isError: true,
|
|
83
|
+
}
|
|
165
84
|
}
|
|
166
85
|
},
|
|
167
|
-
)
|
|
86
|
+
)
|
|
168
87
|
}
|
|
@@ -1,34 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deriveDepositAddresses,
|
|
3
|
+
type OneSatContext,
|
|
4
|
+
} from "@1sat/actions";
|
|
1
5
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
|
|
6
|
+
|
|
7
|
+
const MCP_ADDRESS_PREFIX = "mcp";
|
|
3
8
|
|
|
4
9
|
/**
|
|
5
|
-
* Register the tool to get the wallet address
|
|
6
|
-
* @param server The MCP server instance
|
|
7
|
-
* @param wallet The initialized custom Wallet instance
|
|
10
|
+
* Register the tool to get the wallet's BRC-29 deposit address
|
|
8
11
|
*/
|
|
9
12
|
export function registerGetAddressTool(
|
|
10
13
|
server: McpServer,
|
|
11
|
-
|
|
14
|
+
ctx?: OneSatContext,
|
|
12
15
|
): void {
|
|
13
16
|
server.tool(
|
|
14
17
|
"wallet_getAddress",
|
|
15
|
-
"Retrieves the
|
|
18
|
+
"Retrieves the wallet's BRC-29 deposit address derived for MCP. This address can receive BSV, ordinals, or tokens via external payments.",
|
|
16
19
|
{},
|
|
17
20
|
async () => {
|
|
18
21
|
try {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (!address) {
|
|
22
|
-
throw new Error(
|
|
23
|
-
"Could not retrieve address from wallet instance. Key might be missing or getAddress method failed.",
|
|
24
|
-
);
|
|
22
|
+
if (!ctx) {
|
|
23
|
+
throw new Error("BRC-100 wallet context not available");
|
|
25
24
|
}
|
|
26
25
|
|
|
26
|
+
const { derivations } = await deriveDepositAddresses.execute(ctx, {
|
|
27
|
+
prefix: MCP_ADDRESS_PREFIX,
|
|
28
|
+
});
|
|
29
|
+
|
|
27
30
|
return {
|
|
28
31
|
content: [
|
|
29
32
|
{
|
|
30
33
|
type: "text",
|
|
31
|
-
text: JSON.stringify({
|
|
34
|
+
text: JSON.stringify({
|
|
35
|
+
address: derivations[0].address,
|
|
36
|
+
status: "ok",
|
|
37
|
+
}),
|
|
32
38
|
},
|
|
33
39
|
],
|
|
34
40
|
};
|
|
@@ -1,54 +1,58 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import type { OneSatContext } from '@1sat/actions'
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
3
|
+
import { toBitcoin } from 'satoshi-token'
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Registers the wallet_getBalance tool
|
|
7
|
-
*/
|
|
8
5
|
export function registerWalletGetBalanceTool(
|
|
9
6
|
server: McpServer,
|
|
10
|
-
|
|
7
|
+
ctx: OneSatContext | undefined,
|
|
11
8
|
) {
|
|
12
9
|
server.tool(
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
'wallet_getBalance',
|
|
11
|
+
'Retrieves the current BSV balance for the wallet.',
|
|
15
12
|
{},
|
|
16
13
|
async () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
if (!ctx) {
|
|
15
|
+
return {
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: 'text',
|
|
19
|
+
text: 'Wallet not initialized. Please configure a wallet before checking balance.',
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
isError: true,
|
|
25
23
|
}
|
|
24
|
+
}
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
try {
|
|
27
|
+
const result = await ctx.wallet.listOutputs({ basket: 'default' })
|
|
28
|
+
const totalSatoshis = result.outputs.reduce(
|
|
29
|
+
(sum, output) => sum + output.satoshis,
|
|
30
|
+
0,
|
|
31
|
+
)
|
|
28
32
|
|
|
29
33
|
return {
|
|
30
34
|
content: [
|
|
31
35
|
{
|
|
32
|
-
type:
|
|
36
|
+
type: 'text',
|
|
33
37
|
text: JSON.stringify({
|
|
34
38
|
satoshis: totalSatoshis,
|
|
35
|
-
bsv:
|
|
36
|
-
utxoCount:
|
|
39
|
+
bsv: toBitcoin(totalSatoshis),
|
|
40
|
+
utxoCount: result.totalOutputs,
|
|
37
41
|
}),
|
|
38
42
|
},
|
|
39
43
|
],
|
|
40
|
-
}
|
|
44
|
+
}
|
|
41
45
|
} catch (error) {
|
|
42
46
|
return {
|
|
43
47
|
content: [
|
|
44
48
|
{
|
|
45
|
-
type:
|
|
49
|
+
type: 'text',
|
|
46
50
|
text: error instanceof Error ? error.message : String(error),
|
|
47
51
|
},
|
|
48
52
|
],
|
|
49
53
|
isError: true,
|
|
50
|
-
}
|
|
54
|
+
}
|
|
51
55
|
}
|
|
52
56
|
},
|
|
53
|
-
)
|
|
57
|
+
)
|
|
54
58
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { getBsv21Balances, type OneSatContext } from '@1sat/actions'
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
3
|
+
|
|
4
|
+
export function registerGetBsv21BalancesTool(
|
|
5
|
+
server: McpServer,
|
|
6
|
+
ctx?: OneSatContext,
|
|
7
|
+
) {
|
|
8
|
+
server.tool(
|
|
9
|
+
'wallet_getBsv21Balances',
|
|
10
|
+
'Get aggregated BSV21 token balances grouped by token ID',
|
|
11
|
+
{},
|
|
12
|
+
async () => {
|
|
13
|
+
try {
|
|
14
|
+
if (!ctx) throw new Error('BRC-100 wallet context not available')
|
|
15
|
+
const result = await getBsv21Balances.execute(ctx, {})
|
|
16
|
+
return {
|
|
17
|
+
content: [{
|
|
18
|
+
type: 'text',
|
|
19
|
+
text: JSON.stringify(result, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2),
|
|
20
|
+
}],
|
|
21
|
+
}
|
|
22
|
+
} catch (err: unknown) {
|
|
23
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
24
|
+
return { content: [{ type: 'text', text: msg }], isError: true }
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getLockData, type OneSatContext } from '@1sat/actions'
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
3
|
+
|
|
4
|
+
export function registerGetLockDataTool(
|
|
5
|
+
server: McpServer,
|
|
6
|
+
ctx?: OneSatContext,
|
|
7
|
+
) {
|
|
8
|
+
server.tool(
|
|
9
|
+
'wallet_getLockData',
|
|
10
|
+
'Get summary of time-locked BSV (total, unlockable, next unlock height)',
|
|
11
|
+
{},
|
|
12
|
+
async () => {
|
|
13
|
+
try {
|
|
14
|
+
if (!ctx) throw new Error('BRC-100 wallet context not available')
|
|
15
|
+
const result = await getLockData.execute(ctx, {})
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
18
|
+
}
|
|
19
|
+
} catch (err: unknown) {
|
|
20
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
21
|
+
return { content: [{ type: 'text', text: msg }], isError: true }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { getOrdinals, type OneSatContext } from '@1sat/actions'
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
|
|
5
|
+
export function registerGetOrdinalsTool(
|
|
6
|
+
server: McpServer,
|
|
7
|
+
ctx?: OneSatContext,
|
|
8
|
+
) {
|
|
9
|
+
server.tool(
|
|
10
|
+
'wallet_getOrdinals',
|
|
11
|
+
'List ordinals/inscriptions in the wallet with metadata',
|
|
12
|
+
{
|
|
13
|
+
limit: z.number().int().optional().describe('Max number of results to return'),
|
|
14
|
+
offset: z.number().int().optional().describe('Number of results to skip'),
|
|
15
|
+
},
|
|
16
|
+
async (params) => {
|
|
17
|
+
try {
|
|
18
|
+
if (!ctx) throw new Error('BRC-100 wallet context not available')
|
|
19
|
+
const result = await getOrdinals.execute(ctx, params)
|
|
20
|
+
const outputs = result.outputs.map((o: any) => ({
|
|
21
|
+
outpoint: o.outpoint,
|
|
22
|
+
satoshis: o.satoshis,
|
|
23
|
+
tags: o.tags,
|
|
24
|
+
customInstructions: o.customInstructions,
|
|
25
|
+
}))
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: 'text', text: JSON.stringify(outputs, null, 2) }],
|
|
28
|
+
}
|
|
29
|
+
} catch (err: unknown) {
|
|
30
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
31
|
+
return { content: [{ type: 'text', text: msg }], isError: true }
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { OneSatContext } from '@1sat/actions'
|
|
2
|
+
import { listOrdinal } from '@1sat/actions'
|
|
3
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
4
|
+
import { z } from 'zod'
|
|
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
|
+
})
|
|
13
|
+
|
|
14
|
+
const listOrdinalArgsSchema = z.object({
|
|
15
|
+
ordinal: walletOutputSchema.describe(
|
|
16
|
+
'WalletOutput of the ordinal to list (from wallet_getOrdinals)',
|
|
17
|
+
),
|
|
18
|
+
inputBEEF: z
|
|
19
|
+
.array(z.number())
|
|
20
|
+
.describe(
|
|
21
|
+
"BEEF bytes from listOutputs (include: 'entire transactions')",
|
|
22
|
+
),
|
|
23
|
+
price: z.number().describe('Price in satoshis'),
|
|
24
|
+
payAddress: z
|
|
25
|
+
.string()
|
|
26
|
+
.describe('Address to receive payment on purchase'),
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
export function registerListOrdinalTool(
|
|
30
|
+
server: McpServer,
|
|
31
|
+
ctx: OneSatContext | undefined,
|
|
32
|
+
) {
|
|
33
|
+
server.tool(
|
|
34
|
+
'wallet_listOrdinal',
|
|
35
|
+
'List an ordinal for sale on the marketplace',
|
|
36
|
+
{ ...listOrdinalArgsSchema.shape },
|
|
37
|
+
async ({ ordinal, inputBEEF, price, payAddress }) => {
|
|
38
|
+
if (!ctx) {
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: 'text',
|
|
43
|
+
text: 'Wallet not initialized. Please configure a wallet before listing.',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
isError: true,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const result = await listOrdinal.execute(ctx, {
|
|
52
|
+
ordinal: ordinal as Parameters<typeof listOrdinal.execute>[1]['ordinal'],
|
|
53
|
+
inputBEEF,
|
|
54
|
+
price,
|
|
55
|
+
payAddress,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
if (result.error) {
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: 'text', text: result.error }],
|
|
61
|
+
isError: true,
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: 'text',
|
|
69
|
+
text: JSON.stringify(result, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2),
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
}
|
|
73
|
+
} catch (err: unknown) {
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: 'text',
|
|
78
|
+
text: err instanceof Error ? err.message : String(err),
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
isError: true,
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
)
|
|
86
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { listTokens, type OneSatContext } from '@1sat/actions'
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
|
|
5
|
+
export function registerListTokensTool(
|
|
6
|
+
server: McpServer,
|
|
7
|
+
ctx?: OneSatContext,
|
|
8
|
+
) {
|
|
9
|
+
server.tool(
|
|
10
|
+
'wallet_listTokens',
|
|
11
|
+
'List BSV21 token outputs in the wallet',
|
|
12
|
+
{
|
|
13
|
+
limit: z.number().int().optional().describe('Max number of results to return'),
|
|
14
|
+
},
|
|
15
|
+
async (params) => {
|
|
16
|
+
try {
|
|
17
|
+
if (!ctx) throw new Error('BRC-100 wallet context not available')
|
|
18
|
+
const result = await listTokens.execute(ctx, params)
|
|
19
|
+
return {
|
|
20
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
21
|
+
}
|
|
22
|
+
} catch (err: unknown) {
|
|
23
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
24
|
+
return { content: [{ type: 'text', text: msg }], isError: true }
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { OneSatContext } from '@1sat/actions'
|
|
2
|
+
import { lockBsv } from '@1sat/actions'
|
|
3
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
4
|
+
import { z } from 'zod'
|
|
5
|
+
|
|
6
|
+
const lockBsvArgsSchema = z.object({
|
|
7
|
+
requests: z
|
|
8
|
+
.array(
|
|
9
|
+
z.object({
|
|
10
|
+
satoshis: z.number().describe('Amount in satoshis to lock'),
|
|
11
|
+
until: z.number().describe('Block height until which to lock'),
|
|
12
|
+
}),
|
|
13
|
+
)
|
|
14
|
+
.describe('Array of lock requests'),
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export function registerLockBsvTool(
|
|
18
|
+
server: McpServer,
|
|
19
|
+
ctx: OneSatContext | undefined,
|
|
20
|
+
) {
|
|
21
|
+
server.tool(
|
|
22
|
+
'wallet_lockBsv',
|
|
23
|
+
'Lock BSV until a specific block height',
|
|
24
|
+
{ ...lockBsvArgsSchema.shape },
|
|
25
|
+
async ({ requests }) => {
|
|
26
|
+
if (!ctx) {
|
|
27
|
+
return {
|
|
28
|
+
content: [
|
|
29
|
+
{
|
|
30
|
+
type: 'text',
|
|
31
|
+
text: 'Wallet not initialized. Please configure a wallet before locking.',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
isError: true,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const result = await lockBsv.execute(ctx, { requests })
|
|
40
|
+
|
|
41
|
+
if (result.error) {
|
|
42
|
+
return {
|
|
43
|
+
content: [{ type: 'text', text: result.error }],
|
|
44
|
+
isError: true,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: 'text',
|
|
52
|
+
text: JSON.stringify(result, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2),
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
}
|
|
56
|
+
} catch (err: unknown) {
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: 'text',
|
|
61
|
+
text: err instanceof Error ? err.message : String(err),
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
isError: true,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
)
|
|
69
|
+
}
|