bsv-mcp 0.2.15 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +83 -10
  2. package/README.md +13 -13
  3. package/dist/app.html +483 -106
  4. package/dist/index.js +227181 -117395
  5. package/index.ts +463 -57
  6. package/package.json +24 -15
  7. package/prompts/bsvSdk/auth.ts +1 -1
  8. package/prompts/bsvSdk/cryptography.ts +1 -1
  9. package/prompts/bsvSdk/overview.ts +1 -1
  10. package/prompts/bsvSdk/primitives.ts +1 -1
  11. package/prompts/bsvSdk/script.ts +1 -1
  12. package/prompts/bsvSdk/transaction.ts +1 -1
  13. package/prompts/bsvSdk/wallet.ts +1 -1
  14. package/prompts/ordinals.ts +1 -1
  15. package/test-mcp-server.ts +26 -4
  16. package/tools/a2b/discover.ts +2 -2
  17. package/tools/bap/friend.ts +17 -24
  18. package/tools/bap/generate.test.ts +34 -32
  19. package/tools/bap/generate.ts +48 -43
  20. package/tools/bap/getCurrentAddress.ts +1 -3
  21. package/tools/bap/getId.test.ts +18 -10
  22. package/tools/bap/getId.ts +8 -6
  23. package/tools/bap/utils.ts +1 -1
  24. package/tools/bsocial/bmapReadPosts.ts +16 -2
  25. package/tools/bsocial/createPost.ts +21 -10
  26. package/tools/bsocial/readPosts.ts +10 -4
  27. package/tools/bsv/decodeTransaction.ts +1 -1
  28. package/tools/bsv/explore.ts +0 -4
  29. package/tools/bsv/getPrice.ts +1 -1
  30. package/tools/bsv/token.ts +14 -6
  31. package/tools/constants.ts +6 -2
  32. package/tools/index.ts +10 -10
  33. package/tools/mnee/getBalance.ts +1 -1
  34. package/tools/mnee/parseTx.ts +1 -1
  35. package/tools/mnee/sendMnee.ts +30 -8
  36. package/tools/ordinals/getInscription.ts +1 -3
  37. package/tools/ordinals/getTokenByIdOrTicker.ts +1 -3
  38. package/tools/ordinals/index.ts +4 -1
  39. package/tools/ordinals/marketListings.ts +1 -1
  40. package/tools/ordinals/marketSales.ts +1 -1
  41. package/tools/ordinals/searchInscriptions.ts +1 -1
  42. package/tools/utils/aip.ts +31 -22
  43. package/tools/utils/installAgentMaster.ts +8 -9
  44. package/tools/utils/toolRegistration.ts +21 -22
  45. package/tools/utils/transactionBuilder.ts +21 -14
  46. package/tools/wallet/a2bPublishMcp.ts +15 -5
  47. package/tools/wallet/brc100.ts +541 -310
  48. package/tools/wallet/cancelListing.ts +29 -37
  49. package/tools/wallet/createOrdinals.ts +43 -27
  50. package/tools/wallet/fetchPaymentUtxos.ts +7 -5
  51. package/tools/wallet/gatherCollectionInfo.ts +3 -5
  52. package/tools/wallet/getAddress.ts +1 -4
  53. package/tools/wallet/getBalance.ts +15 -15
  54. package/tools/wallet/{getBalanceDroplet.ts → getBalanceDroplit.ts} +6 -6
  55. package/tools/wallet/getBsv21Balances.ts +20 -14
  56. package/tools/wallet/getLockData.ts +11 -11
  57. package/tools/wallet/getOrdinals.ts +26 -20
  58. package/tools/wallet/integratedWallet.ts +55 -53
  59. package/tools/wallet/listOrdinal.ts +40 -39
  60. package/tools/wallet/listTokens.ts +18 -17
  61. package/tools/wallet/lockBsv.ts +36 -22
  62. package/tools/wallet/mintCollection.ts +15 -10
  63. package/tools/wallet/opnsDeregister.ts +29 -39
  64. package/tools/wallet/opnsRegister.ts +29 -39
  65. package/tools/wallet/purchaseListing.test.ts +27 -0
  66. package/tools/wallet/purchaseListing.ts +59 -40
  67. package/tools/wallet/refreshUtxos.ts +1 -1
  68. package/tools/wallet/schemas.ts +0 -13
  69. package/tools/wallet/sendAllBsv.ts +26 -20
  70. package/tools/wallet/sendBsv.ts +107 -0
  71. package/tools/wallet/setupDroplit.ts +157 -0
  72. package/tools/wallet/signBsm.ts +18 -18
  73. package/tools/wallet/sweepBsv.ts +48 -27
  74. package/tools/wallet/sweepBsv21.ts +42 -28
  75. package/tools/wallet/sweepOrdinals.ts +38 -26
  76. package/tools/wallet/tools.ts +11 -13
  77. package/tools/wallet/transactionHelper.ts +13 -5
  78. package/tools/wallet/transferOrdToken.ts +72 -84
  79. package/tools/wallet/unlockBsv.ts +23 -17
  80. package/tools/wallet/utxo.ts +1 -0
  81. package/tools/wallet/wallet.ts +1 -13
  82. package/tools/wallet/sendToAddress.ts +0 -74
  83. package/tools/wallet/setupDroplet.ts +0 -161
