bsv-mcp 0.0.7 → 0.0.9
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/Dockerfile +20 -0
- package/README.md +109 -33
- package/index.ts +33 -6
- package/package.json +1 -1
- package/smithery.yaml +10 -10
- package/tools/bsv/explore.ts +177 -0
- package/tools/bsv/getPrice.ts +47 -13
- package/tools/bsv/index.ts +2 -0
- package/tools/wallet/schemas.ts +14 -0
- package/tools/wallet/sendToAddress.ts +2 -28
- package/tools/wallet/tools.test.ts +8 -8
- package/tools/wallet/tools.ts +36 -31
- package/tools/wallet/wallet.ts +10 -1
package/Dockerfile
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Use the official Bun image
|
|
2
|
+
FROM oven/bun:1
|
|
3
|
+
|
|
4
|
+
# Set working directory
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
|
|
7
|
+
# Copy all application code first
|
|
8
|
+
COPY . .
|
|
9
|
+
|
|
10
|
+
# Install dependencies
|
|
11
|
+
RUN bun install --frozen-lockfile
|
|
12
|
+
|
|
13
|
+
# Set user for security
|
|
14
|
+
USER bun
|
|
15
|
+
|
|
16
|
+
# Expose port (if needed)
|
|
17
|
+
EXPOSE 3000
|
|
18
|
+
|
|
19
|
+
# Run the application
|
|
20
|
+
CMD ["bun", "run", "index.ts"]
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Bitcoin SV MCP Server
|
|
2
2
|
|
|
3
|
+
[](https://smithery.ai/server/@b-open-io/bsv-mcp)
|
|
4
|
+
|
|
3
5
|
> **⚠️ NOTICE: Experimental Work in Progress**
|
|
4
6
|
> This project is in an early experimental stage. Features may change, and the API is not yet stable.
|
|
5
7
|
> Contributions, feedback, and bug reports are welcome! Feel free to open issues or submit pull requests.
|
|
@@ -136,46 +138,46 @@ The toolkit is organized into several categories:
|
|
|
136
138
|
|
|
137
139
|
Wallet tools provide core BSV wallet functionality:
|
|
138
140
|
|
|
139
|
-
| Tool Name | Description |
|
|
140
|
-
|
|
141
|
-
| `wallet_getPublicKey` | Retrieves a public key for a specified protocol and key ID |
|
|
142
|
-
| `wallet_createSignature` | Creates a cryptographic signature for the provided data |
|
|
143
|
-
| `wallet_verifySignature` | Verifies a cryptographic signature against the provided data |
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
149
|
-
| `wallet_createOrdinals` | Creates and inscribes ordinals on the BSV blockchain |
|
|
141
|
+
| Tool Name | Description | Example Output |
|
|
142
|
+
|-----------|-------------|----------------|
|
|
143
|
+
| `wallet_getPublicKey` | Retrieves a public key for a specified protocol and key ID | `{"publicKey":"032d0c73eb9270e9e009fd1f9dd77e19cf764fbad5f799560c4e8fd414e40d6fc2"}` |
|
|
144
|
+
| `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,...]}` |
|
|
145
|
+
| `wallet_verifySignature` | Verifies a cryptographic signature against the provided data | `{"isValid":true}` |
|
|
146
|
+
| `wallet_encryption` | Combined tool for encrypting and decrypting data using the wallet's cryptographic keys (replaces separate encrypt/decrypt tools) | Encrypt: `{"ciphertext":[89,32,155,38,125,22,49,226,26,...]}` <br> Decrypt: `{"plaintext":[104,101,108,108,111,32,119,111,114,108,100]}` |
|
|
147
|
+
| `wallet_getAddress` | Returns a BSV address for the current wallet or a derived path | `{"address":"1ExampleBsvAddressXXXXXXXXXXXXXXXXX","status":"ok"}` |
|
|
148
|
+
| `wallet_sendToAddress` | Sends BSV to a specified address (supports BSV or USD amounts) | `{"status":"success","txid":"a1b2c3d4e5f6...","satoshis":1000000}` |
|
|
149
|
+
| `wallet_purchaseListing` | Purchases NFTs or BSV-20/BSV-21 tokens from marketplace listings | `{"status":"success","txid":"a1b2c3d4e5f6...","type":"nft","origin":"abcdef123456..."}` |
|
|
150
|
+
| `wallet_createOrdinals` | Creates and inscribes ordinals on the BSV blockchain | `{"txid":"a1b2c3d4e5f6...","inscriptionAddress":"1ExampleAddress...","contentType":"image/png"}` |
|
|
150
151
|
|
|
151
152
|
### BSV Tools
|
|
152
153
|
|
|
153
154
|
Tools for interacting with the BSV blockchain and network:
|
|
154
155
|
|
|
155
|
-
| Tool Name | Description |
|
|
156
|
-
|
|
157
|
-
| `bsv_getPrice` | Gets the current BSV price from an exchange API |
|
|
158
|
-
| `bsv_decodeTransaction` | Decodes a BSV transaction and returns detailed information |
|
|
156
|
+
| Tool Name | Description | Example Output |
|
|
157
|
+
|-----------|-------------|----------------|
|
|
158
|
+
| `bsv_getPrice` | Gets the current BSV price from an exchange API | `Current BSV price: $38.75 USD` |
|
|
159
|
+
| `bsv_decodeTransaction` | Decodes a BSV transaction and returns detailed information | `{"txid":"a1b2c3d4e5f6...","version":1,"locktime":0,"size":225,"inputs":[...],"outputs":[...]}` |
|
|
160
|
+
| `bsv_explore` | Comprehensive blockchain explorer tool accessing WhatsOnChain API endpoints | `{"chain_info":{"chain":"main","blocks":826458,"headers":826458,"bestblockhash":"0000000000..."}}` |
|
|
159
161
|
|
|
160
162
|
### Ordinals Tools
|
|
161
163
|
|
|
162
164
|
Tools for working with ordinals (NFTs) on BSV:
|
|
163
165
|
|
|
164
|
-
| Tool Name | Description |
|
|
165
|
-
|
|
166
|
-
| `ordinals_getInscription` | Retrieves detailed information about a specific inscription |
|
|
167
|
-
| `ordinals_searchInscriptions` | Searches for inscriptions based on various criteria |
|
|
168
|
-
| `ordinals_marketListings` | Retrieves market listings for NFTs, BSV-20, and BSV-21 tokens with unified interface |
|
|
169
|
-
| `ordinals_marketSales` | Gets information about BSV-20 and BSV-21 token market sales |
|
|
170
|
-
| `
|
|
166
|
+
| Tool Name | Description | Example Output |
|
|
167
|
+
|-----------|-------------|----------------|
|
|
168
|
+
| `ordinals_getInscription` | Retrieves detailed information about a specific inscription | `{"id":"a1b2c3d4e5f6...","origin":"a1b2c3d4e5f6...","contentType":"image/png","content":"iVBORw0KGgoAAA..."}` |
|
|
169
|
+
| `ordinals_searchInscriptions` | Searches for inscriptions based on various criteria | `{"results":[{"id":"a1b2c3...","contentType":"image/png","owner":"1Example..."},...]}` |
|
|
170
|
+
| `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},...]}` |
|
|
171
|
+
| `ordinals_marketSales` | Gets information about BSV-20 and BSV-21 token market sales | `{"results":[{"txid":"a1b2c3...","price":34710050,"tick":"$BTC","sale":true},...]}` |
|
|
172
|
+
| `ordinals_getTokenByIdOrTicker` | Retrieves details about a specific BSV20 token by ID | `{"tick":"PEPE","max":"21000000","lim":"1000","dec":"2"}` |
|
|
171
173
|
|
|
172
174
|
### Utility Tools
|
|
173
175
|
|
|
174
176
|
General-purpose utility functions:
|
|
175
177
|
|
|
176
|
-
| Tool Name | Description |
|
|
177
|
-
|
|
178
|
-
| `utils_convertData` | Converts data between different encodings (utf8, hex, base64, binary) |
|
|
178
|
+
| Tool Name | Description | Example Output |
|
|
179
|
+
|-----------|-------------|----------------|
|
|
180
|
+
| `utils_convertData` | Converts data between different encodings (utf8, hex, base64, binary) | `68656c6c6f20776f726c64` (UTF-8 "hello world" converted to hex) |
|
|
179
181
|
|
|
180
182
|
## Using the Tools with MCP
|
|
181
183
|
|
|
@@ -185,6 +187,8 @@ Once connected, you can use natural language to interact with Bitcoin SV through
|
|
|
185
187
|
- "Get my Bitcoin SV address"
|
|
186
188
|
- "Send 0.01 BSV to 1ExampleBsvAddressXXXXXXXXXXXXXXXXX"
|
|
187
189
|
- "Send $5 USD worth of BSV to 1ExampleBsvAddressXXXXXXXXXXXXXXXXX"
|
|
190
|
+
- "Encrypt this message using my wallet's keys"
|
|
191
|
+
- "Decrypt this data that was previously encrypted for me"
|
|
188
192
|
- "Purchase this NFT listing: txid_vout"
|
|
189
193
|
- "Purchase this BSV-20 token listing: txid_vout"
|
|
190
194
|
|
|
@@ -198,6 +202,11 @@ Once connected, you can use natural language to interact with Bitcoin SV through
|
|
|
198
202
|
### Blockchain Operations
|
|
199
203
|
- "What is the current BSV price?"
|
|
200
204
|
- "Decode this BSV transaction: (transaction hex or ID)"
|
|
205
|
+
- "Get the latest Bitcoin SV chain information"
|
|
206
|
+
- "Show me block details for height 800000"
|
|
207
|
+
- "Explore transaction history for address 1ExampleBsvAddressXXXX"
|
|
208
|
+
- "Check unspent outputs (UTXOs) for my wallet address"
|
|
209
|
+
- "Get details for transaction with hash a1b2c3d4e5f6..."
|
|
201
210
|
|
|
202
211
|
### Data Conversion
|
|
203
212
|
- "Convert 'Hello World' from UTF-8 to hex format"
|
|
@@ -230,14 +239,81 @@ For Cursor, check the Cursor MCP logs in Settings → Extensions → Model Conte
|
|
|
230
239
|
|
|
231
240
|
## Recent Updates
|
|
232
241
|
|
|
233
|
-
|
|
234
|
-
- **Unified
|
|
235
|
-
- **
|
|
236
|
-
- **
|
|
242
|
+
- **Blockchain Explorer**: Added `bsv_explore` tool for WhatsOnChain API access with mainnet/testnet support
|
|
243
|
+
- **Unified Tools**: Merged `wallet_encrypt`/`wallet_decrypt` into single `wallet_encryption` tool
|
|
244
|
+
- **Enhanced Marketplace**: Support for NFTs, BSV-20/21 tokens in listings, sales and purchases
|
|
245
|
+
- **Performance**: Added price caching and optimized API endpoint structure
|
|
246
|
+
- **Improved Validation**: Better error handling for private keys and parameters
|
|
247
|
+
|
|
248
|
+
## Bitcoin SV Blockchain Explorer
|
|
249
|
+
|
|
250
|
+
The `bsv_explore` tool provides comprehensive access to the Bitcoin SV blockchain through the WhatsOnChain API. This powerful explorer tool allows you to query various aspects of the blockchain, including chain data, blocks, transactions, and address information.
|
|
251
|
+
|
|
252
|
+
### Available Endpoints
|
|
253
|
+
|
|
254
|
+
The tool supports the following endpoint categories and specific endpoints:
|
|
255
|
+
|
|
256
|
+
#### Chain Data
|
|
257
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
258
|
+
|----------|-------------|---------------------|------------------|
|
|
259
|
+
| `chain_info` | Network statistics, difficulty, and chain work | None | `{"chain":"main","blocks":826458,"headers":826458,"bestblockhash":"000000000000..."}` |
|
|
260
|
+
| `chain_tips` | Current chain tips including heights and states | None | `[{"height":826458,"hash":"000000000000...","branchlen":0,"status":"active"}]` |
|
|
261
|
+
| `circulating_supply` | Current BSV circulating supply | None | `{"bsv":21000000}` |
|
|
262
|
+
| `peer_info` | Connected peer statistics | None | `[{"addr":"1.2.3.4:8333","services":"000000000000...","lastsend":1621234567}]` |
|
|
263
|
+
|
|
264
|
+
#### Block Data
|
|
265
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
266
|
+
|----------|-------------|---------------------|------------------|
|
|
267
|
+
| `block_by_hash` | Complete block data via hash | `blockHash` | `{"hash":"000000000000...","confirmations":1000,"size":1000000,...}` |
|
|
268
|
+
| `block_by_height` | Complete block data via height | `blockHeight` | `{"hash":"000000000000...","confirmations":1000,"size":1000000,...}` |
|
|
269
|
+
|
|
270
|
+
#### Transaction Data
|
|
271
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
272
|
+
|----------|-------------|---------------------|------------------|
|
|
273
|
+
| `tx_by_hash` | Detailed transaction data | `txHash` | `{"txid":"a1b2c3d4e5f6...","version":1,"locktime":0,"size":225,...}` |
|
|
274
|
+
| `tx_raw` | Raw transaction hex data | `txHash` | `"01000000012345abcdef..."` |
|
|
275
|
+
| `tx_receipt` | Transaction receipt | `txHash` | `{"blockHash":"000000000000...","blockHeight":800000,"confirmations":26458}` |
|
|
276
|
+
|
|
277
|
+
#### Address Data
|
|
278
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
279
|
+
|----------|-------------|---------------------|------------------|
|
|
280
|
+
| `address_history` | Transaction history for address | `address`, optional: `limit` | `[{"tx_hash":"a1b2c3d4e5f6...","height":800000},...]` |
|
|
281
|
+
| `address_utxos` | Unspent outputs for address | `address` | `[{"tx_hash":"a1b2c3d4e5f6...","tx_pos":0,"value":100000},...]` |
|
|
282
|
+
|
|
283
|
+
#### Network
|
|
284
|
+
| Endpoint | Description | Required Parameters | Example Response |
|
|
285
|
+
|----------|-------------|---------------------|------------------|
|
|
286
|
+
| `health` | API health check | None | `{"status":"synced"}` |
|
|
287
|
+
|
|
288
|
+
### Usage Examples
|
|
289
|
+
|
|
290
|
+
The `bsv_explore` tool can be used with natural language prompts like:
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
"Get the current Bitcoin SV blockchain information"
|
|
294
|
+
"Show me block #800000 details"
|
|
295
|
+
"Fetch transaction history for address 1ExampleBsvAddressXXXXXXXX"
|
|
296
|
+
"Get unspent outputs for my wallet address"
|
|
297
|
+
"Check transaction details for txid a1b2c3d4e5f6..."
|
|
298
|
+
"What is the current BSV circulating supply?"
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Under the hood, the tool accepts parameters to specify which data to retrieve:
|
|
302
|
+
|
|
303
|
+
- `endpoint`: The specific WhatsOnChain endpoint to query (e.g., `chain_info`, `tx_by_hash`)
|
|
304
|
+
- `network`: The BSV network to use (`main` or `test`)
|
|
305
|
+
- Additional parameters as required by the specific endpoint:
|
|
306
|
+
- `blockHash`: For block_by_hash endpoint
|
|
307
|
+
- `blockHeight`: For block_by_height endpoint
|
|
308
|
+
- `txHash`: For transaction-related endpoints
|
|
309
|
+
- `address`: For address-related endpoints
|
|
310
|
+
- `limit`: Optional pagination limit for address_history
|
|
311
|
+
|
|
312
|
+
### Network Options
|
|
237
313
|
|
|
238
|
-
|
|
239
|
-
-
|
|
240
|
-
-
|
|
314
|
+
The tool supports both mainnet and testnet:
|
|
315
|
+
- `main`: Bitcoin SV mainnet (default)
|
|
316
|
+
- `test`: Bitcoin SV testnet
|
|
241
317
|
|
|
242
318
|
## Development
|
|
243
319
|
|
|
@@ -255,4 +331,4 @@ bun test
|
|
|
255
331
|
|
|
256
332
|
## License
|
|
257
333
|
|
|
258
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
334
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
package/index.ts
CHANGED
|
@@ -6,16 +6,43 @@ import { registerAllTools } from "./tools";
|
|
|
6
6
|
import { registerWalletTools } from "./tools/wallet/tools";
|
|
7
7
|
import { Wallet } from "./tools/wallet/wallet";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Validate the private key from environment variables
|
|
11
|
+
* Exits the process with an error message if validation fails
|
|
12
|
+
*/
|
|
13
|
+
function validatePrivateKey(): PrivateKey {
|
|
14
|
+
const privateKeyWif = process.env.PRIVATE_KEY_WIF;
|
|
15
|
+
|
|
16
|
+
// Check if private key is set
|
|
17
|
+
if (!privateKeyWif) {
|
|
18
|
+
console.error("\x1b[31mError: PRIVATE_KEY_WIF environment variable is not set\x1b[0m");
|
|
19
|
+
console.error("Please set this variable with a valid Bitcoin SV private key in WIF format");
|
|
20
|
+
console.error("Example: PRIVATE_KEY_WIF=your_private_key_wif bun run index.ts");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Validate the private key format
|
|
25
|
+
try {
|
|
26
|
+
return PrivateKey.fromWif(privateKeyWif);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error("\x1b[31mError: Invalid private key format\x1b[0m");
|
|
29
|
+
console.error("The PRIVATE_KEY_WIF provided is not a valid Bitcoin SV private key in WIF format");
|
|
30
|
+
console.error("Please check your key and try again");
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Validate private key early before starting the server
|
|
36
|
+
const privKey = validatePrivateKey();
|
|
37
|
+
console.log("\x1b[32mPrivate key validated successfully\x1b[0m");
|
|
38
|
+
|
|
9
39
|
const server = new McpServer({
|
|
10
40
|
name: "Bitcoin SV MCP",
|
|
11
41
|
version: "0.0.1",
|
|
12
42
|
});
|
|
13
43
|
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
const privateKeyWif = process.env.PRIVATE_KEY_WIF;
|
|
17
|
-
const privKey = privateKeyWif ? PrivateKey.fromWif(privateKeyWif) : undefined;
|
|
18
|
-
const wallet = privKey ? new Wallet(privKey) : new Wallet();
|
|
44
|
+
// Initialize wallet with the validated private key
|
|
45
|
+
const wallet = new Wallet(privKey);
|
|
19
46
|
|
|
20
47
|
// Register wallet tools separately (needs wallet instance)
|
|
21
48
|
registerWalletTools(server, wallet);
|
|
@@ -25,7 +52,7 @@ registerAllTools(server);
|
|
|
25
52
|
|
|
26
53
|
// Debug: Log all registered tools
|
|
27
54
|
console.log("Registered tools:", Object.keys(server));
|
|
28
|
-
console.log("MCP Server
|
|
55
|
+
console.log("MCP Server ready 🚀");
|
|
29
56
|
|
|
30
57
|
// Connect to the transport
|
|
31
58
|
const transport = new StdioServerTransport();
|
package/package.json
CHANGED
package/smithery.yaml
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
build:
|
|
2
|
+
dockerBuildPath: ./
|
|
3
|
+
|
|
1
4
|
startCommand:
|
|
2
5
|
type: stdio
|
|
3
6
|
configSchema:
|
|
@@ -7,15 +10,12 @@ startCommand:
|
|
|
7
10
|
properties:
|
|
8
11
|
privateKeyWif:
|
|
9
12
|
type: string
|
|
10
|
-
description: "
|
|
13
|
+
description: "The private key WIF (Wallet Import Format) for Bitcoin SV transactions. This key is used to sign transactions and is required for wallet operations."
|
|
11
14
|
commandFunction: |
|
|
12
|
-
(config) => ({
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"env": {
|
|
19
|
-
"PRIVATE_KEY_WIF": config.privateKeyWif
|
|
20
|
-
}
|
|
15
|
+
(config) => ({
|
|
16
|
+
command: 'bun',
|
|
17
|
+
args: ['run', 'index.ts'],
|
|
18
|
+
env: {
|
|
19
|
+
PRIVATE_KEY_WIF: config.privateKeyWif
|
|
20
|
+
}
|
|
21
21
|
})
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
|
|
4
|
+
// Base URL for WhatsOnChain API
|
|
5
|
+
const WOC_API_BASE_URL = "https://api.whatsonchain.com/v1/bsv";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* WhatsOnChain API endpoints available for exploration
|
|
9
|
+
*/
|
|
10
|
+
enum ExploreEndpoint {
|
|
11
|
+
// Chain endpoints
|
|
12
|
+
CHAIN_INFO = "chain_info",
|
|
13
|
+
CHAIN_TIPS = "chain_tips",
|
|
14
|
+
CIRCULATING_SUPPLY = "circulating_supply",
|
|
15
|
+
PEER_INFO = "peer_info",
|
|
16
|
+
|
|
17
|
+
// Block endpoints
|
|
18
|
+
BLOCK_BY_HASH = "block_by_hash",
|
|
19
|
+
BLOCK_BY_HEIGHT = "block_by_height",
|
|
20
|
+
|
|
21
|
+
// Transaction endpoints
|
|
22
|
+
TX_BY_HASH = "tx_by_hash",
|
|
23
|
+
TX_RAW = "tx_raw",
|
|
24
|
+
TX_RECEIPT = "tx_receipt",
|
|
25
|
+
ADDRESS_HISTORY = "address_history",
|
|
26
|
+
ADDRESS_UTXOS = "address_utxos",
|
|
27
|
+
|
|
28
|
+
// Health endpoint
|
|
29
|
+
HEALTH = "health",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
enum Network {
|
|
33
|
+
MAIN = "main",
|
|
34
|
+
TEST = "test",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Schema for the bsv_explore tool arguments
|
|
38
|
+
const exploreArgsSchema = z.object({
|
|
39
|
+
endpoint: z.nativeEnum(ExploreEndpoint).describe("WhatsOnChain API endpoint to call"),
|
|
40
|
+
network: z.nativeEnum(Network).default(Network.MAIN).describe("Network to use (main or test)"),
|
|
41
|
+
|
|
42
|
+
// Parameters for specific endpoints
|
|
43
|
+
blockHash: z.string().optional().describe("Block hash (required for block_by_hash endpoint)"),
|
|
44
|
+
blockHeight: z.number().optional().describe("Block height (required for block_by_height endpoint)"),
|
|
45
|
+
txHash: z.string().optional().describe("Transaction hash (required for tx_by_hash, tx_raw, and tx_receipt endpoints)"),
|
|
46
|
+
address: z.string().optional().describe("Bitcoin address (required for address_history and address_utxos endpoints)"),
|
|
47
|
+
limit: z.number().optional().describe("Limit for paginated results (optional for address_history)"),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Type for the tool arguments
|
|
51
|
+
type ExploreArgs = z.infer<typeof exploreArgsSchema>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Register the bsv_explore tool with the MCP server
|
|
55
|
+
* @param server The MCP server instance
|
|
56
|
+
*/
|
|
57
|
+
export function registerExploreTool(server: McpServer): void {
|
|
58
|
+
server.tool(
|
|
59
|
+
"bsv_explore",
|
|
60
|
+
"Explore Bitcoin SV blockchain data using the WhatsOnChain API. Access multiple data types:\n\n" +
|
|
61
|
+
"CHAIN DATA:\n" +
|
|
62
|
+
"- chain_info: Network stats, difficulty, and chain work\n" +
|
|
63
|
+
"- chain_tips: Current chain tips including heights and states\n" +
|
|
64
|
+
"- circulating_supply: Current BSV circulating supply\n" +
|
|
65
|
+
"- peer_info: Connected peer statistics\n\n" +
|
|
66
|
+
"BLOCK DATA:\n" +
|
|
67
|
+
"- block_by_hash: Complete block data via hash (requires blockHash parameter)\n" +
|
|
68
|
+
"- block_by_height: Complete block data via height (requires blockHeight parameter)\n\n" +
|
|
69
|
+
"TRANSACTION DATA:\n" +
|
|
70
|
+
"- tx_by_hash: Detailed transaction data (requires txHash parameter)\n" +
|
|
71
|
+
"- tx_raw: Raw transaction hex data (requires txHash parameter)\n" +
|
|
72
|
+
"- tx_receipt: Transaction receipt (requires txHash parameter)\n\n" +
|
|
73
|
+
"ADDRESS DATA:\n" +
|
|
74
|
+
"- address_history: Transaction history for address (requires address parameter, optional limit)\n" +
|
|
75
|
+
"- address_utxos: Unspent outputs for address (requires address parameter)\n\n" +
|
|
76
|
+
"NETWORK:\n" +
|
|
77
|
+
"- health: API health check\n\n" +
|
|
78
|
+
"Use the appropriate parameters for each endpoint type and specify 'main' or 'test' network.",
|
|
79
|
+
{ args: exploreArgsSchema },
|
|
80
|
+
async ({ args }) => {
|
|
81
|
+
try {
|
|
82
|
+
const params = exploreArgsSchema.parse(args);
|
|
83
|
+
|
|
84
|
+
// Validate required parameters for specific endpoints
|
|
85
|
+
if (params.endpoint === ExploreEndpoint.BLOCK_BY_HASH && !params.blockHash) {
|
|
86
|
+
throw new Error("blockHash is required for block_by_hash endpoint");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (params.endpoint === ExploreEndpoint.BLOCK_BY_HEIGHT && params.blockHeight === undefined) {
|
|
90
|
+
throw new Error("blockHeight is required for block_by_height endpoint");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if ([ExploreEndpoint.TX_BY_HASH, ExploreEndpoint.TX_RAW, ExploreEndpoint.TX_RECEIPT].includes(params.endpoint) && !params.txHash) {
|
|
94
|
+
throw new Error("txHash is required for transaction endpoints");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if ([ExploreEndpoint.ADDRESS_HISTORY, ExploreEndpoint.ADDRESS_UTXOS].includes(params.endpoint) && !params.address) {
|
|
98
|
+
throw new Error("address is required for address endpoints");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Build API URL based on the selected endpoint
|
|
102
|
+
let apiUrl = `${WOC_API_BASE_URL}/${params.network}`;
|
|
103
|
+
|
|
104
|
+
switch (params.endpoint) {
|
|
105
|
+
case ExploreEndpoint.CHAIN_INFO:
|
|
106
|
+
apiUrl += "/chain/info";
|
|
107
|
+
break;
|
|
108
|
+
case ExploreEndpoint.CHAIN_TIPS:
|
|
109
|
+
apiUrl += "/chain/tips";
|
|
110
|
+
break;
|
|
111
|
+
case ExploreEndpoint.CIRCULATING_SUPPLY:
|
|
112
|
+
apiUrl += "/circulatingsupply";
|
|
113
|
+
break;
|
|
114
|
+
case ExploreEndpoint.PEER_INFO:
|
|
115
|
+
apiUrl += "/peer/info";
|
|
116
|
+
break;
|
|
117
|
+
case ExploreEndpoint.BLOCK_BY_HASH:
|
|
118
|
+
apiUrl += `/block/hash/${params.blockHash}`;
|
|
119
|
+
break;
|
|
120
|
+
case ExploreEndpoint.BLOCK_BY_HEIGHT:
|
|
121
|
+
apiUrl += `/block/height/${params.blockHeight}`;
|
|
122
|
+
break;
|
|
123
|
+
case ExploreEndpoint.TX_BY_HASH:
|
|
124
|
+
apiUrl += `/tx/hash/${params.txHash}`;
|
|
125
|
+
break;
|
|
126
|
+
case ExploreEndpoint.TX_RAW:
|
|
127
|
+
apiUrl += `/tx/${params.txHash}/hex`;
|
|
128
|
+
break;
|
|
129
|
+
case ExploreEndpoint.TX_RECEIPT:
|
|
130
|
+
apiUrl += `/tx/${params.txHash}/receipt`;
|
|
131
|
+
break;
|
|
132
|
+
case ExploreEndpoint.ADDRESS_HISTORY:
|
|
133
|
+
apiUrl += `/address/${params.address}/history`;
|
|
134
|
+
if (params.limit !== undefined) {
|
|
135
|
+
apiUrl += `?limit=${params.limit}`;
|
|
136
|
+
}
|
|
137
|
+
break;
|
|
138
|
+
case ExploreEndpoint.ADDRESS_UTXOS:
|
|
139
|
+
apiUrl += `/address/${params.address}/unspent`;
|
|
140
|
+
break;
|
|
141
|
+
case ExploreEndpoint.HEALTH:
|
|
142
|
+
apiUrl += "/woc";
|
|
143
|
+
break;
|
|
144
|
+
default:
|
|
145
|
+
throw new Error(`Unsupported endpoint: ${params.endpoint}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Make the API request
|
|
149
|
+
const response = await fetch(apiUrl);
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
throw new Error(`API error: ${response.status} ${response.statusText}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const result = await response.json();
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
content: [
|
|
158
|
+
{
|
|
159
|
+
type: "text",
|
|
160
|
+
text: JSON.stringify(result, null, 2),
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
};
|
|
164
|
+
} catch (error) {
|
|
165
|
+
return {
|
|
166
|
+
content: [
|
|
167
|
+
{
|
|
168
|
+
type: "text",
|
|
169
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
170
|
+
}
|
|
171
|
+
],
|
|
172
|
+
isError: true,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
}
|
package/tools/bsv/getPrice.ts
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
|
+
// Define cache duration (5 minutes in milliseconds)
|
|
5
|
+
const PRICE_CACHE_DURATION = 5 * 60 * 1000;
|
|
6
|
+
|
|
7
|
+
// Cache object to store price data
|
|
8
|
+
let cachedPrice: { value: number; timestamp: number } | null = null;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get the BSV price with caching mechanism
|
|
12
|
+
* @returns The current BSV price in USD
|
|
13
|
+
*/
|
|
14
|
+
async function getBsvPriceWithCache(): Promise<number> {
|
|
15
|
+
// Return cached price if it's still valid
|
|
16
|
+
if (cachedPrice && (Date.now() - cachedPrice.timestamp) < PRICE_CACHE_DURATION) {
|
|
17
|
+
console.log("Using cached BSV price");
|
|
18
|
+
return cachedPrice.value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log("Fetching fresh BSV price");
|
|
22
|
+
// If no valid cache, fetch new price
|
|
23
|
+
const res = await fetch(
|
|
24
|
+
"https://api.whatsonchain.com/v1/bsv/main/exchangerate",
|
|
25
|
+
);
|
|
26
|
+
if (!res.ok) throw new Error("Failed to fetch price");
|
|
27
|
+
|
|
28
|
+
const data = (await res.json()) as {
|
|
29
|
+
currency: string;
|
|
30
|
+
rate: string;
|
|
31
|
+
time: number;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const price = Number(data.rate);
|
|
35
|
+
if (Number.isNaN(price) || price <= 0) throw new Error("Invalid price received");
|
|
36
|
+
|
|
37
|
+
// Update cache
|
|
38
|
+
cachedPrice = {
|
|
39
|
+
value: price,
|
|
40
|
+
timestamp: Date.now()
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return price;
|
|
44
|
+
}
|
|
45
|
+
|
|
4
46
|
/**
|
|
5
47
|
* Register the BSV price lookup tool
|
|
6
48
|
* @param server The MCP server instance
|
|
@@ -14,23 +56,12 @@ export function registerGetPriceTool(server: McpServer): void {
|
|
|
14
56
|
},
|
|
15
57
|
async () => {
|
|
16
58
|
try {
|
|
17
|
-
const
|
|
18
|
-
"https://api.whatsonchain.com/v1/bsv/main/exchangerate",
|
|
19
|
-
);
|
|
20
|
-
if (!res.ok) throw new Error("Failed to fetch price");
|
|
21
|
-
const data = (await res.json()) as {
|
|
22
|
-
currency: string;
|
|
23
|
-
rate: string;
|
|
24
|
-
time: number;
|
|
25
|
-
};
|
|
26
|
-
const price = data.rate;
|
|
27
|
-
if (typeof price !== "string" && typeof price !== "number")
|
|
28
|
-
throw new Error("Price not found");
|
|
59
|
+
const price = await getBsvPriceWithCache();
|
|
29
60
|
return {
|
|
30
61
|
content: [
|
|
31
62
|
{
|
|
32
63
|
type: "text",
|
|
33
|
-
text: `Current BSV price: $${
|
|
64
|
+
text: `Current BSV price: $${price.toFixed(2)} USD`,
|
|
34
65
|
},
|
|
35
66
|
],
|
|
36
67
|
};
|
|
@@ -43,3 +74,6 @@ export function registerGetPriceTool(server: McpServer): void {
|
|
|
43
74
|
},
|
|
44
75
|
);
|
|
45
76
|
}
|
|
77
|
+
|
|
78
|
+
// Export the cached price getter for use in other modules
|
|
79
|
+
export { getBsvPriceWithCache };
|
package/tools/bsv/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { registerDecodeTransactionTool } from "./decodeTransaction";
|
|
3
3
|
import { registerGetPriceTool } from "./getPrice";
|
|
4
|
+
import { registerExploreTool } from "./explore";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Register all BSV tools with the MCP server
|
|
@@ -10,4 +11,5 @@ export function registerBsvTools(server: McpServer): void {
|
|
|
10
11
|
// Register BSV-related tools
|
|
11
12
|
registerGetPriceTool(server);
|
|
12
13
|
registerDecodeTransactionTool(server);
|
|
14
|
+
registerExploreTool(server);
|
|
13
15
|
}
|
package/tools/wallet/schemas.ts
CHANGED
|
@@ -72,6 +72,19 @@ export const walletDecryptArgsSchema = z.object({
|
|
|
72
72
|
privileged: z.boolean().optional(),
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
+
// Combined wallet encryption/decryption args
|
|
76
|
+
export const walletEncryptionArgsSchema = z.object({
|
|
77
|
+
mode: z.enum(["encrypt", "decrypt"]).describe("Operation mode: 'encrypt' to encrypt data or 'decrypt' to decrypt data"),
|
|
78
|
+
data: z.array(z.number()).describe("Data to process: plaintext for encryption or ciphertext for decryption"),
|
|
79
|
+
protocolID: walletProtocolSchema,
|
|
80
|
+
keyID: z.string(),
|
|
81
|
+
privilegedReason: z.string().optional(),
|
|
82
|
+
counterparty: z
|
|
83
|
+
.union([z.string(), z.literal("self"), z.literal("anyone")])
|
|
84
|
+
.optional(),
|
|
85
|
+
privileged: z.boolean().optional(),
|
|
86
|
+
}).describe("Combined schema for encryption and decryption operations, with a mode parameter to switch between functions");
|
|
87
|
+
|
|
75
88
|
// Create HMAC arguments
|
|
76
89
|
export const createHmacArgsSchema = z.object({
|
|
77
90
|
message: z.string(),
|
|
@@ -296,3 +309,4 @@ export const purchaseListingArgsSchema = z.object({
|
|
|
296
309
|
// Export types
|
|
297
310
|
export type SendToAddressArgs = z.infer<typeof sendToAddressArgsSchema>;
|
|
298
311
|
export type PurchaseListingArgs = z.infer<typeof purchaseListingArgsSchema>;
|
|
312
|
+
export type WalletEncryptionArgs = z.infer<typeof walletEncryptionArgsSchema>;
|
|
@@ -5,33 +5,7 @@ import { toSatoshi } from "satoshi-token";
|
|
|
5
5
|
import type { z } from "zod";
|
|
6
6
|
import { sendToAddressArgsSchema } from "./schemas";
|
|
7
7
|
import type { Wallet } from "./wallet";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Fetch the current BSV price from whatsonchain API
|
|
11
|
-
* @returns The BSV price in USD
|
|
12
|
-
*/
|
|
13
|
-
async function getBsvPrice(): Promise<number> {
|
|
14
|
-
try {
|
|
15
|
-
const res = await fetch(
|
|
16
|
-
"https://api.whatsonchain.com/v1/bsv/main/exchangerate",
|
|
17
|
-
);
|
|
18
|
-
if (!res.ok) throw new Error("Failed to fetch BSV price");
|
|
19
|
-
|
|
20
|
-
// Parse the response with proper type casting
|
|
21
|
-
const data = (await res.json()) as {
|
|
22
|
-
rate: string;
|
|
23
|
-
currency: string;
|
|
24
|
-
time: number;
|
|
25
|
-
};
|
|
26
|
-
const price = Number(data.rate);
|
|
27
|
-
|
|
28
|
-
if (Number.isNaN(price) || price <= 0) throw new Error("Invalid BSV price");
|
|
29
|
-
return price;
|
|
30
|
-
} catch (error) {
|
|
31
|
-
console.error("BSV price fetch error:", error);
|
|
32
|
-
throw error;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
8
|
+
import { getBsvPriceWithCache } from "../bsv/getPrice";
|
|
35
9
|
|
|
36
10
|
// Use the schema imported from schemas.ts
|
|
37
11
|
export type SendToAddressArgs = z.infer<typeof sendToAddressArgsSchema>;
|
|
@@ -62,7 +36,7 @@ export function registerSendToAddressTool(server: McpServer, wallet: Wallet) {
|
|
|
62
36
|
let satoshis: number;
|
|
63
37
|
if (currency === "USD") {
|
|
64
38
|
// Get current BSV price
|
|
65
|
-
const bsvPriceUsd = await
|
|
39
|
+
const bsvPriceUsd = await getBsvPriceWithCache();
|
|
66
40
|
|
|
67
41
|
// Convert USD to BSV
|
|
68
42
|
const bsvAmount = amount / bsvPriceUsd;
|
|
@@ -11,15 +11,13 @@ type WalletToolName =
|
|
|
11
11
|
| "wallet_getPublicKey"
|
|
12
12
|
| "wallet_createSignature"
|
|
13
13
|
| "wallet_verifySignature"
|
|
14
|
-
| "
|
|
15
|
-
| "wallet_decrypt";
|
|
14
|
+
| "wallet_encryption";
|
|
16
15
|
|
|
17
16
|
const toolNames: WalletToolName[] = [
|
|
18
17
|
"wallet_getPublicKey",
|
|
19
18
|
"wallet_createSignature",
|
|
20
19
|
"wallet_verifySignature",
|
|
21
|
-
"
|
|
22
|
-
"wallet_decrypt",
|
|
20
|
+
"wallet_encryption",
|
|
23
21
|
];
|
|
24
22
|
|
|
25
23
|
// Helper function to get dummy arguments for each tool
|
|
@@ -36,10 +34,12 @@ function getDummyArgs(tool: WalletToolName): Record<string, unknown> {
|
|
|
36
34
|
signature: "sig",
|
|
37
35
|
publicKey: "pubkey",
|
|
38
36
|
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
// TODO we merged encrypt and decrypt into encryption we need to update the test file
|
|
38
|
+
// case "wallet_encryption":
|
|
39
|
+
// if
|
|
40
|
+
// return { data: "test", publicKey: "pubkey" };
|
|
41
|
+
// case "wallet_decryption":
|
|
42
|
+
// return { encryptedData: "data" };
|
|
43
43
|
default:
|
|
44
44
|
return {};
|
|
45
45
|
}
|
package/tools/wallet/tools.ts
CHANGED
|
@@ -31,8 +31,7 @@ import {
|
|
|
31
31
|
type purchaseListingArgsSchema,
|
|
32
32
|
type sendToAddressArgsSchema,
|
|
33
33
|
verifySignatureArgsSchema,
|
|
34
|
-
|
|
35
|
-
walletEncryptArgsSchema,
|
|
34
|
+
walletEncryptionArgsSchema,
|
|
36
35
|
} from "./schemas";
|
|
37
36
|
|
|
38
37
|
import { registerCreateOrdinalsTool } from "./createOrdinals";
|
|
@@ -46,8 +45,7 @@ type ToolArgSchemas = {
|
|
|
46
45
|
wallet_getPublicKey: typeof getPublicKeyArgsSchema;
|
|
47
46
|
wallet_createSignature: typeof createSignatureArgsSchema;
|
|
48
47
|
wallet_verifySignature: typeof verifySignatureArgsSchema;
|
|
49
|
-
|
|
50
|
-
wallet_decrypt: typeof walletDecryptArgsSchema;
|
|
48
|
+
wallet_encryption: typeof walletEncryptionArgsSchema;
|
|
51
49
|
wallet_listActions: typeof listActionsArgsSchema;
|
|
52
50
|
wallet_listOutputs: typeof listOutputsArgsSchema;
|
|
53
51
|
wallet_getNetwork: typeof emptyArgsSchema;
|
|
@@ -94,11 +92,12 @@ export function registerWalletTools(
|
|
|
94
92
|
// Handle tools registration with properly typed parameters
|
|
95
93
|
function registerTool<T extends z.ZodType>(
|
|
96
94
|
name: keyof ToolArgSchemas,
|
|
95
|
+
description: string,
|
|
97
96
|
schema: { args: T },
|
|
98
97
|
handler: ToolCallback<{ args: T }>,
|
|
99
98
|
): void {
|
|
100
99
|
// Register all tools normally
|
|
101
|
-
server.tool(name, schema, handler);
|
|
100
|
+
server.tool(name, description, schema, handler);
|
|
102
101
|
handlers[name] = handler as ToolHandler;
|
|
103
102
|
}
|
|
104
103
|
|
|
@@ -117,6 +116,7 @@ export function registerWalletTools(
|
|
|
117
116
|
// Register wallet_getPublicKey
|
|
118
117
|
registerTool(
|
|
119
118
|
"wallet_getPublicKey",
|
|
119
|
+
"Retrieves the current wallet's public key. This public key can be used for cryptographic operations like signature verification or encryption.",
|
|
120
120
|
{ args: getPublicKeyArgsSchema },
|
|
121
121
|
async (
|
|
122
122
|
{ args }: { args: z.infer<typeof getPublicKeyArgsSchema> },
|
|
@@ -135,6 +135,7 @@ export function registerWalletTools(
|
|
|
135
135
|
// Register wallet_createSignature
|
|
136
136
|
registerTool(
|
|
137
137
|
"wallet_createSignature",
|
|
138
|
+
"Creates a cryptographic signature using the wallet's private key. This tool enables secure message signing and transaction authorization, supporting various signature protocols.",
|
|
138
139
|
{ args: createSignatureArgsSchema },
|
|
139
140
|
async (
|
|
140
141
|
{ args }: { args: z.infer<typeof createSignatureArgsSchema> },
|
|
@@ -153,6 +154,7 @@ export function registerWalletTools(
|
|
|
153
154
|
// Register wallet_verifySignature
|
|
154
155
|
registerTool(
|
|
155
156
|
"wallet_verifySignature",
|
|
157
|
+
"Verifies a cryptographic signature against a message or data. This tool supports various verification protocols and can validate signatures from both the wallet's own keys and external public keys.",
|
|
156
158
|
{ args: verifySignatureArgsSchema },
|
|
157
159
|
async (
|
|
158
160
|
{ args }: { args: z.infer<typeof verifySignatureArgsSchema> },
|
|
@@ -168,16 +170,38 @@ export function registerWalletTools(
|
|
|
168
170
|
},
|
|
169
171
|
);
|
|
170
172
|
|
|
171
|
-
// Register
|
|
173
|
+
// Register combined wallet_encryption tool
|
|
172
174
|
registerTool(
|
|
173
|
-
"
|
|
174
|
-
|
|
175
|
+
"wallet_encryption",
|
|
176
|
+
"Combined tool for encrypting and decrypting data using the wallet's cryptographic keys. Supports both encryption of plaintext data and decryption of previously encrypted content. Use the 'mode' parameter to switch between operations.",
|
|
177
|
+
{ args: walletEncryptionArgsSchema },
|
|
175
178
|
async (
|
|
176
|
-
{ args }: { args: z.infer<typeof
|
|
179
|
+
{ args }: { args: z.infer<typeof walletEncryptionArgsSchema> },
|
|
177
180
|
extra: RequestHandlerExtra,
|
|
178
181
|
) => {
|
|
179
182
|
try {
|
|
180
|
-
|
|
183
|
+
let result: { ciphertext?: number[]; plaintext?: number[] };
|
|
184
|
+
if (args.mode === "encrypt") {
|
|
185
|
+
// For encryption, the data is treated as plaintext
|
|
186
|
+
result = await wallet.encrypt({
|
|
187
|
+
plaintext: args.data,
|
|
188
|
+
protocolID: args.protocolID,
|
|
189
|
+
keyID: args.keyID,
|
|
190
|
+
privilegedReason: args.privilegedReason,
|
|
191
|
+
counterparty: args.counterparty,
|
|
192
|
+
privileged: args.privileged,
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
// For decryption, the data is treated as ciphertext
|
|
196
|
+
result = await wallet.decrypt({
|
|
197
|
+
ciphertext: args.data,
|
|
198
|
+
protocolID: args.protocolID,
|
|
199
|
+
keyID: args.keyID,
|
|
200
|
+
privilegedReason: args.privilegedReason,
|
|
201
|
+
counterparty: args.counterparty,
|
|
202
|
+
privileged: args.privileged,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
181
205
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
182
206
|
} catch (err: unknown) {
|
|
183
207
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -186,27 +210,8 @@ export function registerWalletTools(
|
|
|
186
210
|
},
|
|
187
211
|
);
|
|
188
212
|
|
|
189
|
-
// Register
|
|
190
|
-
registerTool(
|
|
191
|
-
"wallet_decrypt",
|
|
192
|
-
{ args: walletDecryptArgsSchema },
|
|
193
|
-
async (
|
|
194
|
-
{ args }: { args: z.infer<typeof walletDecryptArgsSchema> },
|
|
195
|
-
extra: RequestHandlerExtra,
|
|
196
|
-
) => {
|
|
197
|
-
try {
|
|
198
|
-
const result = await wallet.decrypt(args);
|
|
199
|
-
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
200
|
-
} catch (err: unknown) {
|
|
201
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
202
|
-
return { content: [{ type: "text", text: msg }], isError: true };
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
// Register ordinals extension tools
|
|
208
|
-
// Register the wallet_createOrdinals tool
|
|
213
|
+
// Register createOrdinals tool
|
|
209
214
|
registerCreateOrdinalsTool(server, wallet);
|
|
210
|
-
|
|
215
|
+
|
|
211
216
|
return handlers;
|
|
212
217
|
}
|
package/tools/wallet/wallet.ts
CHANGED
|
@@ -38,6 +38,7 @@ import type {
|
|
|
38
38
|
ListOutputsResult,
|
|
39
39
|
ProveCertificateArgs,
|
|
40
40
|
ProveCertificateResult,
|
|
41
|
+
PubKeyHex,
|
|
41
42
|
RelinquishCertificateArgs,
|
|
42
43
|
RelinquishCertificateResult,
|
|
43
44
|
RelinquishOutputArgs,
|
|
@@ -127,7 +128,15 @@ export class Wallet extends ProtoWallet implements WalletInterface {
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
async getPublicKey(args: GetPublicKeyArgs): Promise<GetPublicKeyResult> {
|
|
130
|
-
|
|
131
|
+
const privateKey = this.getPrivateKey();
|
|
132
|
+
if (!privateKey) {
|
|
133
|
+
throw new Error("No private key available");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const publicKey = privateKey.toPublicKey();
|
|
137
|
+
return {
|
|
138
|
+
publicKey: publicKey.toDER("hex") as PubKeyHex,
|
|
139
|
+
};
|
|
131
140
|
}
|
|
132
141
|
async revealCounterpartyKeyLinkage(
|
|
133
142
|
args: RevealCounterpartyKeyLinkageArgs,
|