bsv-mcp 0.0.2 → 0.0.4

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/README.md CHANGED
@@ -154,7 +154,8 @@ Wallet tools provide core BSV wallet functionality:
154
154
  | `wallet_decrypt` | Decrypts data using a specified protocol and key |
155
155
  | `wallet_getAddress` | Returns a BSV address for the current wallet or a derived path |
156
156
  | `wallet_sendToAddress` | Sends BSV to a specified address (supports BSV or USD amounts) |
157
- | `wallet_purchaseListing` | Purchases an NFT from a marketplace listing |
157
+ | `wallet_purchaseListing` | Purchases NFTs or BSV-20/BSV-21 tokens from marketplace listings |
158
+ | `wallet_createOrdinals` | Creates and inscribes ordinals on the BSV blockchain |
158
159
 
159
160
  ### BSV Tools
160
161
 
@@ -173,8 +174,8 @@ Tools for working with ordinals (NFTs) on BSV:
173
174
  |-----------|-------------|
174
175
  | `ordinals_getInscription` | Retrieves detailed information about a specific inscription |
175
176
  | `ordinals_searchInscriptions` | Searches for inscriptions based on various criteria |
176
- | `ordinals_marketListings` | Retrieves current marketplace listings for inscriptions |
177
- | `ordinals_bsv20MarketSales` | Gets information about BSV20 token market sales |
177
+ | `ordinals_marketListings` | Retrieves market listings for NFTs, BSV-20, and BSV-21 tokens with unified interface |
178
+ | `ordinals_marketSales` | Gets information about BSV-20 and BSV-21 token market sales |
178
179
  | `ordinals_getBsv20ById` | Retrieves details about a specific BSV20 token by ID |
179
180
 
180
181
  ### Utility Tools
@@ -193,11 +194,15 @@ Once connected, you can use natural language to interact with Bitcoin SV through
193
194
  - "Get my Bitcoin SV address"
194
195
  - "Send 0.01 BSV to 1ExampleBsvAddressXXXXXXXXXXXXXXXXX"
195
196
  - "Send $5 USD worth of BSV to 1ExampleBsvAddressXXXXXXXXXXXXXXXXX"
197
+ - "Purchase this NFT listing: txid_vout"
198
+ - "Purchase this BSV-20 token listing: txid_vout"
196
199
 
197
200
  ### Ordinals (NFTs)
198
201
  - "Show me information about the NFT with outpoint 6a89047af2cfac96da17d51ae8eb62c5f1d982be2bc4ba0d0cd2084b7ffed325_0"
199
202
  - "Search for Pixel Zoide NFTs"
200
203
  - "Show me the current marketplace listings for BSV NFTs"
204
+ - "Show me BSV-20 token listings for ticker PEPE"
205
+ - "Get recent BSV-20 token sales"
201
206
 
202
207
  ### Blockchain Operations
203
208
  - "What is the current BSV price?"
@@ -232,6 +237,17 @@ tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
232
237
 
233
238
  For Cursor, check the Cursor MCP logs in Settings → Extensions → Model Context Protocol.
234
239
 
240
+ ## Recent Updates
241
+
242
+ ### Enhanced Marketplace Tools
243
+ - **Unified Market Listings**: The `ordinals_marketListings` tool now supports NFTs, BSV-20, and BSV-21 tokens through a single interface with appropriate filtering.
244
+ - **Improved Market Sales**: The `ordinals_marketSales` tool (renamed from `ordinals_bsv20MarketSales`) now supports both BSV-20 and BSV-21 token sales.
245
+ - **Token Purchases**: The `wallet_purchaseListing` tool has been enhanced to support purchasing both NFTs and BSV-20/BSV-21 tokens.
246
+
247
+ ### API Refinements
248
+ - Standardized endpoint structure for interactions with the GorillaPool API.
249
+ - Improved parameter handling for different token types and marketplace actions.
250
+
235
251
  ## Development