@@ -1,80 +1,72 @@
1
- import type { OneSatContext } from '@1sat/actions'
2
- import { cancelListing } 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
- })
1
+ import type { OneSatContext } from "@1sat/actions";
2
+ import { cancelOrdinalListing } 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
  const cancelListingArgsSchema = z.object({
15
- listing: walletOutputSchema.describe(
16
- 'WalletOutput of the listing to cancel (must include lockingScript)',
17
- ),
18
- inputBEEF: z
19
- .array(z.number())
8
+ id: z
9
+ .string()
20
10
  .describe(
21
- "BEEF bytes from listOutputs (include: 'entire transactions')",
11
+ "Tracking id of the listing in the ordinals basket (the 'id:' tag from wallet_getOrdinals)",
22
12
  ),
23
- })
13
+ });
24
14
 
25
15
  export function registerCancelListingTool(
26
16
  server: McpServer,
27
17
  ctx: OneSatContext | undefined,
28
18
  ) {
29
19
  server.tool(
30
- 'wallet_cancelListing',
31
- 'Cancel an ordinal marketplace listing',
20
+ "wallet_cancelListing",
21
+ "Cancel an ordinal marketplace listing",
32
22
  { ...cancelListingArgsSchema.shape },
33
- async ({ listing, inputBEEF }) => {
23
+ async ({ id }) => {
34
24
  if (!ctx) {
35
25
  return {
36
26
  content: [
37
27
  {
38
- type: 'text',
39
- text: 'Wallet not initialized. Please configure a wallet before cancelling.',
28
+ type: "text",
29
+ text: "Wallet not initialized. Please configure a wallet before cancelling.",
40
30
  },
41
31
  ],
42
32
  isError: true,
43
- }
33
+ };
44
34
  }
45
35
 
46
36
  try {
47
- const result = await cancelListing.execute(ctx, {
48
- listing: listing as Parameters<typeof cancelListing.execute>[1]['listing'],
49
- inputBEEF,
50
- })
37
+ assertBroadcastAllowed("wallet_cancelListing");
38
+ const result = await cancelOrdinalListing.execute(ctx, { id });
51
39
 
52
40
  if (result.error) {
53
41
  return {
54
- content: [{ type: 'text', text: result.error }],
42
+ content: [{ type: "text", text: result.error }],
55
43
  isError: true,
56
- }
44
+ };
57
45
  }
58
46
 
59
47
  return {
60
48
  content: [
61
49
  {
62
- type: 'text',
63
- text: JSON.stringify(result, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2),
50
+ type: "text",
51
+ text: JSON.stringify(
52
+ result,
53
+ (_, v) => (typeof v === "bigint" ? v.toString() : v),
54
+ 2,
55
+ ),
64
56
  },
65
57
  ],
66
- }
58
+ };
67
59
  } catch (err: unknown) {
68
60
  return {
69
61
  content: [
70
62
  {
71
- type: 'text',
63
+ type: "text",
72
64
  text: err instanceof Error ? err.message : String(err),
73
65
  },
74
66
  ],
75
67
  isError: true,
76
- }
68
+ };
77
69
  }
