bsv-mcp 0.0.19 → 0.0.21
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 +112 -113
- package/index.ts +28 -20
- package/package.json +2 -1
- package/tools/index.ts +11 -7
- package/tools/mnee/getBalance.ts +56 -0
- package/tools/mnee/index.ts +21 -0
- package/tools/mnee/parseTx.ts +45 -0
- package/tools/mnee/sendMnee.ts +97 -0
- package/tools/wallet/tools.ts +6 -0
- package/tools/wallet/transferOrdToken/index.ts +103 -0
package/README.md
CHANGED
|
@@ -48,22 +48,23 @@ To use the BSV MCP server with [Cursor](https://cursor.sh/):
|
|
|
48
48
|
5. Enter the following configuration in JSON format:
|
|
49
49
|
|
|
50
50
|
```json
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"Bitcoin SV": {
|
|
54
|
+
"command": "bunx",
|
|
55
|
+
"args": [
|
|
56
|
+
"bsv-mcp@latest"
|
|
57
|
+
],
|
|
58
|
+
"env": {
|
|
59
|
+
"PRIVATE_KEY_WIF": "<your_private_key_wif>"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
60
63
|
}
|
|
61
|
-
}
|
|
62
64
|
```
|
|
63
65
|
|
|
64
66
|
6. Replace `<your_private_key_wif>` with your actual private key WIF (keep this secure!)
|
|
65
|
-
7.
|
|
66
|
-
8. Click "Save"
|
|
67
|
+
7. Click "Save"
|
|
67
68
|
|
|
68
69
|
The BSV tools will now be available to Cursor's AI assistant under the "Bitcoin SV" namespace.
|
|
69
70
|
|
|
@@ -74,61 +75,34 @@ To connect this server to Claude for Desktop:
|
|
|
74
75
|
1. Ensure you have [Claude for Desktop](https://claude.ai/desktop) installed and updated to the latest version
|
|
75
76
|
2. Clone this repository and run `bun install` in the project directory
|
|
76
77
|
3. Open your Claude for Desktop configuration file:
|
|
78
|
+
|
|
77
79
|
```bash
|
|
78
80
|
# macOS/Linux
|
|
79
81
|
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
|
|
80
|
-
|
|
82
|
+
|
|
81
83
|
# Windows
|
|
82
84
|
code %APPDATA%\Claude\claude_desktop_config.json
|
|
83
85
|
```
|
|
86
|
+
|
|
84
87
|
4. Add the BSV MCP server to your configuration (create the file if it doesn't exist):
|
|
85
88
|
```json
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
{
|
|
90
|
+
"mcpServers": {
|
|
91
|
+
"Bitcoin SV": {
|
|
92
|
+
"command": "bunx",
|
|
93
|
+
"args": [
|
|
94
|
+
"bsv-mcp@latest"
|
|
95
|
+
],
|
|
96
|
+
"env": {
|
|
97
|
+
"PRIVATE_KEY_WIF": "<your_private_key_wif>"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
99
102
|
```
|
|
100
103
|
5. Replace `<your_private_key_wif>` with your actual private key WIF
|
|
101
|
-
6.
|
|
102
|
-
7.
|
|
103
|
-
8. The BSV tools will appear when you click the tools icon (hammer) in Claude for Desktop
|
|
104
|
-
|
|
105
|
-
### Generic MCP Client Integration
|
|
106
|
-
|
|
107
|
-
For other MCP clients that support JSON configuration:
|
|
108
|
-
|
|
109
|
-
```json
|
|
110
|
-
{
|
|
111
|
-
"Bitcoin SV": {
|
|
112
|
-
"command": "env",
|
|
113
|
-
"args": [
|
|
114
|
-
"PRIVATE_KEY_WIF=<your_private_key_wif>",
|
|
115
|
-
"bun",
|
|
116
|
-
"run",
|
|
117
|
-
"<path_to_project>/index.ts"
|
|
118
|
-
]
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
If running the server directly:
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
# Set environment variable first
|
|
127
|
-
export PRIVATE_KEY_WIF=<your_private_key_wif>
|
|
128
|
-
|
|
129
|
-
# Then run the server
|
|
130
|
-
bun run index.ts
|
|
131
|
-
```
|
|
104
|
+
6. Save the file and restart Claude for Desktop
|
|
105
|
+
7. The BSV tools will appear when you click the tools icon (hammer) in Claude for Desktop
|
|
132
106
|
|
|
133
107
|
## Available Tools
|
|
134
108
|
|
|
@@ -138,61 +112,76 @@ The toolkit is organized into several categories:
|
|
|
138
112
|
|
|
139
113
|
Wallet tools provide core BSV wallet functionality:
|
|
140
114
|
|
|
141
|
-
| Tool Name
|
|
142
|
-
|
|
143
|
-
| `wallet_getPublicKey`
|
|
144
|
-
| `wallet_createSignature` | Creates a cryptographic signature for the provided data
|
|
145
|
-
| `wallet_verifySignature` | Verifies a cryptographic signature against the provided data
|
|
146
|
-
| `wallet_encryption`
|
|
147
|
-
| `wallet_getAddress`
|
|
148
|
-
| `wallet_sendToAddress`
|
|
149
|
-
| `wallet_purchaseListing` | Purchases NFTs or BSV-20/BSV-21 tokens from marketplace listings
|
|
150
|
-
| `wallet_createOrdinals`
|
|
115
|
+
| Tool Name | Description | Example Output |
|
|
116
|
+
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
117
|
+
| `wallet_getPublicKey` | Retrieves a public key for a specified protocol and key ID | `{"publicKey":"032d0c73eb9270e9e009fd1f9dd77e19cf764fbad5f799560c4e8fd414e40d6fc2"}` |
|
|
118
|
+
| `wallet_createSignature` | Creates a cryptographic signature for the provided data | `{"signature":[144,124,85,193,226,45,140,249,9,177,11,167,33,215,209,38,...]}` |
|
|
119
|
+
| `wallet_verifySignature` | Verifies a cryptographic signature against the provided data | `{"isValid":true}` |
|
|
120
|
+
| `wallet_encryption` | Combined tool for encrypting and decrypting data using the wallet's cryptographic keys.<br><br>**Examples:**<br>1. Encrypt text: `"Encrypt this message: Hello World"`<br>2. Decrypt data: `"Decrypt this data that was previously encrypted for me"` | Encrypt: `{"ciphertext":[89,32,155,38,125,22,49,226,26,...]}` <br> Decrypt: `{"plaintext":"hello world"}` |
|
|
121
|
+
| `wallet_getAddress` | Returns a BSV address for the current wallet or a derived path | `{"address":"1ExampleBsvAddressXXXXXXXXXXXXXXXXX","status":"ok"}` |
|
|
122
|
+
| `wallet_sendToAddress` | Sends BSV to a specified address (supports BSV or USD amounts) | `{"status":"success","txid":"a1b2c3d4e5f6...","satoshis":1000000}` |
|
|
123
|
+
| `wallet_purchaseListing` | Purchases NFTs or BSV-20/BSV-21 tokens from marketplace listings | `{"status":"success","txid":"a1b2c3d4e5f6...","type":"nft","origin":"abcdef123456..."}` |
|
|
124
|
+
| `wallet_createOrdinals` | Creates and inscribes ordinals on the BSV blockchain | `{"txid":"a1b2c3d4e5f6...","inscriptionAddress":"1ExampleAddress...","contentType":"image/png"}` |
|
|
151
125
|
|
|
152
126
|
### BSV Tools
|
|
153
127
|
|
|
154
128
|
Tools for interacting with the BSV blockchain and network:
|
|
155
129
|
|
|
156
|
-
| Tool Name
|
|
157
|
-
|
|
158
|
-
| `bsv_getPrice`
|
|
159
|
-
| `bsv_decodeTransaction` | Decodes a BSV transaction and returns detailed information
|
|
160
|
-
| `bsv_explore`
|
|
130
|
+
| Tool Name | Description | Example Output |
|
|
131
|
+
| ----------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
132
|
+
| `bsv_getPrice` | Gets the current BSV price from an exchange API | `Current BSV price: $38.75 USD` |
|
|
133
|
+
| `bsv_decodeTransaction` | Decodes a BSV transaction and returns detailed information | `{"txid":"a1b2c3d4e5f6...","version":1,"locktime":0,"size":225,"inputs":[...],"outputs":[...]}` |
|
|
134
|
+
| `bsv_explore` | Comprehensive blockchain explorer tool accessing WhatsOnChain API endpoints | `{"chain_info":{"chain":"main","blocks":826458,"headers":826458,"bestblockhash":"0000000000..."}}` |
|
|
161
135
|
|
|
162
136
|
### Ordinals Tools
|
|
163
137
|
|
|
164
138
|
Tools for working with ordinals (NFTs) on BSV:
|
|
165
139
|
|
|
166
|
-
| Tool Name
|
|
167
|
-
|
|
168
|
-
| `ordinals_getInscription`
|
|
169
|
-
| `ordinals_searchInscriptions`
|
|
170
|
-
| `ordinals_marketListings`
|
|
171
|
-
| `ordinals_marketSales`
|
|
172
|
-
| `ordinals_getTokenByIdOrTicker` | Retrieves details about a specific BSV20 token by ID
|
|
140
|
+
| Tool Name | Description | Example Output |
|
|
141
|
+
| ------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
|
|
142
|
+
| `ordinals_getInscription` | Retrieves detailed information about a specific inscription | `{"id":"a1b2c3d4e5f6...","origin":"a1b2c3d4e5f6...","contentType":"image/png","content":"iVBORw0KGgoAAA..."}` |
|
|
143
|
+
| `ordinals_searchInscriptions` | Searches for inscriptions based on various criteria | `{"results":[{"id":"a1b2c3...","contentType":"image/png","owner":"1Example..."},...]}` |
|
|
144
|
+
| `ordinals_marketListings` | Retrieves market listings for NFTs, BSV-20, and BSV-21 tokens with unified interface | `{"results":[{"txid":"a1b2c3...","price":9990000,"tick":"PEPE","listing":true},...]}` |
|
|
145
|
+
| `ordinals_marketSales` | Gets information about BSV-20 and BSV-21 token market sales | `{"results":[{"txid":"a1b2c3...","price":34710050,"tick":"$BTC","sale":true},...]}` |
|
|
146
|
+
| `ordinals_getTokenByIdOrTicker` | Retrieves details about a specific BSV20 token by ID | `{"tick":"PEPE","max":"21000000","lim":"1000","dec":"2"}` |
|
|
173
147
|
|
|
174
148
|
### Utility Tools
|
|
175
149
|
|
|
176
150
|
General-purpose utility functions:
|
|
177
151
|
|
|
178
|
-
| Tool Name
|
|
179
|
-
|
|
152
|
+
| Tool Name | Description | Example Output |
|
|
153
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- |
|
|
180
154
|
| `utils_convertData` | Converts data between different encoding formats (utf8, hex, base64, binary).<br><br>**Parameters:**<br>- `data` (required): The string to convert<br>- `from` (required): Source encoding format (utf8, hex, base64, or binary)<br>- `to` (required): Target encoding format (utf8, hex, base64, or binary)<br><br>**Examples:**<br>- UTF-8 to hex: `{"data": "hello world", "from": "utf8", "to": "hex"}` → `68656c6c6f20776f726c64`<br>- UTF-8 to base64: `{"data": "Hello World", "from": "utf8", "to": "base64"}` → `SGVsbG8gV29ybGQ=`<br>- base64 to UTF-8: `{"data": "SGVsbG8gV29ybGQ=", "from": "base64", "to": "utf8"}` → `Hello World`<br>- hex to base64: `{"data": "68656c6c6f20776f726c64", "from": "hex", "to": "base64"}` → `aGVsbG8gd29ybGQ=`<br><br>**Notes:**<br>- All parameters are required<br>- The tool returns the converted data as a string<br>- For binary conversion, data is represented as an array of byte values | `"SGVsbG8gV29ybGQ="` (UTF-8 "Hello World" converted to base64) |
|
|
181
155
|
|
|
156
|
+
### MNEE Tools
|
|
157
|
+
|
|
158
|
+
Tools for working with MNEE tokens:
|
|
159
|
+
|
|
160
|
+
| Tool Name | Description | Example Output |
|
|
161
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
162
|
+
| `mnee_getBalance` | Retrieves the current MNEE token balance for the wallet | `{"balance": {"amount": 2900, "decimalAmount": 0.029}}` |
|
|
163
|
+
| `mnee_sendMnee` | Send MNEE tokens to a specified address. Supports both MNEE and USD amounts | `{"success": true, "txid": "d1ce853934964e6c1fe9f44c918a824f175c6ab466b966f49ebc0682a8318895", "rawtx": "0100000002a0be40d8942015f1...", "mneeAmount": 0.01, "usdAmount": "$0.01", "recipient": "15mNxEkyKJXPD8amic6oLUjS45zBKQQoLu"}` |
|
|
164
|
+
| `mnee_parseTx` | Parse an MNEE transaction to get detailed information about its operations and amounts. All amounts are in atomic units with 5 decimal precision (e.g. 1000 atomic units = 0.01 MNEE) | `{"txid": "d1ce853934964e6c1fe9f44c918a824f175c6ab466b966f49ebc0682a8318895", "environment": "production", "type": "transfer", "inputs": [{"address": "18izL7Wtm2fx3ALoRY3MkY2VFSMjArP62D", "amount": 2900}], "outputs": [{"address": "15mNxEkyKJXPD8amic6oLUjS45zBKQQoLu", "amount": 1000}, {"address": "19Vq2TV8aVhFNLQkhDMdnEQ7zT96x6F3PK", "amount": 100}, {"address": "18izL7Wtm2fx3ALoRY3MkY2VFSMjArP62D", "amount": 1800}]}` |
|
|
165
|
+
|
|
182
166
|
## Using the Tools with MCP
|
|
183
167
|
|
|
184
168
|
Once connected, you can use natural language to interact with Bitcoin SV through your AI assistant. Here are some example prompts:
|
|
185
169
|
|
|
186
170
|
### Wallet Operations
|
|
171
|
+
|
|
187
172
|
- "Get my Bitcoin SV address"
|
|
188
173
|
- "Send 0.01 BSV to 1ExampleBsvAddressXXXXXXXXXXXXXXXXX"
|
|
189
174
|
- "Send $5 USD worth of BSV to 1ExampleBsvAddressXXXXXXXXXXXXXXXXX"
|
|
175
|
+
- "Send 0.01 MNEE to 1ExampleBsvAddressXXXXXXXXXXXXXXXXX"
|
|
176
|
+
- "Check my MNEE balance"
|
|
177
|
+
- "Parse this MNEE transaction: txid"
|
|
190
178
|
- "Encrypt this message using my wallet's keys"
|
|
191
179
|
- "Decrypt this data that was previously encrypted for me"
|
|
192
180
|
- "Purchase this NFT listing: txid_vout"
|
|
193
181
|
- "Purchase this BSV-20 token listing: txid_vout"
|
|
194
182
|
|
|
195
183
|
### Ordinals (NFTs)
|
|
184
|
+
|
|
196
185
|
- "Show me information about the NFT with outpoint 6a89047af2cfac96da17d51ae8eb62c5f1d982be2bc4ba0d0cd2084b7ffed325_0"
|
|
197
186
|
- "Search for Pixel Zoide NFTs"
|
|
198
187
|
- "Show me the current marketplace listings for BSV NFTs"
|
|
@@ -200,6 +189,7 @@ Once connected, you can use natural language to interact with Bitcoin SV through
|
|
|
200
189
|
- "Get recent BSV-20 token sales"
|
|
201
190
|
|
|
202
191
|
### Blockchain Operations
|
|
192
|
+
|
|
203
193
|
- "What is the current BSV price?"
|
|
204
194
|
- "Decode this BSV transaction: (transaction hex or ID)"
|
|
205
195
|
- "Get the latest Bitcoin SV chain information"
|
|
@@ -209,6 +199,7 @@ Once connected, you can use natural language to interact with Bitcoin SV through
|
|
|
209
199
|
- "Get details for transaction with hash a1b2c3d4e5f6..."
|
|
210
200
|
|
|
211
201
|
### Data Conversion
|
|
202
|
+
|
|
212
203
|
- "Convert 'Hello World' from UTF-8 to hex format"
|
|
213
204
|
|
|
214
205
|
## How MCP Works
|
|
@@ -231,6 +222,7 @@ If you're having issues connecting to the server:
|
|
|
231
222
|
4. Look for error messages in the client's console output
|
|
232
223
|
|
|
233
224
|
For Claude for Desktop, check the logs at:
|
|
225
|
+
|
|
234
226
|
```bash
|
|
235
227
|
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
|
|
236
228
|
```
|
|
@@ -254,47 +246,53 @@ The `bsv_explore` tool provides comprehensive access to the Bitcoin SV blockchai
|
|
|
254
246
|
The tool supports the following endpoint categories and specific endpoints:
|
|
255
247
|
|
|
256
248
|
#### Chain Data
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
|
260
|
-
| `
|
|
261
|
-
| `
|
|
262
|
-
| `
|
|
249
|
+
|
|
250
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
251
|
+
| -------------------- | ----------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------- |
|
|
252
|
+
| `chain_info` | Network statistics, difficulty, and chain work | None | `{"chain":"main","blocks":826458,"headers":826458,"bestblockhash":"000000000000..."}` |
|
|
253
|
+
| `chain_tips` | Current chain tips including heights and states | None | `[{"height":826458,"hash":"000000000000...","branchlen":0,"status":"active"}]` |
|
|
254
|
+
| `circulating_supply` | Current BSV circulating supply | None | `{"bsv":21000000}` |
|
|
255
|
+
| `peer_info` | Connected peer statistics | None | `[{"addr":"1.2.3.4:8333","services":"000000000000...","lastsend":1621234567}]` |
|
|
263
256
|
|
|
264
257
|
#### Block Data
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
|
268
|
-
| `
|
|
269
|
-
| `
|
|
270
|
-
| `
|
|
271
|
-
| `
|
|
258
|
+
|
|
259
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
260
|
+
| --------------------- | --------------------------------------------------- | ----------------------------------- | -------------------------------------------------------------------------- |
|
|
261
|
+
| `block_by_hash` | Complete block data via hash | `blockHash` | `{"hash":"000000000000...","confirmations":1000,"size":1000000,...}` |
|
|
262
|
+
| `block_by_height` | Complete block data via height | `blockHeight` | `{"hash":"000000000000...","confirmations":1000,"size":1000000,...}` |
|
|
263
|
+
| `tag_count_by_height` | Stats on tag count for a specific block | `blockHeight` | `{"tags":{"amp":3,"bitkey":5,"metanet":12,"planaria":7,"b":120}}` |
|
|
264
|
+
| `block_headers` | Retrieves the last 10 block headers | None | `[{"hash":"000000000000...","height":826458,"version":536870912,...},...]` |
|
|
265
|
+
| `block_pages` | Retrieves pages of transaction IDs for large blocks | `blockHash`, optional: `pageNumber` | `["tx1hash","tx2hash","tx3hash",...]` |
|
|
272
266
|
|
|
273
267
|
#### Stats Data
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
|
277
|
-
| `
|
|
278
|
-
| `
|
|
268
|
+
|
|
269
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
270
|
+
| ----------------------- | ----------------------------------------- | ---------------------------- | -------------------------------------------------------------------------------------- |
|
|
271
|
+
| `block_stats_by_height` | Block statistics for a specific height | `blockHeight` | `{"size":123456,"txCount":512,"outputTotal":54.12345678,"outputTotalUsd":2345.67,...}` |
|
|
272
|
+
| `block_miner_stats` | Block mining statistics for a time period | optional: `days` (default 7) | `{"blocks":{"miner1":412,"miner2":208,...},"total":1008}` |
|
|
273
|
+
| `miner_summary_stats` | Summary of mining statistics | optional: `days` (default 7) | `{"totalBlocks":1008,"totalFees":1.23456789,"totalFeesUsd":53.67,...}` |
|
|
279
274
|
|
|
280
275
|
#### Transaction Data
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
|
284
|
-
| `
|
|
285
|
-
| `
|
|
286
|
-
| `
|
|
276
|
+
|
|
277
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
278
|
+
| ----------------- | --------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------ |
|
|
279
|
+
| `tx_by_hash` | Detailed transaction data | `txHash` | `{"txid":"a1b2c3d4e5f6...","version":1,"locktime":0,"size":225,...}` |
|
|
280
|
+
| `tx_raw` | Raw transaction hex data | `txHash` | `"01000000012345abcdef..."` |
|
|
281
|
+
| `tx_receipt` | Transaction receipt | `txHash` | `{"blockHash":"000000000000...","blockHeight":800000,"confirmations":26458}` |
|
|
282
|
+
| `bulk_tx_details` | Retrieve multiple transactions in one request | `txids` (array) | `[{"txid":"a1b2c3d4e5f6...","version":1,...}, {"txid":"b2c3d4e5f6a7...","version":1,...}]` |
|
|
287
283
|
|
|
288
284
|
#### Address Data
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
|
292
|
-
| `
|
|
285
|
+
|
|
286
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
287
|
+
| ----------------- | ------------------------------- | ---------------------------- | --------------------------------------------------------------- |
|
|
288
|
+
| `address_history` | Transaction history for address | `address`, optional: `limit` | `[{"tx_hash":"a1b2c3d4e5f6...","height":800000},...]` |
|
|
289
|
+
| `address_utxos` | Unspent outputs for address | `address` | `[{"tx_hash":"a1b2c3d4e5f6...","tx_pos":0,"value":100000},...]` |
|
|
293
290
|
|
|
294
291
|
#### Network
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
|
292
|
+
|
|
293
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
294
|
+
| -------- | ---------------- | ------------------- | --------------------- |
|
|
295
|
+
| `health` | API health check | None | `{"status":"synced"}` |
|
|
298
296
|
|
|
299
297
|
### Usage Examples
|
|
300
298
|
|
|
@@ -333,6 +331,7 @@ Under the hood, the tool accepts parameters to specify which data to retrieve:
|
|
|
333
331
|
### Network Options
|
|
334
332
|
|
|
335
333
|
The tool supports both mainnet and testnet:
|
|
334
|
+
|
|
336
335
|
- `main`: Bitcoin SV mainnet (default)
|
|
337
336
|
- `test`: Bitcoin SV testnet
|
|
338
337
|
|
|
@@ -352,4 +351,4 @@ bun test
|
|
|
352
351
|
|
|
353
352
|
## License
|
|
354
353
|
|
|
355
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
354
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
package/index.ts
CHANGED
|
@@ -11,25 +11,33 @@ import { Wallet } from "./tools/wallet/wallet";
|
|
|
11
11
|
* Exits the process with an error message if validation fails
|
|
12
12
|
*/
|
|
13
13
|
function validatePrivateKey(): PrivateKey {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
14
|
+
const privateKeyWif = process.env.PRIVATE_KEY_WIF;
|
|
15
|
+
|
|
16
|
+
// Check if private key is set
|
|
17
|
+
if (!privateKeyWif) {
|
|
18
|
+
console.error(
|
|
19
|
+
"\x1b[31mError: PRIVATE_KEY_WIF environment variable is not set\x1b[0m"
|
|
20
|
+
);
|
|
21
|
+
console.error(
|
|
22
|
+
"Please set this variable with a valid Bitcoin SV private key in WIF format"
|
|
23
|
+
);
|
|
24
|
+
console.error(
|
|
25
|
+
"Example: PRIVATE_KEY_WIF=your_private_key_wif bun run index.ts"
|
|
26
|
+
);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Validate the private key format
|
|
31
|
+
try {
|
|
32
|
+
return PrivateKey.fromWif(privateKeyWif);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error("\x1b[31mError: Invalid private key format\x1b[0m");
|
|
35
|
+
console.error(
|
|
36
|
+
"The PRIVATE_KEY_WIF provided is not a valid Bitcoin SV private key in WIF format"
|
|
37
|
+
);
|
|
38
|
+
console.error("Please check your key and try again");
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
// Validate private key early before starting the server
|
|
@@ -37,7 +45,7 @@ const privKey = validatePrivateKey();
|
|
|
37
45
|
|
|
38
46
|
const server = new McpServer({
|
|
39
47
|
name: "Bitcoin SV MCP Server",
|
|
40
|
-
version: "0.0.
|
|
48
|
+
version: "0.0.21",
|
|
41
49
|
});
|
|
42
50
|
|
|
43
51
|
// Initialize wallet with the validated private key
|
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.
|
|
5
|
+
"version": "0.0.21",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "satchmo",
|
|
8
8
|
"description": "A collection of Bitcoin SV (BSV) tools for the Model Context Protocol (MCP) framework",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"@modelcontextprotocol/sdk": "^1.9.0",
|
|
46
46
|
"@types/node": "^22.14.1",
|
|
47
47
|
"js-1sat-ord": "^0.1.80",
|
|
48
|
+
"mnee": "^2.0.0",
|
|
48
49
|
"satoshi-token": "^0.0.4",
|
|
49
50
|
"zod": "^3.24.2"
|
|
50
51
|
},
|
package/tools/index.ts
CHANGED
|
@@ -2,20 +2,24 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { registerBsvTools } from "./bsv";
|
|
3
3
|
import { registerOrdinalsTools } from "./ordinals";
|
|
4
4
|
import { registerUtilsTools } from "./utils";
|
|
5
|
+
import { registerMneeTools } from "./mnee";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Register all tools with the MCP server
|
|
8
9
|
* @param server The MCP server instance
|
|
9
10
|
*/
|
|
10
11
|
export function registerAllTools(server: McpServer): void {
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
// Register BSV-related tools
|
|
13
|
+
registerBsvTools(server);
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
// Register Ordinals-related tools
|
|
16
|
+
registerOrdinalsTools(server);
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
// Register utility tools
|
|
19
|
+
registerUtilsTools(server);
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
// Register MNEE tools
|
|
22
|
+
registerMneeTools(server);
|
|
23
|
+
|
|
24
|
+
// Add more tool categories as needed
|
|
21
25
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { PrivateKey } from "@bsv/sdk";
|
|
5
|
+
import type { MneeInterface } from "mnee";
|
|
6
|
+
|
|
7
|
+
export const getBalanceArgsSchema = z.object({});
|
|
8
|
+
|
|
9
|
+
export type GetBalanceArgs = z.infer<typeof getBalanceArgsSchema>;
|
|
10
|
+
|
|
11
|
+
export function registerGetBalanceTool(
|
|
12
|
+
server: McpServer,
|
|
13
|
+
mnee: MneeInterface
|
|
14
|
+
): void {
|
|
15
|
+
server.tool(
|
|
16
|
+
"mnee_getBalance",
|
|
17
|
+
"Retrieves the current MNEE token balance for the wallet. Returns the balance in MNEE tokens.",
|
|
18
|
+
{
|
|
19
|
+
args: getBalanceArgsSchema,
|
|
20
|
+
},
|
|
21
|
+
async (
|
|
22
|
+
{ args }: { args: GetBalanceArgs },
|
|
23
|
+
extra: RequestHandlerExtra<any, any>
|
|
24
|
+
) => {
|
|
25
|
+
try {
|
|
26
|
+
// Get private key from wallet
|
|
27
|
+
const privateKey = PrivateKey.fromWif(process.env.PRIVATE_KEY_WIF!);
|
|
28
|
+
if (!privateKey) {
|
|
29
|
+
throw new Error("No private key available");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const address = privateKey.toAddress().toString();
|
|
33
|
+
const balance = await mnee.balance(address);
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
content: [
|
|
37
|
+
{
|
|
38
|
+
type: "text",
|
|
39
|
+
text: JSON.stringify({ balance }, null, 2),
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
} catch (error) {
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "text",
|
|
48
|
+
text: error instanceof Error ? error.message : String(error),
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
isError: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { registerGetBalanceTool } from "./getBalance";
|
|
3
|
+
import Mnee from "mnee";
|
|
4
|
+
import { registerSendMneeTool } from "./sendMnee";
|
|
5
|
+
import { registerParseTxTool } from "./parseTx";
|
|
6
|
+
|
|
7
|
+
const mnee = new Mnee({
|
|
8
|
+
environment: "production",
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Register all MNEE tools with the MCP server
|
|
12
|
+
* @param server The MCP server instance
|
|
13
|
+
*/
|
|
14
|
+
export function registerMneeTools(server: McpServer): void {
|
|
15
|
+
// Register MNEE-related tools
|
|
16
|
+
registerGetBalanceTool(server, mnee);
|
|
17
|
+
|
|
18
|
+
registerSendMneeTool(server, mnee);
|
|
19
|
+
|
|
20
|
+
registerParseTxTool(server, mnee);
|
|
21
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
3
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import type { MneeInterface, ParseTxResponse } from "mnee";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Schema for the parseTx tool arguments.
|
|
9
|
+
*/
|
|
10
|
+
export const parseTxArgsSchema = z.object({
|
|
11
|
+
txid: z.string().describe("Transaction ID to parse"),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type ParseTxArgs = z.infer<typeof parseTxArgsSchema>;
|
|
15
|
+
|
|
16
|
+
export function registerParseTxTool(
|
|
17
|
+
server: McpServer,
|
|
18
|
+
mnee: MneeInterface
|
|
19
|
+
): void {
|
|
20
|
+
server.tool(
|
|
21
|
+
"mnee_parseTx",
|
|
22
|
+
"Parse an MNEE transaction to get detailed information about its operations and amounts. All amounts are in atomic units with 5 decimal precision (e.g. 1000 atomic units = 0.01 MNEE).",
|
|
23
|
+
{ args: parseTxArgsSchema },
|
|
24
|
+
async (
|
|
25
|
+
{ args }: { args: ParseTxArgs },
|
|
26
|
+
extra: RequestHandlerExtra<any, any>
|
|
27
|
+
): Promise<CallToolResult> => {
|
|
28
|
+
try {
|
|
29
|
+
const result: ParseTxResponse = await mnee.parseTx(args.txid);
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
content: [
|
|
33
|
+
{
|
|
34
|
+
type: "text",
|
|
35
|
+
text: JSON.stringify(result, null, 2),
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
41
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
3
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import type Mnee from "mnee";
|
|
5
|
+
import type { SendMNEE, TransferResponse } from "mnee";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Schema for the sendMnee tool arguments.
|
|
10
|
+
*/
|
|
11
|
+
export const sendMneeArgsSchema = z.object({
|
|
12
|
+
address: z.string().describe("The recipient's address"),
|
|
13
|
+
amount: z.number().describe("Amount to send"),
|
|
14
|
+
currency: z
|
|
15
|
+
.enum(["MNEE", "USD"])
|
|
16
|
+
.default("MNEE")
|
|
17
|
+
.describe("Currency of the amount (MNEE or USD)"),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export type SendMneeArgs = z.infer<typeof sendMneeArgsSchema>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Format a number as USD
|
|
24
|
+
*/
|
|
25
|
+
function formatUSD(amount: number): string {
|
|
26
|
+
return new Intl.NumberFormat("en-US", {
|
|
27
|
+
style: "currency",
|
|
28
|
+
currency: "USD",
|
|
29
|
+
minimumFractionDigits: 2,
|
|
30
|
+
maximumFractionDigits: 2,
|
|
31
|
+
}).format(amount);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Registers the mnee_sendMnee tool for sending MNEE tokens
|
|
36
|
+
*/
|
|
37
|
+
export function registerSendMneeTool(server: McpServer, mnee: Mnee): void {
|
|
38
|
+
server.tool(
|
|
39
|
+
"mnee_sendMnee",
|
|
40
|
+
"Send MNEE tokens to a specified address",
|
|
41
|
+
{ args: sendMneeArgsSchema },
|
|
42
|
+
async (
|
|
43
|
+
{ args }: { args: SendMneeArgs },
|
|
44
|
+
extra: RequestHandlerExtra<any, any>
|
|
45
|
+
): Promise<CallToolResult> => {
|
|
46
|
+
try {
|
|
47
|
+
// Since 1 MNEE = $1, the amount is the same in both currencies
|
|
48
|
+
const mneeAmount = args.amount;
|
|
49
|
+
|
|
50
|
+
const transferRequest: SendMNEE[] = [
|
|
51
|
+
{
|
|
52
|
+
address: args.address,
|
|
53
|
+
amount: mneeAmount,
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
// Get WIF from environment
|
|
58
|
+
const wif = process.env.PRIVATE_KEY_WIF;
|
|
59
|
+
if (!wif) {
|
|
60
|
+
throw new Error("PRIVATE_KEY_WIF environment variable is not set");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const result: TransferResponse = await mnee.transfer(
|
|
64
|
+
transferRequest,
|
|
65
|
+
wif
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
if (result.error) {
|
|
69
|
+
throw new Error(result.error);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: "text",
|
|
76
|
+
text: JSON.stringify(
|
|
77
|
+
{
|
|
78
|
+
success: true,
|
|
79
|
+
txid: result.txid,
|
|
80
|
+
rawtx: result.rawtx,
|
|
81
|
+
mneeAmount: mneeAmount,
|
|
82
|
+
usdAmount: formatUSD(mneeAmount),
|
|
83
|
+
recipient: args.address,
|
|
84
|
+
},
|
|
85
|
+
null,
|
|
86
|
+
2
|
|
87
|
+
),
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
} catch (error) {
|
|
92
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
93
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
}
|
package/tools/wallet/tools.ts
CHANGED
|
@@ -39,6 +39,8 @@ import type { createOrdinalsArgsSchema } from "./createOrdinals";
|
|
|
39
39
|
import { registerGetAddressTool } from "./getAddress";
|
|
40
40
|
import { registerPurchaseListingTool } from "./purchaseListing";
|
|
41
41
|
import { registerSendToAddressTool } from "./sendToAddress";
|
|
42
|
+
import { registerTransferOrdTokenTool } from "./transferOrdToken";
|
|
43
|
+
import type { transferOrdTokenArgsSchema } from "./transferOrdToken";
|
|
42
44
|
import { Utils, type WalletProtocol } from "@bsv/sdk";
|
|
43
45
|
|
|
44
46
|
// Define mapping from tool names to argument schemas
|
|
@@ -70,6 +72,7 @@ type ToolArgSchemas = {
|
|
|
70
72
|
wallet_getAddress: typeof getAddressArgsSchema;
|
|
71
73
|
wallet_sendToAddress: typeof sendToAddressArgsSchema;
|
|
72
74
|
wallet_purchaseListing: typeof purchaseListingArgsSchema;
|
|
75
|
+
wallet_transferOrdToken: typeof transferOrdTokenArgsSchema;
|
|
73
76
|
wallet_createOrdinals: typeof createOrdinalsArgsSchema;
|
|
74
77
|
};
|
|
75
78
|
|
|
@@ -111,6 +114,9 @@ export function registerWalletTools(
|
|
|
111
114
|
// Register the wallet_purchaseListing tool
|
|
112
115
|
registerPurchaseListingTool(server, wallet);
|
|
113
116
|
|
|
117
|
+
// Register the wallet_transferOrdToken tool
|
|
118
|
+
registerTransferOrdTokenTool(server, wallet);
|
|
119
|
+
|
|
114
120
|
// Register only the minimal public-facing tools
|
|
115
121
|
// wallet_createAction, wallet_signAction and wallet_getHeight have been removed
|
|
116
122
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import {
|
|
5
|
+
transferOrdTokens,
|
|
6
|
+
TokenType,
|
|
7
|
+
TokenInputMode,
|
|
8
|
+
TokenSelectionStrategy,
|
|
9
|
+
selectTokenUtxos,
|
|
10
|
+
type TransferOrdTokensConfig,
|
|
11
|
+
type Utxo,
|
|
12
|
+
type TokenUtxo,
|
|
13
|
+
type Payment,
|
|
14
|
+
type Distribution,
|
|
15
|
+
type TokenChangeResult,
|
|
16
|
+
} from "js-1sat-ord";
|
|
17
|
+
import type { Wallet } from "../wallet";
|
|
18
|
+
|
|
19
|
+
// Schema for BSV-20/BSV-21 token transfer arguments
|
|
20
|
+
export const transferOrdTokenArgsSchema = z.object({
|
|
21
|
+
protocol: z.enum(["bsv-20", "bsv-21"]),
|
|
22
|
+
tokenID: z.string(),
|
|
23
|
+
sendAmount: z.number(),
|
|
24
|
+
paymentUtxos: z.array(
|
|
25
|
+
z.object({ txid: z.string(), vout: z.number(), satoshis: z.number(), script: z.string() })
|
|
26
|
+
),
|
|
27
|
+
tokenUtxos: z.array(
|
|
28
|
+
z.object({ txid: z.string(), vout: z.number(), satoshis: z.literal(1), script: z.string(), amt: z.string(), id: z.string() })
|
|
29
|
+
),
|
|
30
|
+
distributions: z.array(z.object({ address: z.string(), tokens: z.number() })),
|
|
31
|
+
decimals: z.number(),
|
|
32
|
+
additionalPayments: z.array(z.object({ to: z.string(), amount: z.number() })).optional(),
|
|
33
|
+
});
|
|
34
|
+
export type TransferOrdTokenArgs = z.infer<typeof transferOrdTokenArgsSchema>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Register the wallet_transferOrdToken tool for transferring BSV tokens.
|
|
38
|
+
*/
|
|
39
|
+
export function registerTransferOrdTokenTool(server: McpServer, wallet: Wallet) {
|
|
40
|
+
server.tool(
|
|
41
|
+
"wallet_transferOrdToken",
|
|
42
|
+
"Transfers BSV-20 or BSV-21 tokens from your wallet via js-1sat-ord transferOrdTokens.",
|
|
43
|
+
{ args: transferOrdTokenArgsSchema },
|
|
44
|
+
async (
|
|
45
|
+
{ args }: { args: TransferOrdTokenArgs },
|
|
46
|
+
extra: RequestHandlerExtra
|
|
47
|
+
) => {
|
|
48
|
+
try {
|
|
49
|
+
// fetch keys
|
|
50
|
+
const paymentPk = wallet.getPrivateKey();
|
|
51
|
+
if (!paymentPk) throw new Error("No private key available");
|
|
52
|
+
const ordPk = paymentPk;
|
|
53
|
+
const changeAddress = paymentPk.toAddress().toString();
|
|
54
|
+
const ordAddress = changeAddress;
|
|
55
|
+
|
|
56
|
+
// select token UTXOs
|
|
57
|
+
const { selectedUtxos: inputTokens } = selectTokenUtxos(
|
|
58
|
+
args.tokenUtxos as TokenUtxo[],
|
|
59
|
+
args.sendAmount,
|
|
60
|
+
args.decimals,
|
|
61
|
+
{ inputStrategy: TokenSelectionStrategy.SmallestFirst, outputStrategy: TokenSelectionStrategy.LargestFirst }
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// build config
|
|
65
|
+
const config: TransferOrdTokensConfig = {
|
|
66
|
+
protocol: args.protocol === "bsv-20" ? TokenType.BSV20 : TokenType.BSV21,
|
|
67
|
+
tokenID: args.tokenID,
|
|
68
|
+
utxos: args.paymentUtxos as Utxo[],
|
|
69
|
+
inputTokens,
|
|
70
|
+
distributions: args.distributions as Distribution[],
|
|
71
|
+
tokenChangeAddress: ordAddress,
|
|
72
|
+
changeAddress,
|
|
73
|
+
paymentPk,
|
|
74
|
+
ordPk,
|
|
75
|
+
additionalPayments: args.additionalPayments as Payment[] || [],
|
|
76
|
+
decimals: args.decimals,
|
|
77
|
+
inputMode: TokenInputMode.Needed,
|
|
78
|
+
splitConfig: { outputs: inputTokens.length === 1 ? 2 : 1, threshold: args.sendAmount },
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// execute transfer
|
|
82
|
+
const result: TokenChangeResult = await transferOrdTokens(config);
|
|
83
|
+
await result.tx.broadcast();
|
|
84
|
+
|
|
85
|
+
// refresh UTXOs
|
|
86
|
+
try { await wallet.refreshUtxos(); } catch {}
|
|
87
|
+
|
|
88
|
+
// respond
|
|
89
|
+
return {
|
|
90
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
91
|
+
txid: result.tx.id("hex"),
|
|
92
|
+
spentOutpoints: result.spentOutpoints,
|
|
93
|
+
payChange: result.payChange,
|
|
94
|
+
tokenChange: result.tokenChange,
|
|
95
|
+
}) }]
|
|
96
|
+
};
|
|
97
|
+
} catch (err: unknown) {
|
|
98
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
99
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
}
|