bsv-mcp 0.0.33 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -1
- package/README.md +8 -0
- package/index.ts +9 -3
- package/package.json +5 -4
- package/resources/junglebus.ts +242 -0
- package/resources/resources.ts +4 -0
- package/tools/a2b/discover.ts +184 -44
- package/tools/index.ts +2 -2
- package/tools/wallet/a2bPublishAgent.ts +45 -17
- package/tools/wallet/a2bPublishMcp.ts +223 -45
- package/tools/wallet/createOrdinals.ts +44 -27
- package/tools/wallet/fetchPaymentUtxos.ts +130 -0
- package/tools/wallet/purchaseListing.ts +47 -36
- package/tools/wallet/refreshUtxos.ts +76 -0
- package/tools/wallet/sendOrdinals.ts +45 -29
- package/tools/wallet/tools.ts +18 -4
- package/tools/wallet/transferOrdToken.ts +35 -12
- package/tools/wallet/wallet.ts +29 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,38 @@
|
|
|
1
1
|
# BSV MCP Server Changelog
|
|
2
2
|
|
|
3
|
+
## v0.0.35 - A2B Overlay Integration & Improved MCP Server Publishing
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
- **A2B Overlay Integration**: Implemented a robust connection to the A2B Overlay API
|
|
7
|
+
- Updated `a2b_discover` tool to search for on-chain MCP servers and agents
|
|
8
|
+
- Enhanced search capabilities with relevance-based result ranking
|
|
9
|
+
- User-friendly formatted output with command suggestions
|
|
10
|
+
- Support for filtering by type (agent/tool/all), block range, and free text search
|
|
11
|
+
- **Improved MCP Server Publishing**: Enhanced the wallet_a2bPublishMcp tool
|
|
12
|
+
- Better identity key integration via LocalSigner
|
|
13
|
+
- More robust configuration for sigma signing
|
|
14
|
+
- Improved transaction handling and error reporting
|
|
15
|
+
|
|
16
|
+
### Technical Improvements
|
|
17
|
+
- Updated API endpoint to use production overlay service
|
|
18
|
+
- Implemented enhanced search for better relevance scoring
|
|
19
|
+
- Better error handling for API responses
|
|
20
|
+
- Improved response formatting for readability
|
|
21
|
+
- Updated type definitions for consistency
|
|
22
|
+
|
|
23
|
+
## v0.0.34 - Transaction Broadcast Control
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
- Added `DISABLE_BROADCASTING` environment variable to control transaction broadcasting behavior
|
|
27
|
+
- When set to "true", transactions are created but not broadcast to the network
|
|
28
|
+
- Returns raw transaction hex instead of broadcasting, useful for testing and review
|
|
29
|
+
- Code cleanup and organization improvements
|
|
30
|
+
|
|
3
31
|
## v0.0.33 - Identity Key Sigma Signing
|
|
4
32
|
|
|
5
33
|
### Features
|
|
6
34
|
- Added optional `IDENTITY_KEY_WIF` environment variable for sigma-protocol signing.
|
|
7
|
-
-
|
|
35
|
+
- `wallet_createOrdinals`, and `wallet_purchaseListing` tools now support signing with an identity key.
|
|
8
36
|
- Updated `README.md` to document `IDENTITY_KEY_WIF` usage and JSON configuration examples.
|
|
9
37
|
|
|
10
38
|
## v0.0.32 - Reliability Improvements
|
package/README.md
CHANGED
|
@@ -365,6 +365,7 @@ The BSV MCP server can be customized using environment variables to enable or di
|
|
|
365
365
|
| `DISABLE_ORDINALS_TOOLS` | `false` | Set to `true` to disable Ordinals/NFT tools |
|
|
366
366
|
| `DISABLE_UTILS_TOOLS` | `false` | Set to `true` to disable utility tools |
|
|
367
367
|
| `IDENTITY_KEY_WIF` | `not set` | Optional WIF for identity key; if set, ordinals inscriptions will be signed with sigma-protocol for authentication, curation, and web-of-trust. |
|
|
368
|
+
| `DISABLE_BROADCASTING` | `false` | Set to `true` to disable transaction broadcasting; returns raw transaction hex instead - useful for testing and transaction review before broadcasting |
|
|
368
369
|
|
|
369
370
|
### Examples
|
|
370
371
|
|
|
@@ -386,6 +387,12 @@ Use all tools except wallet operations:
|
|
|
386
387
|
DISABLE_WALLET_TOOLS=true bunx bsv-mcp@latest
|
|
387
388
|
```
|
|
388
389
|
|
|
390
|
+
Create transactions without broadcasting them (dry-run mode):
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
DISABLE_BROADCASTING=true bunx bsv-mcp@latest
|
|
394
|
+
```
|
|
395
|
+
|
|
389
396
|
## Troubleshooting
|
|
390
397
|
|
|
391
398
|
If you're having issues with the BSV MCP server:
|
|
@@ -427,6 +434,7 @@ For Cursor, check the Cursor MCP logs in Settings → Extensions → Model Conte
|
|
|
427
434
|
|
|
428
435
|
## Recent Updates
|
|
429
436
|
|
|
437
|
+
- **Transaction Broadcast Control**: Added `DISABLE_BROADCASTING` environment variable to prevent transactions from being broadcast to the network
|
|
430
438
|
- **Blockchain Explorer**: Added `bsv_explore` tool for WhatsOnChain API access with mainnet/testnet support
|
|
431
439
|
- **Unified Tools**: Merged `wallet_encrypt`/`wallet_decrypt` into single `wallet_encryption` tool
|
|
432
440
|
- **Enhanced Marketplace**: Support for NFTs, BSV-20/21 tokens in listings, sales and purchases
|
package/index.ts
CHANGED
|
@@ -24,7 +24,10 @@ const CONFIG = {
|
|
|
24
24
|
loadBsvTools: process.env.DISABLE_BSV_TOOLS !== "true",
|
|
25
25
|
loadOrdinalsTools: process.env.DISABLE_ORDINALS_TOOLS !== "true",
|
|
26
26
|
loadUtilsTools: process.env.DISABLE_UTILS_TOOLS !== "true",
|
|
27
|
-
loadA2bTools: process.env.
|
|
27
|
+
loadA2bTools: process.env.ENABLE_A2B_TOOLS === "true",
|
|
28
|
+
|
|
29
|
+
// Transaction broadcasting control
|
|
30
|
+
disableBroadcasting: process.env.DISABLE_BROADCASTING === "true",
|
|
28
31
|
};
|
|
29
32
|
|
|
30
33
|
/**
|
|
@@ -70,7 +73,7 @@ function initializePrivateKey(): PrivateKey | undefined {
|
|
|
70
73
|
const privKey = initializePrivateKey();
|
|
71
74
|
|
|
72
75
|
const server = new McpServer(
|
|
73
|
-
{ name: "Bitcoin SV", version: "0.0.
|
|
76
|
+
{ name: "Bitcoin SV", version: "0.0.35" },
|
|
74
77
|
// {
|
|
75
78
|
// // Advertise only what you actually implement
|
|
76
79
|
// capabilities: {
|
|
@@ -102,7 +105,10 @@ if (CONFIG.loadTools) {
|
|
|
102
105
|
// Initialize wallet with the private key if wallet tools are enabled
|
|
103
106
|
if (CONFIG.loadWalletTools) {
|
|
104
107
|
wallet = new Wallet(privKey);
|
|
105
|
-
registerWalletTools(server, wallet
|
|
108
|
+
registerWalletTools(server, wallet, {
|
|
109
|
+
disableBroadcasting: CONFIG.disableBroadcasting,
|
|
110
|
+
enableA2bTools: CONFIG.loadA2bTools,
|
|
111
|
+
});
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
114
|
|
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.35",
|
|
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",
|
|
@@ -14,11 +14,12 @@
|
|
|
14
14
|
"bitcoin",
|
|
15
15
|
"bsv",
|
|
16
16
|
"bitcoin-sv",
|
|
17
|
-
"mcp",
|
|
18
|
-
"model-context-protocol",
|
|
19
17
|
"wallet",
|
|
20
18
|
"ordinals",
|
|
21
|
-
"blockchain"
|
|
19
|
+
"blockchain",
|
|
20
|
+
"1sat-ordinals",
|
|
21
|
+
"explorer",
|
|
22
|
+
"block explorer"
|
|
22
23
|
],
|
|
23
24
|
"files": [
|
|
24
25
|
"package.json",
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
|
|
3
|
+
// Main JungleBus API documentation URL
|
|
4
|
+
const JUNGLEBUS_DOCS_URL = "https://junglebus.gorillapool.io/docs/";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Manually structured JungleBus API documentation
|
|
8
|
+
* Provides a clean summary of key JungleBus API endpoints and functionality
|
|
9
|
+
*/
|
|
10
|
+
export function getJungleBusDocumentation(): string {
|
|
11
|
+
return `# JungleBus API Documentation
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
JungleBus is a transaction monitoring service for Bitcoin SV that allows applications to subscribe to transaction events and filter them based on specific criteria. The API provides both subscription and querying capabilities.
|
|
16
|
+
|
|
17
|
+
## API Endpoints
|
|
18
|
+
|
|
19
|
+
### Base URL
|
|
20
|
+
\`\`\`
|
|
21
|
+
https://junglebus.gorillapool.io/v1
|
|
22
|
+
\`\`\`
|
|
23
|
+
|
|
24
|
+
### Transaction API
|
|
25
|
+
|
|
26
|
+
#### Get Transaction by ID
|
|
27
|
+
\`\`\`
|
|
28
|
+
GET /transaction/get/{txid}
|
|
29
|
+
\`\`\`
|
|
30
|
+
|
|
31
|
+
Returns detailed information about a specific transaction, including:
|
|
32
|
+
- Transaction data (hex format)
|
|
33
|
+
- Block information (hash, height, time)
|
|
34
|
+
- Input and output details
|
|
35
|
+
- Address information
|
|
36
|
+
|
|
37
|
+
#### Get Transactions by Block Hash
|
|
38
|
+
\`\`\`
|
|
39
|
+
GET /block/{blockhash}/transactions
|
|
40
|
+
\`\`\`
|
|
41
|
+
|
|
42
|
+
Returns all transactions within a specific block.
|
|
43
|
+
|
|
44
|
+
### Subscription API
|
|
45
|
+
|
|
46
|
+
#### Create Subscription
|
|
47
|
+
\`\`\`
|
|
48
|
+
POST /subscribe
|
|
49
|
+
\`\`\`
|
|
50
|
+
|
|
51
|
+
Create a new subscription to monitor transactions based on filtering criteria.
|
|
52
|
+
|
|
53
|
+
Example request body:
|
|
54
|
+
\`\`\`json
|
|
55
|
+
{
|
|
56
|
+
"callback": "https://your-callback-url.com",
|
|
57
|
+
"fromBlock": 0,
|
|
58
|
+
"query": {
|
|
59
|
+
"find": {
|
|
60
|
+
"out.tape.cell.s": "BEEF"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
\`\`\`
|
|
65
|
+
|
|
66
|
+
#### Delete Subscription
|
|
67
|
+
\`\`\`
|
|
68
|
+
DELETE /subscribe/{id}
|
|
69
|
+
\`\`\`
|
|
70
|
+
|
|
71
|
+
Deletes an existing subscription.
|
|
72
|
+
|
|
73
|
+
### Network API
|
|
74
|
+
|
|
75
|
+
#### Get Network Info
|
|
76
|
+
\`\`\`
|
|
77
|
+
GET /network/info
|
|
78
|
+
\`\`\`
|
|
79
|
+
|
|
80
|
+
Returns current blockchain network information, including block height and other statistics.
|
|
81
|
+
|
|
82
|
+
## Client Implementations
|
|
83
|
+
|
|
84
|
+
### TypeScript Client
|
|
85
|
+
|
|
86
|
+
Installation:
|
|
87
|
+
\`\`\`bash
|
|
88
|
+
$ npm install @gorillapool/js-junglebus
|
|
89
|
+
\`\`\`
|
|
90
|
+
|
|
91
|
+
Usage:
|
|
92
|
+
\`\`\`javascript
|
|
93
|
+
import { JungleBusClient } from '@gorillapool/js-junglebus';
|
|
94
|
+
|
|
95
|
+
const server = "junglebus.gorillapool.io";
|
|
96
|
+
const jungleBusClient = new JungleBusClient(server, {
|
|
97
|
+
onConnected(ctx) {
|
|
98
|
+
// add your own code here
|
|
99
|
+
console.log(ctx);
|
|
100
|
+
},
|
|
101
|
+
onConnecting(ctx) {
|
|
102
|
+
// add your own code here
|
|
103
|
+
console.log(ctx);
|
|
104
|
+
},
|
|
105
|
+
onDisconnected(ctx) {
|
|
106
|
+
// add your own code here
|
|
107
|
+
console.log(ctx);
|
|
108
|
+
},
|
|
109
|
+
onError(ctx) {
|
|
110
|
+
// add your own code here
|
|
111
|
+
console.error(ctx);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// create subscriptions in the dashboard of the JungleBus website
|
|
116
|
+
const subId = "...."; // fill in the ID for the subscription
|
|
117
|
+
const fromBlock = 750000;
|
|
118
|
+
|
|
119
|
+
const subscription = jungleBusClient.Subscribe(
|
|
120
|
+
subId,
|
|
121
|
+
fromBlock,
|
|
122
|
+
onPublish(tx) => {
|
|
123
|
+
// add your own code here
|
|
124
|
+
console.log(tx);
|
|
125
|
+
},
|
|
126
|
+
onStatus(ctx) => {
|
|
127
|
+
// add your own code here
|
|
128
|
+
console.log(ctx);
|
|
129
|
+
},
|
|
130
|
+
onError(ctx) => {
|
|
131
|
+
// add your own code here
|
|
132
|
+
console.log(ctx);
|
|
133
|
+
},
|
|
134
|
+
onMempool(tx) => {
|
|
135
|
+
// add your own code here
|
|
136
|
+
console.log(tx);
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
// For lite mode (transaction hash and block height only)
|
|
141
|
+
await client.Subscribe("a5e2fa655c41753331539a2a86546bf9335ff6d9b7a512dc9acddb00ab9985c0", 1550000, onPublish, onStatus, onError, onMempool, true);
|
|
142
|
+
\`\`\`
|
|
143
|
+
|
|
144
|
+
### Go Client
|
|
145
|
+
|
|
146
|
+
Installation:
|
|
147
|
+
\`\`\`bash
|
|
148
|
+
go get github.com/GorillaPool/go-junglebus
|
|
149
|
+
\`\`\`
|
|
150
|
+
|
|
151
|
+
Usage:
|
|
152
|
+
\`\`\`go
|
|
153
|
+
package main
|
|
154
|
+
|
|
155
|
+
import (
|
|
156
|
+
"context"
|
|
157
|
+
"log"
|
|
158
|
+
"sync"
|
|
159
|
+
"github.com/GorillaPool/go-junglebus"
|
|
160
|
+
"github.com/GorillaPool/go-junglebus/models"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
func main() {
|
|
164
|
+
wg := &sync.WaitGroup{}
|
|
165
|
+
|
|
166
|
+
junglebusClient, err := junglebus.New(
|
|
167
|
+
junglebus.WithHTTP("https://junglebus.gorillapool.io"),
|
|
168
|
+
)
|
|
169
|
+
if err != nil {
|
|
170
|
+
log.Fatalln(err.Error())
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
subscriptionID := "..." // fill in the ID for the subscription
|
|
174
|
+
fromBlock := uint64(750000)
|
|
175
|
+
|
|
176
|
+
eventHandler := junglebus.EventHandler{
|
|
177
|
+
// do not set this function to leave out mined transactions
|
|
178
|
+
OnTransaction: func(tx *models.TransactionResponse) {
|
|
179
|
+
log.Printf("[TX]: %d: %v", tx.BlockHeight, tx.Id)
|
|
180
|
+
},
|
|
181
|
+
// do not set this function to leave out mempool transactions
|
|
182
|
+
OnMempool: func(tx *models.TransactionResponse) {
|
|
183
|
+
log.Printf("[MEMPOOL TX]: %v", tx.Id)
|
|
184
|
+
},
|
|
185
|
+
OnStatus: func(status *models.ControlResponse) {
|
|
186
|
+
log.Printf("[STATUS]: %v", status)
|
|
187
|
+
},
|
|
188
|
+
OnError: func(err error) {
|
|
189
|
+
log.Printf("[ERROR]: %v", err)
|
|
190
|
+
},
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
var subscription *junglebus.Subscription
|
|
194
|
+
if subscription, err = junglebusClient.Subscribe(context.Background(), subscriptionID, fromBlock, eventHandler); err != nil {
|
|
195
|
+
log.Printf("ERROR: failed getting subscription %s", err.Error())
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// For lite mode
|
|
199
|
+
if subscription, err := junglebusClient.SubscribeWithQueue(context.Background(), subscriptionID, fromBlock, 0, eventHandler, &junglebus.SubscribeOptions{
|
|
200
|
+
QueueSize: 100000,
|
|
201
|
+
LiteMode: true,
|
|
202
|
+
}); err != nil {
|
|
203
|
+
log.Printf("ERROR: failed getting subscription %s", err.Error())
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
wg.Add(1)
|
|
207
|
+
wg.Wait()
|
|
208
|
+
}
|
|
209
|
+
\`\`\`
|
|
210
|
+
|
|
211
|
+
## Further Reading
|
|
212
|
+
|
|
213
|
+
For complete API documentation, visit [JungleBus Docs](${JUNGLEBUS_DOCS_URL})
|
|
214
|
+
`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Register the JungleBus API documentation resource with the MCP server
|
|
219
|
+
* @param server The MCP server instance
|
|
220
|
+
*/
|
|
221
|
+
export function registerJungleBusResource(server: McpServer): void {
|
|
222
|
+
server.resource(
|
|
223
|
+
"junglebus-api-docs",
|
|
224
|
+
JUNGLEBUS_DOCS_URL,
|
|
225
|
+
{
|
|
226
|
+
title: "JungleBus API Documentation",
|
|
227
|
+
description:
|
|
228
|
+
"API documentation for JungleBus, a transaction monitoring service for Bitcoin SV",
|
|
229
|
+
},
|
|
230
|
+
async (uri) => {
|
|
231
|
+
const documentationContent = getJungleBusDocumentation();
|
|
232
|
+
return {
|
|
233
|
+
contents: [
|
|
234
|
+
{
|
|
235
|
+
uri: uri.href,
|
|
236
|
+
text: documentationContent,
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
};
|
|
240
|
+
},
|
|
241
|
+
);
|
|
242
|
+
}
|
package/resources/resources.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { registerBRCsResources } from "./brcs";
|
|
3
3
|
import { registerChangelogResource } from "./changelog";
|
|
4
|
+
import { registerJungleBusResource } from "./junglebus";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Register all resources with the MCP server
|
|
@@ -13,5 +14,8 @@ export function registerResources(server: McpServer): void {
|
|
|
13
14
|
// Register changelog resource
|
|
14
15
|
registerChangelogResource(server);
|
|
15
16
|
|
|
17
|
+
// Register JungleBus API documentation resource
|
|
18
|
+
registerJungleBusResource(server);
|
|
19
|
+
|
|
16
20
|
// Add more resource categories here as needed
|
|
17
21
|
}
|
package/tools/a2b/discover.ts
CHANGED
|
@@ -6,25 +6,34 @@ import type {
|
|
|
6
6
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
// API endpoint for the A2B Overlay service
|
|
10
|
+
const OVERLAY_API_URL = "https://a2b-overlay-production.up.railway.app/v1";
|
|
11
|
+
|
|
12
|
+
type A2BDiscoveryItem = {
|
|
13
|
+
txid: string;
|
|
14
|
+
outpoint: string;
|
|
10
15
|
type: "agent" | "tool";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
app: string;
|
|
17
|
+
serverName: string;
|
|
18
|
+
command: string;
|
|
19
|
+
description: string;
|
|
20
|
+
keywords: string[];
|
|
21
|
+
args: Record<string, string>;
|
|
22
|
+
env: Record<string, string>;
|
|
23
|
+
blockHeight: number;
|
|
24
|
+
timestamp: string;
|
|
25
|
+
tools?: string[];
|
|
26
|
+
prompts?: string[];
|
|
27
|
+
resources?: string[];
|
|
16
28
|
};
|
|
17
29
|
|
|
18
|
-
type
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
name: string;
|
|
26
|
-
description: string;
|
|
27
|
-
}[];
|
|
30
|
+
type OverlaySearchResponse = {
|
|
31
|
+
items: A2BDiscoveryItem[];
|
|
32
|
+
total: number;
|
|
33
|
+
limit: number;
|
|
34
|
+
offset: number;
|
|
35
|
+
queryType: "agent" | "tool" | "all";
|
|
36
|
+
query: string;
|
|
28
37
|
};
|
|
29
38
|
|
|
30
39
|
// Schema for agent discovery parameters
|
|
@@ -38,6 +47,73 @@ export const a2bDiscoverArgsSchema = z.object({
|
|
|
38
47
|
});
|
|
39
48
|
export type A2bDiscoverArgs = z.infer<typeof a2bDiscoverArgsSchema>;
|
|
40
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Format the response in a user-friendly way
|
|
52
|
+
*/
|
|
53
|
+
function formatSearchResults(data: unknown, queryType: string): string {
|
|
54
|
+
// console.log(`Received data: ${JSON.stringify(data).substring(0, 200)}...`); // Debug log
|
|
55
|
+
|
|
56
|
+
// Check if data is an object with items property
|
|
57
|
+
if (!data) {
|
|
58
|
+
return `No ${queryType} results found.`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Handle the new API format where data is an object with 'items' array
|
|
62
|
+
const items = Array.isArray(data)
|
|
63
|
+
? data
|
|
64
|
+
: (data as { items?: A2BDiscoveryItem[] }).items;
|
|
65
|
+
|
|
66
|
+
// Ensure items is an array
|
|
67
|
+
if (!items || !Array.isArray(items) || items.length === 0) {
|
|
68
|
+
return `No ${queryType} results found.`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let result = `Found ${items.length} ${queryType === "all" ? "items" : `${queryType}s`}:\n\n`;
|
|
72
|
+
|
|
73
|
+
items.forEach((item, index) => {
|
|
74
|
+
if (!item) return;
|
|
75
|
+
|
|
76
|
+
// Agent or MCP server name with description
|
|
77
|
+
result += `${index + 1}. **${item.serverName || "Unknown"}** - ${item.description || "No description"}\n`;
|
|
78
|
+
|
|
79
|
+
// Display command to run
|
|
80
|
+
if (item.command) {
|
|
81
|
+
const args = item.args ? Object.values(item.args).join(" ") : "";
|
|
82
|
+
result += ` Command: \`${item.command} ${args}\`\n`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Add tools count if available
|
|
86
|
+
if (item.tools && Array.isArray(item.tools)) {
|
|
87
|
+
result += ` Tools: ${item.tools.length} available\n`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Add keywords if available
|
|
91
|
+
if (
|
|
92
|
+
item.keywords &&
|
|
93
|
+
Array.isArray(item.keywords) &&
|
|
94
|
+
item.keywords.length > 0
|
|
95
|
+
) {
|
|
96
|
+
result += ` Keywords: ${item.keywords.join(", ")}\n`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Add blockchain details
|
|
100
|
+
if (item.outpoint) {
|
|
101
|
+
result += ` Outpoint: ${item.outpoint}\n`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (item.blockHeight !== undefined) {
|
|
105
|
+
const date = item.timestamp
|
|
106
|
+
? new Date(item.timestamp).toLocaleDateString()
|
|
107
|
+
: "Unknown date";
|
|
108
|
+
result += ` Block: ${item.blockHeight}, ${date}\n`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
result += "\n";
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
|
|
41
117
|
/**
|
|
42
118
|
* Registers the a2b_discover tool for on-chain agent discovery
|
|
43
119
|
*/
|
|
@@ -50,49 +126,113 @@ export function registerA2bDiscoverTool(server: McpServer) {
|
|
|
50
126
|
{ args }: { args: A2bDiscoverArgs },
|
|
51
127
|
extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
|
|
52
128
|
) => {
|
|
53
|
-
if (args.queryType === "agent") {
|
|
54
|
-
return {
|
|
55
|
-
content: [
|
|
56
|
-
{ type: "text", text: "Agent discovery is not supported yet" },
|
|
57
|
-
],
|
|
58
|
-
isError: true,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (args.queryType !== "tool") {
|
|
63
|
-
return {
|
|
64
|
-
content: [
|
|
65
|
-
{
|
|
66
|
-
type: "text",
|
|
67
|
-
text: "Only tool discovery is supported currently",
|
|
68
|
-
},
|
|
69
|
-
],
|
|
70
|
-
isError: true,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
129
|
try {
|
|
75
130
|
const params = new URLSearchParams();
|
|
131
|
+
|
|
132
|
+
// Set query type (agent, tool, or all)
|
|
76
133
|
params.set("type", args.queryType);
|
|
77
|
-
|
|
78
|
-
|
|
134
|
+
|
|
135
|
+
// Use enhanced search for better relevance scoring
|
|
136
|
+
let searchEndpoint = "/search/enhanced";
|
|
137
|
+
|
|
138
|
+
// For empty queries, use the regular search endpoint
|
|
139
|
+
if (!args.query || !args.query.trim()) {
|
|
140
|
+
searchEndpoint = "/search";
|
|
141
|
+
} else {
|
|
142
|
+
params.set("q", args.query); // enhanced search uses 'q' parameter
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Add pagination parameters
|
|
146
|
+
params.set("limit", args.limit?.toString() ?? "10");
|
|
79
147
|
params.set("offset", args.offset?.toString() ?? "0");
|
|
148
|
+
|
|
149
|
+
// Add block range if specified
|
|
80
150
|
if (args.fromBlock) {
|
|
81
151
|
params.set("fromBlock", args.fromBlock.toString());
|
|
82
152
|
}
|
|
83
153
|
if (args.toBlock) {
|
|
84
154
|
params.set("toBlock", args.toBlock.toString());
|
|
85
155
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
156
|
+
|
|
157
|
+
// Construct the full URL
|
|
158
|
+
const searchUrl = `${OVERLAY_API_URL}${searchEndpoint}?${params.toString()}`;
|
|
159
|
+
//console.log(`Searching URL: ${searchUrl}`);
|
|
160
|
+
|
|
161
|
+
// Make the request to the overlay API
|
|
162
|
+
const response = await fetch(searchUrl, {
|
|
163
|
+
method: "GET",
|
|
164
|
+
headers: {
|
|
165
|
+
Accept: "application/json",
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (!response.ok) {
|
|
170
|
+
throw new Error(
|
|
171
|
+
`API returned status ${response.status}: ${response.statusText}`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const data = (await response.json()) as OverlaySearchResponse;
|
|
176
|
+
|
|
177
|
+
// Format the results for better readability
|
|
178
|
+
let result = "";
|
|
179
|
+
|
|
180
|
+
if (data?.items?.length > 0) {
|
|
181
|
+
result = `Found ${data.items.length} ${args.queryType}(s):\n\n`;
|
|
182
|
+
|
|
183
|
+
data.items.forEach((item: A2BDiscoveryItem, index: number) => {
|
|
184
|
+
// Server name and description
|
|
185
|
+
result += `${index + 1}. **${item.serverName || "Unknown"}** - ${item.description || "No description"}\n`;
|
|
186
|
+
|
|
187
|
+
// Command to run
|
|
188
|
+
if (item.command) {
|
|
189
|
+
const cmdArgs = item.args
|
|
190
|
+
? Object.values(item.args).join(" ")
|
|
191
|
+
: "";
|
|
192
|
+
result += ` Command: \`${item.command} ${cmdArgs}\`\n`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Tools available
|
|
196
|
+
if (item.tools?.length) {
|
|
197
|
+
result += ` Tools: ${item.tools.length} available\n`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Keywords
|
|
201
|
+
if (item.keywords?.length) {
|
|
202
|
+
result += ` Keywords: ${item.keywords.join(", ")}\n`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Blockchain details
|
|
206
|
+
if (item.outpoint) {
|
|
207
|
+
result += ` Outpoint: ${item.outpoint}\n`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (item.blockHeight !== undefined) {
|
|
211
|
+
const date = item.timestamp
|
|
212
|
+
? new Date(item.timestamp).toLocaleDateString()
|
|
213
|
+
: "Unknown date";
|
|
214
|
+
result += ` Block: ${item.blockHeight}, ${date}\n`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
result += "\n";
|
|
218
|
+
});
|
|
219
|
+
} else {
|
|
220
|
+
result = `No ${args.queryType} results found.`;
|
|
221
|
+
}
|
|
222
|
+
|
|
89
223
|
return {
|
|
90
|
-
content: [{ type: "text", text:
|
|
224
|
+
content: [{ type: "text", text: result }],
|
|
91
225
|
isError: false,
|
|
92
226
|
};
|
|
93
227
|
} catch (error) {
|
|
228
|
+
console.error("Search error:", error);
|
|
94
229
|
return {
|
|
95
|
-
content: [
|
|
230
|
+
content: [
|
|
231
|
+
{
|
|
232
|
+
type: "text",
|
|
233
|
+
text: `Error querying A2B Overlay: ${error instanceof Error ? error.message : String(error)}`,
|
|
234
|
+
},
|
|
235
|
+
],
|
|
96
236
|
isError: true,
|
|
97
237
|
};
|
|
98
238
|
}
|
package/tools/index.ts
CHANGED
|
@@ -32,14 +32,14 @@ export function registerAllTools(
|
|
|
32
32
|
enableBsvTools: true,
|
|
33
33
|
enableOrdinalsTools: true,
|
|
34
34
|
enableUtilsTools: true,
|
|
35
|
-
enableA2bTools:
|
|
35
|
+
enableA2bTools: false,
|
|
36
36
|
},
|
|
37
37
|
): void {
|
|
38
38
|
const {
|
|
39
39
|
enableBsvTools = true,
|
|
40
40
|
enableOrdinalsTools = true,
|
|
41
41
|
enableUtilsTools = true,
|
|
42
|
-
enableA2bTools =
|
|
42
|
+
enableA2bTools = false,
|
|
43
43
|
} = config;
|
|
44
44
|
|
|
45
45
|
// Register BSV-related tools
|