78
70
  },
79
- )
71
+ );
80
72
  }
@@ -1,87 +1,103 @@
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'
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";
6
+ import { assertBroadcastAllowed } from "../../utils/broadcastGuard";
6
7
 
7
8
  export const createOrdinalsArgsSchema = z.object({
8
- dataB64: z.string().describe('Base64-encoded content to inscribe'),
9
- contentType: z.string().describe('MIME type of the content'),
9
+ dataB64: z.string().describe("Base64-encoded content to inscribe"),
10
+ contentType: z.string().describe("MIME type of the content"),
10
11
  destinationAddress: z
11
12
  .string()
12
13
  .optional()
13
- .describe('Optional destination address for the ordinal'),
14
+ .describe("Optional destination address for the ordinal"),
14
15
  metadata: z
15
16
  .record(z.string(), z.string())
16
17
  .optional()
17
- .describe('Optional MAP metadata for the inscription'),
18
+ .describe("Optional MAP metadata for the inscription"),
18
19
  signWithBAP: z
19
20
  .boolean()
20
21
  .optional()
21
- .describe('Sign with BAP identity (Sigma protocol). Uses anchor+inscription two-step flow.'),
22
- })
22
+ .describe(
23
+ "Sign with BAP identity (Sigma protocol). Uses anchor+inscription two-step flow.",
24
+ ),
25
+ });
23
26
 
24
- export type CreateOrdinalsArgs = z.infer<typeof createOrdinalsArgsSchema>
27
+ export type CreateOrdinalsArgs = z.infer<typeof createOrdinalsArgsSchema>;
25
28
 
26
29
  export function registerCreateOrdinalsTool(
27
30
  server: McpServer,
28
31
  ctx: OneSatContext | undefined,
29
32
  ) {
30
33
  server.tool(
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.',
34
+ "wallet_createOrdinals",
35
+ "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.",
33
36
  { ...createOrdinalsArgsSchema.shape },
34
- async ({ dataB64, contentType, destinationAddress, metadata, signWithBAP }): Promise<CallToolResult> => {
37
+ async ({
38
+ dataB64,
39
+ contentType,
40
+ destinationAddress,
41
+ metadata,
42
+ signWithBAP,
43
+ }): Promise<CallToolResult> => {
35
44
  if (!ctx) {
36
45
  return {
37
46
  content: [
38
47
  {
39
- type: 'text',
40
- text: 'Wallet not initialized. Please configure a wallet before creating ordinals.',
48
+ type: "text",
49
+ text: "Wallet not initialized. Please configure a wallet before creating ordinals.",
41
50
  },
42
51
  ],
43
52
  isError: true,
44
- }
53
+ };
45
54
  }
46
55
 
47
56
  try {
57
+ assertBroadcastAllowed("wallet_createOrdinals");
48
58
  const result = await inscribe.execute(ctx, {
49
59
  base64Content: dataB64,
50
60
  contentType,
51
61
  map: metadata,
52
62
  signWithBAP,
53
- })
63
+ // Without this the inscription locks to a wallet-derived self
64
+ // key, so a caller-supplied address has to be forwarded or the
65
+ // ordinal silently mints to the wrong owner.
66
+ ...(destinationAddress && {
67
+ destination: { address: destinationAddress },
68
+ }),
69
+ });
54
70
 
55
71
  if (result.error) {
56
72
  return {
57
- content: [{ type: 'text', text: result.error }],
73
+ content: [{ type: "text", text: result.error }],
58
74
  isError: true,
59
- }
75
+ };
60
76
  }
61
77
 
62
78
  return {
63
79
  content: [
64
80
  {
65
- type: 'text',
81
+ type: "text",
66
82
  text: JSON.stringify({
67
83
  txid: result.txid,
68
- rawtx: result.rawtx,
84
+ contentHash: result.contentHash,
69
85
  contentType,
70
86
  }),
71
87
  },
72
88
  ],
73
- }
89
+ };
74
90
  } catch (err: unknown) {
75
91
  return {
76
92
  content: [
77
93
  {
78
- type: 'text',
94
+ type: "text",
79
95
  text: err instanceof Error ? err.message : String(err),
80
96
  },
81
97
  ],
82
98
  isError: true,
83
- }
99
+ };
84
100
  }