236
252
 
237
253
  This project was created using `bun init` in bun v1.2.9. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "bsv-mcp",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.0.2",
5
+ "version": "0.0.4",
6
6
  "bin": {
7
7
  "bsv-mcp": "./index.ts"
8
8
  },
@@ -1,8 +1,8 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { registerBsv20MarketSalesTool } from "./bsv20MarketSales";
3
2
  import { registerGetBsv20ByIdTool } from "./getBsv20ById";
4
3
  import { registerGetInscriptionTool } from "./getInscription";
5
4
  import { registerMarketListingsTool } from "./marketListings";
5
+ import { registerMarketSalesTool } from "./marketSales";
6
6
  import { registerSearchInscriptionsTool } from "./searchInscriptions";
7
7
 
8
8
  /**
@@ -14,6 +14,6 @@ export function registerOrdinalsTools(server: McpServer): void {
14
14
  registerGetInscriptionTool(server);
15
15
  registerSearchInscriptionsTool(server);
16
16
  registerMarketListingsTool(server);
17
- registerBsv20MarketSalesTool(server);
17
+ registerMarketSalesTool(server);
18
18
  registerGetBsv20ByIdTool(server);
19
19
  }
@@ -2,8 +2,9 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
3
3
  import { z } from "zod";
4
4
 
5
- // Schema for market listings arguments
5
+ // Enhanced schema for unified market listings arguments
6
6
  export const marketListingsArgsSchema = z.object({
7
+ // Common parameters
7
8
  limit: z
8
9
  .number()
9
10
  .int()
@@ -12,29 +13,42 @@ export const marketListingsArgsSchema = z.object({
12
13
  .default(20)
13
14
  .describe("Number of results (1-100, default 20)"),
14
15
  offset: z.number().int().min(0).default(0).describe("Pagination offset"),
15
- sort: z
16
- .enum(["recent", "price", "num"])
17
- .default("recent")
18
- .describe("Sort method (recent, price, or num)"),
19
16
  dir: z
20
17
  .enum(["asc", "desc"])
21
18
  .default("desc")
22
19
  .describe("Sort direction (asc or desc)"),
23
20
  address: z.string().optional().describe("Bitcoin address"),
21
+
22
+ // NFT-specific parameters
24
23
  origin: z.string().optional().describe("Origin outpoint"),
25
24
  mime: z.string().optional().describe("MIME type filter"),
26
25
  num: z.string().optional().describe("Inscription number"),
26
+
27
+ // General market parameters
27
28
  minPrice: z.number().optional().describe("Minimum price in satoshis"),
28
29
  maxPrice: z.number().optional().describe("Maximum price in satoshis"),
30
+
31
+ // Token-specific parameters
32
+ tokenType: z
33
+ .enum(["nft", "bsv20", "bsv21", "all"])
34
+ .default("all")
35
+ .describe("Type of token to search for (nft, bsv20, bsv21, or all)"),
36
+ sort: z
37
+ .enum(["recent", "price", "num", "height", "price_per_token"])
38
+ .default("recent")
39
+ .describe("Sort method (recent, price, num, height, price_per_token)"),
40
+ id: z.string().optional().describe("Token ID in outpoint format"),
41
+ tick: z.string().optional().describe("Token ticker symbol"),
42
+ pending: z.boolean().default(false).optional().describe("Include pending sales"),
29
43
  });
30
44
 
31
45
  export type MarketListingsArgs = z.infer<typeof marketListingsArgsSchema>;
32
46
 
33
- // Simplified market listing response type
47
+ // Unified response type that covers all token types
34
48
  interface MarketListingResponse {
35
49
  results: Array<{
36
50
  outpoint: string;
37
- origin: {
51
+ origin?: {
38
52
  outpoint: string;
39
53
  data?: {
40
54
  insc?: {
@@ -51,16 +65,26 @@ interface MarketListingResponse {
51
65
  price?: number;
52
66
  payout?: string;
53
67
  sale?: boolean;
68
+ price_per_token?: number;
69
+ };
70
+ bsv20?: {
71
+ id?: string;
72
+ tick?: string;
73
+ sym?: string;
74
+ amt?: string;
75
+ op?: string;
54
76
  };
55
77
  };
56
78
  satoshis?: number;
79
+ height?: number;
57
80
  [key: string]: unknown;
58
81
  }>;
59
82
  total: number;
60
83
  }
61
84
 
62
85
  /**
63
- * Register the Ordinals market listings tool
86
+ * Register the unified Ordinals market listings tool
87
+ * Handles NFTs, BSV20, and BSV21 tokens
64
88
  */