85
101
  },
86
- )
102
+ );
87
103
  }
@@ -1,9 +1,9 @@
1
- import { P2PKH, Transaction, Utils } from "@bsv/sdk";
1
+ import { Utils } from "@bsv/sdk";
2
2
  import type { Utxo } from "js-1sat-ord";
3
3
  import { V5_API_URL } from "../constants";
4
- import { getBeefTransactionById, getTransactionById } from "./utxo";
4
+ import { getBeefTransactionById } from "./utxo";
5
5
 
6
- const { toBase64, toHex, toArray } = Utils;
6
+ const { toHex, toArray } = Utils;
7
7
 
8
8
  /**
9
9
  * Type definition for WhatsOnChain UTXO response
@@ -105,7 +105,9 @@ export async function fetchPaymentUtxosFromV5(
105
105
  console.error(`Fetching UTXOs from V5: ${url}`);
106
106
  const response = await fetch(url);
107
107
  if (!response.ok) {
108
- console.error(`V5 UTXO fetch failed: ${response.status} ${response.statusText}`);
108
+ console.error(
109
+ `V5 UTXO fetch failed: ${response.status} ${response.statusText}`,
110
+ );
109
111
  return undefined;
110
112
  }
111
113
  const data = (await response.json()) as V5Utxo[] | null;
@@ -126,7 +128,7 @@ export async function fetchPaymentUtxosFromV5(
126
128
  }
127
129
  utxos.push({
128
130
  txid,
129
- vout: Number.parseInt(vout),
131
+ vout: Number.parseInt(vout, 10),
130
132
  satoshis: utxo.satoshis,
131
133
  script: toHex(toArray(utxo.script, "base64")),
132
134
  } as Utxo);
@@ -11,8 +11,6 @@ const gatherCollectionInfoArgsSchema = z.object({
11
11
  .describe("Path to folder containing images to analyze for collection"),
12
12
  });
13
13
 
14
- type GatherCollectionInfoArgs = z.infer<typeof gatherCollectionInfoArgsSchema>;
15
-
16
14
  interface ImageInfo {
17
15
  fileName: string;
18
16
  filePath: string;
@@ -172,7 +170,7 @@ export function registerGatherCollectionInfoTool(
172
170
  if (!folderStat.isDirectory()) {
173
171
  throw new Error(`Path is not a directory: ${folderPath}`);
174
172
  }
175
- } catch (error) {
173
+ } catch (_error) {
176
174
  analysis.errors.push(
177
175
  `Folder not found or inaccessible: ${folderPath}`,
178
176
  );
@@ -188,7 +186,7 @@ export function registerGatherCollectionInfoTool(
188
186
  }
189
187
 
190
188
  // Get wallet info
191
- const paymentPk = wallet.getPrivateKey();
189
+ const paymentPk = wallet.getPaymentKey();
192
190
  if (!paymentPk) {
193
191
  analysis.errors.push("No payment key available in wallet");
194
192
  return {
@@ -213,7 +211,7 @@ export function registerGatherCollectionInfoTool(
213
211
  );
214
212
  analysis.walletInfo.balance = balance;
215
213
  analysis.walletInfo.balanceBSV = balance / 100000000;
216
- } catch (error) {
214
+ } catch (_error) {
217
215
  analysis.warnings.push("Could not fetch wallet balance");
218
216
  }
219
217
 
@@ -1,7 +1,4 @@
1
- import {
2
- deriveDepositAddresses,
3
- type OneSatContext,
4
- } from "@1sat/actions";
1
+ import { deriveDepositAddresses, type OneSatContext } from "@1sat/actions";
5
2
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
3
 
7
4
  const MCP_ADDRESS_PREFIX = "mcp";
@@ -1,39 +1,39 @@
1
- import type { OneSatContext } from '@1sat/actions'
2
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
3
- import { toBitcoin } from 'satoshi-token'
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
5
  export function registerWalletGetBalanceTool(
6
6
  server: McpServer,
7
7
  ctx: OneSatContext | undefined,
8
8
  ) {
9
9
  server.tool(
10
- 'wallet_getBalance',
11
- 'Retrieves the current BSV balance for the wallet.',
10
+ "wallet_getBalance",
11
+ "Retrieves the current BSV balance for the wallet.",
12
12
  {},
13
13
  async () => {
14
14
  if (!ctx) {
15
15
  return {
16
16
  content: [
17
17
  {
18
- type: 'text',
19
- text: 'Wallet not initialized. Please configure a wallet before checking balance.',
18
+ type: "text",
19
+ text: "Wallet not initialized. Please configure a wallet before checking balance.",
20
20
  },
21
21
  ],
22
22
  isError: true,
23
- }
23
+ };
24
24
  }
25
25
 
26
26
  try {
27
- const result = await ctx.wallet.listOutputs({ basket: 'default' })
27
+ const result = await ctx.wallet.listOutputs({ basket: "default" });
28
28
  const totalSatoshis = result.outputs.reduce(
29
29
  (sum, output) => sum + output.satoshis,
30
30
  0,
31
- )
31
+ );
32
32
 
33
33
  return {
34
34
  content: [
35
35
  {
36
- type: 'text',
36
+ type: "text",
37
37
  text: JSON.stringify({
38
38
  satoshis: totalSatoshis,
39
39
  bsv: toBitcoin(totalSatoshis),
@@ -41,18 +41,18 @@ export function registerWalletGetBalanceTool(
41
41
  }),
42
42
  },
43
43
  ],
44
- }
44
+ };
45
45
  } catch (error) {
46
46
  return {
47
47
  content: [
48
48
  {
49
- type: 'text',
49
+ type: "text",
50
50
  text: error instanceof Error ? error.message : String(error),
51
51
  },
52
52
  ],
53
53
  isError: true,
54
- }
54
+ };
55
55
  }
56
56
  },
57
- )
57
+ );
58
58
  }
@@ -1,20 +1,20 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { DropletClient } from "../../utils/droplet";
2
+ import type { DroplitClient } from "../../utils/droplit";
3
3
 
4
4
  /**
5
- * Register the getBalance tool for Droplet API mode
5
+ * Register the getBalance tool for Droplit API mode
6
6
  */
7
- export function registerWalletGetBalanceDropletTool(
7
+ export function registerWalletGetBalanceDroplitTool(
8
8
  server: McpServer,
9
- dropletClient: DropletClient,
9
+ droplitClient: DroplitClient,
10
10
  ) {
11
11
  server.tool(
12
12
  "wallet_getBalance",
13
- "Gets the current balance of the wallet (Droplet mode)",
13
+ "Gets the current balance of the wallet (Droplit mode)",
14
14
  {},
15
15
  async () => {
16
16
  try {
17
- const status = await dropletClient.getFaucetStatus();
17
+ const status = await droplitClient.getFaucetStatus();
18
18
 
19
19
  return {
20
20
  content: [
@@ -1,28 +1,34 @@
1
- import { getBsv21Balances, type OneSatContext } from '@1sat/actions'
2
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
1
+ import { getBsv21Balances, type OneSatContext } from "@1sat/actions";
2
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
 
4
4
  export function registerGetBsv21BalancesTool(
5
5
  server: McpServer,
6
6
  ctx?: OneSatContext,
7
7
  ) {
8
8
  server.tool(
9
- 'wallet_getBsv21Balances',
10
- 'Get aggregated BSV21 token balances grouped by token ID',
9
+ "wallet_getBsv21Balances",
10
+ "Get aggregated BSV21 token balances grouped by token ID",
11
11
  {},
12
12
  async () => {
13
13
  try {
14
- if (!ctx) throw new Error('BRC-100 wallet context not available')
15
- const result = await getBsv21Balances.execute(ctx, {})
14
+ if (!ctx) throw new Error("BRC-100 wallet context not available");
15
+ const result = await getBsv21Balances.execute(ctx, {});
16
16
  return {
17
- content: [{
18
- type: 'text',
19
- text: JSON.stringify(result, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2),
20
- }],
21
- }
17
+ content: [
18
+ {
19
+ type: "text",
20
+ text: JSON.stringify(
21
+ result,
22
+ (_, v) => (typeof v === "bigint" ? v.toString() : v),
23
+ 2,
24
+ ),
25
+ },
26
+ ],
27
+ };
22
28
  } catch (err: unknown) {
23
- const msg = err instanceof Error ? err.message : String(err)
24
- return { content: [{ type: 'text', text: msg }], isError: true }
29
+ const msg = err instanceof Error ? err.message : String(err);
30
+ return { content: [{ type: "text", text: msg }], isError: true };
25
31
  }
26
32
  },
27
- )
33
+ );
28
34
  }
@@ -1,25 +1,25 @@
1
- import { getLockData, type OneSatContext } from '@1sat/actions'
2
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
1
+ import { getLockData, type OneSatContext } from "@1sat/actions";
2
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
 
4
4
  export function registerGetLockDataTool(
5
5
  server: McpServer,
6
6
  ctx?: OneSatContext,
7
7
  ) {
8
8
  server.tool(
9
- 'wallet_getLockData',
10
- 'Get summary of time-locked BSV (total, unlockable, next unlock height)',
9
+ "wallet_getLockData",
10
+ "Get summary of time-locked BSV (total, unlockable, next unlock height)",
11
11
  {},
12
12
  async () => {
13
13
  try {
14
- if (!ctx) throw new Error('BRC-100 wallet context not available')
15
- const result = await getLockData.execute(ctx, {})
14
+ if (!ctx) throw new Error("BRC-100 wallet context not available");
15
+ const result = await getLockData.execute(ctx, {});
16
16
  return {
17
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
18
- }
17
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
18
+ };
19
19
  } catch (err: unknown) {
20
- const msg = err instanceof Error ? err.message : String(err)
21
- return { content: [{ type: 'text', text: msg }], isError: true }
20
+ const msg = err instanceof Error ? err.message : String(err);
21
+ return { content: [{ type: "text", text: msg }], isError: true };
22
22
  }
23
23
  },
24
- )
24
+ );
25
25
  }
@@ -1,35 +1,41 @@
1
- import { getOrdinals, type OneSatContext } from '@1sat/actions'
2
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
3
- import { z } from 'zod'
1
+ import { listOrdinals, type OneSatContext } from "@1sat/actions";
2
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { z } from "zod";
4
4
 
5
5
  export function registerGetOrdinalsTool(
6
6
  server: McpServer,
7
7
  ctx?: OneSatContext,
8
8
  ) {
9
9
  server.tool(
10
- 'wallet_getOrdinals',
11
- 'List ordinals/inscriptions in the wallet with metadata',
10
+ "wallet_getOrdinals",
11
+ "List ordinals/inscriptions in the wallet with metadata. Each result carries an 'id:' tag; that tracking id is the handle the transfer, listing and cancel tools take.",
12
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'),
13
+ limit: z
14
+ .number()
15
+ .int()
16
+ .optional()
17
+ .describe("Max number of results to return"),
18
+ offset: z.number().int().optional().describe("Number of results to skip"),
19
+ tags: z
20
+ .array(z.string())
21
+ .optional()
22
+ .describe("Filter by output tags (e.g. 'type:image/png')"),
23
+ tagQueryMode: z
24
+ .enum(["all", "any"])
25
+ .optional()
26
+ .describe("Whether results must match all tags or any tag"),
15
27
  },
16
28
  async (params) => {
17
29
  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
- }))
30
+ if (!ctx) throw new Error("BRC-100 wallet context not available");
31
+ const result = await listOrdinals.execute(ctx, params);
26
32
  return {
27
- content: [{ type: 'text', text: JSON.stringify(outputs, null, 2) }],
28
- }
33
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
34
+ };
29
35
  } catch (err: unknown) {
30
- const msg = err instanceof Error ? err.message : String(err)
31
- return { content: [{ type: 'text', text: msg }], isError: true }
36
+ const msg = err instanceof Error ? err.message : String(err);
37
+ return { content: [{ type: "text", text: msg }], isError: true };
32
38
  }
33
39
  },
34
- )
40
+ );
35
41
  }