65
89
  export function registerMarketListingsTool(server: McpServer): void {
66
90
  server.tool(
@@ -84,25 +108,65 @@ export function registerMarketListingsTool(server: McpServer): void {
84
108
  num,
85
109
  minPrice,
86
110
  maxPrice,
111
+ tokenType,
112
+ id,
113
+ tick,
114
+ pending,
87
115
  } = args;
88
116
 
117
+ // Determine the API endpoint based on tokenType
118
+ let baseUrl = "https://ordinals.gorillapool.io/api";
119
+ let useTokenParams = false;
120
+
121
+ if (tokenType === "bsv20" || tokenType === "bsv21") {
122
+ baseUrl += "/bsv20/market";
123
+ useTokenParams = true;
124
+ } else if (tokenType === "nft" || tokenType === "all") {
125
+ baseUrl += "/market";
126
+ }
127
+
89
128
  // Build the URL with query parameters
90
- const url = new URL("https://ordinals.gorillapool.io/api/market");
129
+ const url = new URL(baseUrl);
91
130
  url.searchParams.append("limit", limit.toString());
92
131
  url.searchParams.append("offset", offset.toString());
93
- url.searchParams.append("sort", sort);
94
132
  url.searchParams.append("dir", dir);
95
-
133
+ url.searchParams.append("script", "true");
134
+
135
+ // Add sort parameter based on token type
136
+ if (useTokenParams) {
137
+ // BSV20/BSV21 specific sort options
138
+ if (sort === "height" || sort === "price" || sort === "price_per_token") {
139
+ url.searchParams.append("sort", sort);
140
+ }
141
+ // Add token-specific parameters
142
+ if (tokenType === "bsv21") {
143
+ url.searchParams.append("type", "v2");
144
+ }
145
+ if (id) url.searchParams.append("id", id);
146
+ if (tick) url.searchParams.append("tick", tick);
147
+ if (pending !== undefined) url.searchParams.append("pending", pending.toString());
148
+ // For BSV20/21, min/max price parameters have slightly different names
149
+ if (minPrice !== undefined) url.searchParams.append("min_price", minPrice.toString());
150
+ if (maxPrice !== undefined) url.searchParams.append("max_price", maxPrice.toString());
151
+ } else {
152
+ // NFT specific sort options
153
+ if (sort === "recent" || sort === "price" || sort === "num") {
154
+ url.searchParams.append("sort", sort);
155
+ }
156
+ // Add NFT-specific parameters
157
+ if (origin) url.searchParams.append("origin", origin);
158
+ if (mime) url.searchParams.append("mime", mime);
159
+ if (num) url.searchParams.append("num", num);
160
+ // For NFTs, min/max price parameters use short names
161
+ if (minPrice !== undefined) url.searchParams.append("min", minPrice.toString());
162
+ if (maxPrice !== undefined) url.searchParams.append("max", maxPrice.toString());
163
+ }
164
+
165
+ // Add common parameters
96
166
  if (address) url.searchParams.append("address", address);
97
- if (origin) url.searchParams.append("origin", origin);
98
- if (mime) url.searchParams.append("mime", mime);
99
- if (num) url.searchParams.append("num", num);
100
- if (minPrice !== undefined)
101
- url.searchParams.append("min", minPrice.toString());
102
- if (maxPrice !== undefined)
103
- url.searchParams.append("max", maxPrice.toString());
104
167
 
105
- // Fetch market listings from GorillaPool API
168
+ // Make the fetch request
169
+ console.log(`Fetching market listings from: ${url.toString()}`);
106
170
  const response = await fetch(url.toString());
107
171
 
108
172
  if (!response.ok) {
@@ -2,8 +2,9 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
3
3
  import { z } from "zod";
4
4
 
5
- // Schema for BSV20 market sales arguments
6
- export const bsv20MarketSalesArgsSchema = z.object({
5
+ // Schema for unified market sales arguments
6
+ export const marketSalesArgsSchema = z.object({
7
+ // Common parameters
7
8
  limit: z
8
9
  .number()
9
10
  .int()
@@ -16,20 +17,22 @@ export const bsv20MarketSalesArgsSchema = z.object({
16
17
  .enum(["asc", "desc"])
17
18
  .default("desc")
18
19
  .describe("Sort direction (asc or desc)"),
19
- type: z
20
- .enum(["v1", "v2", "all"])
21
- .default("all")
22
- .describe("Token type (v1, v2, or all)"),
20
+ address: z.string().optional().describe("Bitcoin address"),
21
+
22
+ // Token-specific parameters
23
+ tokenType: z
24
+ .enum(["bsv20", "bsv21", "all"])
25
+ .default("bsv20")
26
+ .describe("Type of token to search for (bsv20, bsv21, or all)"),
23
27
  id: z.string().optional().describe("Token ID in outpoint format"),
24
28
  tick: z.string().optional().describe("Token ticker symbol"),
25
- pending: z.boolean().default(false).describe("Include pending sales"),
26
- address: z.string().optional().describe("Bitcoin address"),
29
+ pending: z.boolean().default(false).optional().describe("Include pending sales"),
27
30
  });
28
31
 
29
- export type Bsv20MarketSalesArgs = z.infer<typeof bsv20MarketSalesArgsSchema>;
32
+ export type MarketSalesArgs = z.infer<typeof marketSalesArgsSchema>;
30
33
 
31
- // Simplified BSV20 sale response type
32
- interface Bsv20SaleResponse {
34
+ // Unified response type for token sales
35
+ interface MarketSaleResponse {
33
36
  results: Array<{
34
37
  outpoint: string;
35
38
  data?: {
@@ -48,42 +51,66 @@ interface Bsv20SaleResponse {
48
51
  };
49
52
  satoshis?: number;
50
53
  height?: number;
54
+ owner?: string;
55
+ spend?: string;
56
+ spendHeight?: number;
57
+ spendIdx?: string;
51
58
  [key: string]: unknown;
52
59
  }>;
53
60
  total: number;
54
61
  }
55
62
 
56
63
  /**
57
- * Register the BSV20 market sales tool
64
+ * Register the unified market sales tool
65
+ * Handles BSV20 and BSV21 token sales
58
66
  */
59
- export function registerBsv20MarketSalesTool(server: McpServer): void {
67
+ export function registerMarketSalesTool(server: McpServer): void {
60
68
  server.tool(
61
- "ordinals_bsv20MarketSales",
69
+ "ordinals_marketSales",
62
70
  {
63
- args: bsv20MarketSalesArgsSchema,
71
+ args: marketSalesArgsSchema,
64
72
  },
65
73
  async (
66
- { args }: { args: Bsv20MarketSalesArgs },
74
+ { args }: { args: MarketSalesArgs },
67
75
  extra: RequestHandlerExtra,
68
76
  ) => {
69
77
  try {
70
- const { limit, offset, dir, type, id, tick, pending, address } = args;
78
+ const {
79
+ limit,
80
+ offset,
81
+ dir,
82
+ tokenType,
83
+ id,
84
+ tick,
85
+ pending,
86
+ address
87
+ } = args;
88
+
89
+ // Determine the API endpoint based on tokenType
90
+ let baseUrl = "https://ordinals.gorillapool.io/api";
91
+
92
+ // Default to BSV20 for all token types
93
+ baseUrl += "/bsv20/market/sales";
71
94
 
72
95
  // Build the URL with query parameters
73
- const url = new URL(
74
- "https://ordinals.gorillapool.io/api/bsv20/market/sales",
75
- );
96
+ const url = new URL(baseUrl);
76
97
  url.searchParams.append("limit", limit.toString());
77
98
  url.searchParams.append("offset", offset.toString());
78
99
  url.searchParams.append("dir", dir);
79
- url.searchParams.append("type", type);
80
- url.searchParams.append("pending", pending.toString());
100
+ url.searchParams.append("script", "true");
101
+
102
+ // Add type parameter for bsv21 if needed
103
+ if (tokenType === "bsv21") {
104
+ url.searchParams.append("type", "v2");
105
+ }
81
106
 
82
107
  if (id) url.searchParams.append("id", id);
83
108
  if (tick) url.searchParams.append("tick", tick);
109
+ if (pending !== undefined) url.searchParams.append("pending", pending.toString());
84
110
  if (address) url.searchParams.append("address", address);
85
111
 
86
- // Fetch BSV20 market sales from GorillaPool API
112
+ // Fetch market sales from GorillaPool API
113
+ console.log(`Fetching market sales from: ${url.toString()}`);
87
114
  const response = await fetch(url.toString());
88
115
 
89
116
  if (!response.ok) {
@@ -92,7 +119,7 @@ export function registerBsv20MarketSalesTool(server: McpServer): void {
92
119
  );
93
120
  }
94
121
 
95
- const data = (await response.json()) as Bsv20SaleResponse;
122
+ const data = (await response.json()) as MarketSaleResponse;
96
123
 
97
124
  return {
98
125
  content: [
@@ -3,11 +3,15 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
4
4
  import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
5
5
  import {
6
+ type ChangeResult,
6
7
  type ExistingListing,
7
8
  type Payment,
9
+ type TokenUtxo,
8
10
  type Utxo,
11
+ TokenType,
9
12
  oneSatBroadcaster,
10
13
  purchaseOrdListing,
14
+ purchaseOrdTokenListing,
11
15
  } from "js-1sat-ord";
12
16
  import type { z } from "zod";
13
17
  import {
@@ -29,6 +33,11 @@ interface ListingResponse {
29
33
  price: number;
30
34
  payout: string;
31
35
  };
36
+ bsv20?: {
37
+ amt?: string;
38
+ tick?: string;
39
+ id?: string;
40
+ };
32
41
  };
33
42
  }
34
43
 
@@ -39,7 +48,7 @@ interface ListingResponse {
39
48
  * 1. Parses the listing outpoint to get the txid and vout
40
49
  * 2. Fetches the listing UTXO from the ordinals API
41
50
  * 3. Gets the wallet's payment UTXOs (using the wallet's internal UTXO management)
42
- * 4. Uses purchaseOrdListing to create a purchase transaction with market fee
51
+ * 4. Uses purchaseOrdListing or purchaseOrdTokenListing based on the listing type
43
52
  * 5. Broadcasts the transaction
44
53
  * 6. Returns the transaction details
45
54
  */
@@ -56,6 +65,7 @@ export function registerPurchaseListingTool(server: McpServer, wallet: Wallet) {
56
65
  ): Promise<CallToolResult> => {
57
66
  try {
58
67
  console.log(`Attempting to purchase listing: ${args.listingOutpoint}`);
68
+ console.log(`Listing type: ${args.listingType}`);
59
69
  console.log("Using wallet instance:", wallet);
60
70
  console.log("Wallet has UTXOs:", await wallet.getUtxos());
61
71
 
@@ -102,20 +112,6 @@ export function registerPurchaseListingTool(server: McpServer, wallet: Wallet) {
102
112
  }
103
113
  const vout = Number.parseInt(voutStr || "0", 10);
104
114
 
105
- // Create listing UTXO object in the format required by js-1sat-ord
106
- const listingUtxo: Utxo = {
107
- txid,
108
- vout,
109
- script: listingData.script,
110
- satoshis: listingData.satoshis,
111
- };
112
-
113
- // Create the ExistingListing object
114
- const listing: ExistingListing = {
115
- payout: listingData.data.list.payout,
116
- listingUtxo,
117
- };
118
-
119
115
  // Get private key from the wallet
120
116
  const paymentPk = wallet.getPrivateKey();
121
117
  if (!paymentPk) {
@@ -152,15 +148,78 @@ Please fund this wallet address with enough BSV to cover the purchase price
152
148
  op: "purchase",
153
149
  };
154
150
 
155
- // Create the purchase transaction using the library's config type
156
- const transaction = await purchaseOrdListing({
157
- utxos: paymentUtxos,
158
- paymentPk,
159
- ordAddress: args.ordAddress,
160
- listing,
161
- additionalPayments,
162
- metaData,
163
- });
151
+ // Create the purchase transaction based on listing type
152
+ let transaction: ChangeResult;
153
+
154
+ if (args.listingType === "token") {
155
+ if (!args.tokenProtocol) {
156
+ throw new Error("tokenProtocol is required for token listings");
157
+ }
158
+
159
+ if (!args.tokenID) {
160
+ throw new Error("tokenID is required for token listings");
161
+ }
162
+
163
+ // Validate token data from the listing
164
+ if (!listingData.data.bsv20) {
165
+ throw new Error("This is not a valid BSV-20 token listing");
166
+ }
167
+
168
+ // For BSV-20, the amount should be included in the listing data
169
+ if (!listingData.data.bsv20.amt) {
170
+ throw new Error("Token listing doesn't have an amount specified");
171
+ }
172
+
173
+ // Convert the token protocol to the enum type expected by js-1sat-ord
174
+ const protocol = args.tokenProtocol === "bsv-20"
175
+ ? TokenType.BSV20
176
+ : TokenType.BSV21;
177
+
178
+ // Create a TokenUtxo with the required fields
179
+ const listingUtxo: TokenUtxo = {
180
+ txid,
181
+ vout,
182
+ script: listingData.script,
183
+ satoshis: 1, // TokenUtxo's satoshis must be exactly 1
184
+ amt: listingData.data.bsv20.amt,
185
+ id: args.tokenID,
186
+ payout: listingData.data.list.payout,
187
+ };
188
+
189
+ transaction = await purchaseOrdTokenListing({
190
+ protocol,
191
+ tokenID: args.tokenID,
192
+ utxos: paymentUtxos,
193
+ paymentPk,
194
+ listingUtxo,
195
+ ordAddress: args.ordAddress,
196
+ additionalPayments,
197
+ metaData,
198
+ });
199
+ } else {
200
+ // Create a regular Utxo for NFT listing
201
+ const listingUtxo: Utxo = {
202
+ txid,
203
+ vout,
204
+ script: listingData.script,
205
+ satoshis: listingData.satoshis,
206
+ };
207
+
208
+ // Create the ExistingListing object for NFT listings
209
+ const listing: ExistingListing = {
210
+ payout: listingData.data.list.payout,
211
+ listingUtxo,
212
+ };
213
+
214
+ transaction = await purchaseOrdListing({
215
+ utxos: paymentUtxos,
216
+ paymentPk,
217
+ ordAddress: args.ordAddress,
218
+ listing,
219
+ additionalPayments,
220
+ metaData,
221
+ });
222
+ }
164
223
 
165
224
  // After successful transaction creation, refresh the wallet's UTXOs
166
225
  // This ensures the wallet doesn't try to reuse spent UTXOs
@@ -199,6 +258,9 @@ Please fund this wallet address with enough BSV to cover the purchase price
199
258
  txid: transaction.tx.id("hex"),
200
259
  listingOutpoint: args.listingOutpoint,
201
260
  destinationAddress: args.ordAddress,
261
+ listingType: args.listingType,
262
+ tokenProtocol: args.tokenID ? args.tokenProtocol : undefined,
263
+ tokenID: args.tokenID,
202
264
  price: listingData.data.list.price,
203
265
  marketFee,
204
266
  marketFeeAddress: MARKET_WALLET_ADDRESS,
@@ -261,7 +261,7 @@ export const getAddressArgsSchema = z.object({});
261
261
  export const sendToAddressArgsSchema = z.object({
262
262
  address: z.string(),
263
263
  amount: z.number(),
264
- currency: z.enum(["BSV", "USD"]).optional(),
264
+ currency: z.enum(["BSV", "USD"]).optional().default("BSV"),
265
265
  description: z.string().optional(),
266
266
  });
267
267
 
@@ -275,10 +275,24 @@ export const purchaseListingArgsSchema = z.object({
275
275
  ordAddress: z
276
276
  .string()
277
277
  .describe("The ordinal address to receive the purchased item"),
278
+ listingType: z
279
+ .enum(["nft", "token"])
280
+ .default("nft")
281
+ .describe("Type of listing: 'nft' for ordinal NFTs, 'token' for BSV-20 tokens"),
282
+ tokenProtocol: z
283
+ .enum(["bsv-20", "bsv-21"])
284
+ .optional().default("bsv-21")
285
+ .describe("Token protocol for token listings (required when listingType is 'token')"),
286
+ tokenID: z
287
+ .string()
288
+ .optional()
289
+ .describe("Token ID for BSV-21 tokens or ticker for BSV-20 tokens (required when listingType is 'token')"),
278
290
  description: z
279
291
  .string()
280
292
  .optional()
281
293
  .describe("Optional description for the transaction"),
282
294
  });
283
295
 
296
+ // Export types
297
+ export type SendToAddressArgs = z.infer<typeof sendToAddressArgsSchema>;
284
298
  export type PurchaseListingArgs = z.infer<typeof purchaseListingArgsSchema>;
@@ -40,8 +40,6 @@ import type { createOrdinalsArgsSchema } from "./createOrdinals";
40
40
  import { registerGetAddressTool } from "./getAddress";
41
41
  import { registerPurchaseListingTool } from "./purchaseListing";
42
42
  import { registerSendToAddressTool } from "./sendToAddress";
43
- import { registerSendOrdinalsTool } from "./sendOrdinals";
44
- import type { sendOrdinalsArgsSchema } from "./sendOrdinals";
45
43
 
46
44
  // Define mapping from tool names to argument schemas
47
45
  type ToolArgSchemas = {
@@ -74,7 +72,6 @@ type ToolArgSchemas = {
74
72
  wallet_sendToAddress: typeof sendToAddressArgsSchema;
75
73
  wallet_purchaseListing: typeof purchaseListingArgsSchema;
76
74
  wallet_createOrdinals: typeof createOrdinalsArgsSchema;
77
- wallet_sendOrdinals: typeof sendOrdinalsArgsSchema;
78
75
  };
79
76
 
80
77
  // Define a type for the handler function with proper argument types
@@ -210,8 +207,6 @@ export function registerWalletTools(
210
207
  // Register ordinals extension tools
211
208
  // Register the wallet_createOrdinals tool
212
209
  registerCreateOrdinalsTool(server, wallet);
213
- // Register the wallet_sendOrdinals tool
214
- registerSendOrdinalsTool(server, wallet);
215
210
 
216
211
  return handlers;
217
212
  }