@aibtc/mcp-server 1.70.0 → 1.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -10
- package/dist/bridge/index.js +2 -2
- package/dist/config/contracts.d.ts +8 -8
- package/dist/config/contracts.js +3 -3
- package/dist/endpoints/registry.d.ts +8 -26
- package/dist/endpoints/registry.js +7 -932
- package/dist/services/stacking.service.d.ts +144 -45
- package/dist/services/stacking.service.js +416 -123
- package/dist/services/x402-discovery.service.d.ts +81 -0
- package/dist/services/x402-discovery.service.js +170 -0
- package/dist/tools/defi.tools.js +1 -1
- package/dist/tools/earning.tools.js +3 -3
- package/dist/tools/endpoint.tools.js +85 -38
- package/dist/tools/index.js +7 -1
- package/dist/tools/news.tools.d.ts +5 -31
- package/dist/tools/news.tools.js +96 -1389
- package/dist/tools/pillar-direct.tools.js +23 -2
- package/dist/tools/sbtc.tools.js +2 -21
- package/dist/tools/skill-mappings.js +4 -7
- package/dist/tools/stacking.tools.js +352 -44
- package/dist/tools/yield-dashboard.tools.js +13 -22
- package/dist/utils/bip322.d.ts +2 -3
- package/dist/utils/bip322.js +2 -3
- package/dist/utils/bitcoin.d.ts +8 -0
- package/dist/utils/bitcoin.js +24 -0
- package/dist/utils/erc8004-helpers.d.ts +1 -1
- package/dist/utils/erc8004-helpers.js +1 -1
- package/package.json +6 -6
- package/skill/SKILL.md +3 -3
- package/skill/references/genesis-lifecycle.md +17 -32
- package/skill/references/pillar-wallet.md +1 -1
- package/skill/references/stacks-defi.md +1 -1
- package/dist/tools/erc8004.tools.d.ts +0 -21
- package/dist/tools/erc8004.tools.js +0 -329
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live x402 endpoint discovery.
|
|
3
|
+
*
|
|
4
|
+
* x402.aibtc.com and stx402.com publish an OpenAPI spec, and stx402.com runs a
|
|
5
|
+
* directory of x402 endpoints registered by third parties. Reading those at call
|
|
6
|
+
* time keeps `list_x402_endpoints` in step with what the hosts actually serve,
|
|
7
|
+
* instead of a hand-maintained list that goes stale when routes move.
|
|
8
|
+
*
|
|
9
|
+
* Results are cached briefly. A failed fetch is never cached and never replaced
|
|
10
|
+
* with stale or invented entries: the source is reported as unavailable.
|
|
11
|
+
*/
|
|
12
|
+
import { NETWORK } from "../config/networks.js";
|
|
13
|
+
export const OPENAPI_SOURCES = [
|
|
14
|
+
{
|
|
15
|
+
source: "x402.aibtc.com",
|
|
16
|
+
baseUrl: { mainnet: "https://x402.aibtc.com", testnet: "https://x402.aibtc.dev" },
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
source: "stx402.com",
|
|
20
|
+
baseUrl: { mainnet: "https://stx402.com" },
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
const DIRECTORY_URL = "https://stx402.com/registry/list";
|
|
24
|
+
const DIRECTORY_PAGE_SIZE = 50;
|
|
25
|
+
/** Hard stop so a misbehaving `total` cannot turn one call into hundreds of requests. */
|
|
26
|
+
const DIRECTORY_MAX_PAGES = 20;
|
|
27
|
+
export const DISCOVERY_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
28
|
+
const FETCH_TIMEOUT_MS = 10_000;
|
|
29
|
+
const cache = new Map();
|
|
30
|
+
async function cached(key, load) {
|
|
31
|
+
const hit = cache.get(key);
|
|
32
|
+
if (hit && Date.now() - hit.at < DISCOVERY_CACHE_TTL_MS) {
|
|
33
|
+
return hit.value;
|
|
34
|
+
}
|
|
35
|
+
const value = await load();
|
|
36
|
+
cache.set(key, { at: Date.now(), value });
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
/** Test seam. */
|
|
40
|
+
export function clearDiscoveryCache() {
|
|
41
|
+
cache.clear();
|
|
42
|
+
}
|
|
43
|
+
async function fetchJson(url) {
|
|
44
|
+
const response = await fetch(url, {
|
|
45
|
+
headers: { Accept: "application/json" },
|
|
46
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new Error(`GET ${url} returned HTTP ${response.status}`);
|
|
50
|
+
}
|
|
51
|
+
return response.json();
|
|
52
|
+
}
|
|
53
|
+
const METHODS = ["get", "post", "put", "delete"];
|
|
54
|
+
/**
|
|
55
|
+
* Summaries on these hosts lead with the pricing tier, e.g. "(paid, standard) Decode a
|
|
56
|
+
* transaction" or "(free) List models". Split that into a cost label and a description.
|
|
57
|
+
* The exact price is only known from the 402 challenge, so it is not guessed here.
|
|
58
|
+
*/
|
|
59
|
+
export function parseSummary(summary) {
|
|
60
|
+
const match = summary.match(/^\((free|paid)(?:,\s*([^)]+))?\)\s*(.*)$/i);
|
|
61
|
+
if (match) {
|
|
62
|
+
const [, kind, tier, rest] = match;
|
|
63
|
+
return {
|
|
64
|
+
cost: kind.toLowerCase() === "free" ? "FREE" : `paid${tier ? ` (${tier.trim()})` : ""}`,
|
|
65
|
+
description: rest,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (/\(free\)/i.test(summary)) {
|
|
69
|
+
return { cost: "FREE", description: summary.replace(/\s*\(free\)/i, "") };
|
|
70
|
+
}
|
|
71
|
+
return { cost: "see probe_x402_endpoint", description: summary };
|
|
72
|
+
}
|
|
73
|
+
/** Map an OpenAPI spec to endpoint entries. Admin-only operations are left out. */
|
|
74
|
+
export function endpointsFromOpenApi(spec, source) {
|
|
75
|
+
const endpoints = [];
|
|
76
|
+
for (const [path, operations] of Object.entries(spec.paths ?? {})) {
|
|
77
|
+
for (const method of METHODS) {
|
|
78
|
+
const op = operations[method];
|
|
79
|
+
if (!op)
|
|
80
|
+
continue;
|
|
81
|
+
const tags = op.tags ?? [];
|
|
82
|
+
if (tags.some((tag) => /admin/i.test(tag)))
|
|
83
|
+
continue;
|
|
84
|
+
const { cost, description } = parseSummary(op.summary ?? op.description ?? "");
|
|
85
|
+
// tokenType selects the payment asset; execute_x402_endpoint handles that itself.
|
|
86
|
+
const params = Object.fromEntries((op.parameters ?? [])
|
|
87
|
+
.filter((p) => p.name !== "tokenType")
|
|
88
|
+
.map((p) => [p.name, p.description ?? p.in]));
|
|
89
|
+
const schema = op.requestBody?.content?.["application/json"]?.schema;
|
|
90
|
+
const required = new Set(schema?.required ?? []);
|
|
91
|
+
const body = Object.fromEntries(Object.entries(schema?.properties ?? {}).map(([name, prop]) => [
|
|
92
|
+
name,
|
|
93
|
+
`${prop.description ?? name}${required.has(name) ? "" : " (optional)"}`,
|
|
94
|
+
]));
|
|
95
|
+
endpoints.push({
|
|
96
|
+
path,
|
|
97
|
+
method: method.toUpperCase(),
|
|
98
|
+
description,
|
|
99
|
+
cost,
|
|
100
|
+
category: tags[0] ?? "Other",
|
|
101
|
+
source,
|
|
102
|
+
...(Object.keys(params).length > 0 && { params }),
|
|
103
|
+
...(Object.keys(body).length > 0 && { body }),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return endpoints;
|
|
108
|
+
}
|
|
109
|
+
/** Fetch one host's endpoints from its OpenAPI spec. */
|
|
110
|
+
export function fetchOpenApiEndpoints(source, network = NETWORK) {
|
|
111
|
+
const baseUrl = source.baseUrl[network];
|
|
112
|
+
if (!baseUrl) {
|
|
113
|
+
return Promise.reject(new Error(`${source.source} has no ${network} deployment`));
|
|
114
|
+
}
|
|
115
|
+
return cached(`openapi:${baseUrl}`, async () => {
|
|
116
|
+
const spec = (await fetchJson(`${baseUrl}/openapi.json`));
|
|
117
|
+
if (!spec.paths) {
|
|
118
|
+
throw new Error(`${baseUrl}/openapi.json has no paths`);
|
|
119
|
+
}
|
|
120
|
+
return endpointsFromOpenApi(spec, source.source);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/** Fetch every entry in the stx402.com endpoint directory (mainnet only). */
|
|
124
|
+
export function fetchDirectoryEntries() {
|
|
125
|
+
return cached("directory", async () => {
|
|
126
|
+
const entries = [];
|
|
127
|
+
let total = Infinity;
|
|
128
|
+
for (let page = 0; page < DIRECTORY_MAX_PAGES && entries.length < total; page++) {
|
|
129
|
+
const offset = page * DIRECTORY_PAGE_SIZE;
|
|
130
|
+
const data = (await fetchJson(`${DIRECTORY_URL}?limit=${DIRECTORY_PAGE_SIZE}&offset=${offset}`));
|
|
131
|
+
if (!Array.isArray(data.entries)) {
|
|
132
|
+
throw new Error(`${DIRECTORY_URL} response has no entries array`);
|
|
133
|
+
}
|
|
134
|
+
total = data.total ?? entries.length + data.entries.length;
|
|
135
|
+
for (const e of data.entries) {
|
|
136
|
+
if (!e.url)
|
|
137
|
+
continue;
|
|
138
|
+
entries.push({
|
|
139
|
+
name: e.name ?? e.url,
|
|
140
|
+
url: e.url,
|
|
141
|
+
category: e.category ?? "other",
|
|
142
|
+
status: e.status ?? "unknown",
|
|
143
|
+
owner: e.owner ?? "",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if (data.entries.length < DIRECTORY_PAGE_SIZE)
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
return entries;
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function errorMessage(error) {
|
|
153
|
+
return error instanceof Error ? error.message : String(error);
|
|
154
|
+
}
|
|
155
|
+
/** Fetch every OpenAPI source in parallel, reporting failures per source. */
|
|
156
|
+
export async function discoverOpenApiEndpoints(sources = OPENAPI_SOURCES, network = NETWORK) {
|
|
157
|
+
const results = await Promise.allSettled(sources.map((s) => fetchOpenApiEndpoints(s, network)));
|
|
158
|
+
const endpoints = [];
|
|
159
|
+
const unavailable = [];
|
|
160
|
+
results.forEach((result, i) => {
|
|
161
|
+
if (result.status === "fulfilled") {
|
|
162
|
+
endpoints.push(...result.value);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
unavailable.push({ source: sources[i].source, error: errorMessage(result.reason) });
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
return { endpoints, unavailable };
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=x402-discovery.service.js.map
|
package/dist/tools/defi.tools.js
CHANGED
|
@@ -12,7 +12,7 @@ export function registerDefiTools(server) {
|
|
|
12
12
|
description: `Get a swap quote from ALEX DEX.
|
|
13
13
|
|
|
14
14
|
Returns the expected output amount for swapping tokenX to tokenY.
|
|
15
|
-
Use full contract IDs for tokens (e.g., '
|
|
15
|
+
Use full contract IDs for tokens (e.g., 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wstx-v2').
|
|
16
16
|
|
|
17
17
|
Note: ALEX DEX is only available on mainnet.`,
|
|
18
18
|
inputSchema: {
|
|
@@ -15,9 +15,9 @@ export const EARNING_STRATEGIES = [
|
|
|
15
15
|
id: "stacking",
|
|
16
16
|
name: "Bitcoin Stacking (PoX)",
|
|
17
17
|
assets: ["STX"],
|
|
18
|
-
returns: "
|
|
19
|
-
summary: "Lock STX to support Stacks consensus and earn
|
|
20
|
-
start_with: ["
|
|
18
|
+
returns: "sBTC rewards per PoX cycle",
|
|
19
|
+
summary: "Lock STX with a PoX-5 signer manager to support Stacks consensus and earn sBTC rewards (or BTC via the manager's payout address). Dual Stacking routes the yield as sBTC.",
|
|
20
|
+
start_with: ["list_stacking_signers", "stack_stx", "get_stacking_status", "dual_stacking_enroll"],
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
id: "defi_yield",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { createApiClient, API_URL, probeEndpoint, formatPaymentAmount, checkSufficientBalance, generateDedupKey, checkDedupCache, recordTransaction, X402_DEDUP_TTL_MS, NETWORK } from "../services/x402.service.js";
|
|
3
|
-
import {
|
|
3
|
+
import { STATIC_ENDPOINTS, formatEndpointsTable } from "../endpoints/registry.js";
|
|
4
|
+
import { discoverOpenApiEndpoints, fetchDirectoryEntries, } from "../services/x402-discovery.service.js";
|
|
4
5
|
import { createJsonResponse, createErrorResponse } from "../utils/index.js";
|
|
5
|
-
import { X402_HEADERS } from "../utils/x402-protocol.js";
|
|
6
|
+
import { X402_HEADERS, decodePaymentResponse } from "../utils/x402-protocol.js";
|
|
6
7
|
import { extractPaymentIdFromPaymentSignature, extractTxidFromPaymentSignature, pollTransactionConfirmation, } from "../utils/x402-recovery.js";
|
|
7
8
|
import { formatCanonicalPaymentStatus } from "../utils/x402-payment-state.js";
|
|
8
9
|
import { emitPaymentLog } from "../utils/x402-payment-logging.js";
|
|
9
|
-
const ALL_SOURCES = "x402.biwas.xyz, x402.aibtc.com, stx402.com, aibtc.com";
|
|
10
10
|
/**
|
|
11
11
|
* Parse and validate endpoint URL from either a full URL or path+apiUrl combination.
|
|
12
12
|
* Merges any query parameters from the URL into the provided params.
|
|
@@ -130,27 +130,26 @@ function formatProbeResponse(result, method, fullUrl, callWithOptions, messagePr
|
|
|
130
130
|
export function registerEndpointTools(server) {
|
|
131
131
|
// List x402 endpoints
|
|
132
132
|
server.registerTool("list_x402_endpoints", {
|
|
133
|
-
description: `List
|
|
134
|
-
|
|
135
|
-
The agent can:
|
|
136
|
-
1. Execute x402 endpoints from these sources (paid API calls with automatic payment handling)
|
|
137
|
-
2. Execute direct Stacks transactions (transfer STX, call contracts, deploy contracts)
|
|
133
|
+
description: `List x402 API endpoints. x402.aibtc.com and stx402.com are read live from their OpenAPI specs; the stx402.com directory lists x402 endpoints registered by third parties.
|
|
138
134
|
|
|
139
135
|
Sources:
|
|
140
136
|
- x402.biwas.xyz: DeFi analytics, market data, wallet analysis, Zest/ALEX protocols
|
|
141
|
-
- x402.aibtc.com: AI inference,
|
|
142
|
-
- stx402.com:
|
|
143
|
-
- aibtc.com: Inbox messaging
|
|
137
|
+
- x402.aibtc.com: AI inference, Stacks utilities, hashing, storage (live)
|
|
138
|
+
- stx402.com: x402 endpoint registry, agent registry (ERC-8004), links (live)
|
|
139
|
+
- aibtc.com: Inbox messaging
|
|
140
|
+
- directory: third-party endpoints registered at stx402.com (live, mainnet). Unverified entries are hidden unless includeUnverified is true — probe before paying.
|
|
141
|
+
|
|
142
|
+
Costs from live specs are tiers ("paid (standard)", "paid (dynamic)"); use probe_x402_endpoint for the exact price.`,
|
|
144
143
|
inputSchema: {
|
|
145
144
|
source: z
|
|
146
|
-
.enum(["x402.biwas.xyz", "x402.aibtc.com", "stx402.com", "aibtc.com", "all"])
|
|
145
|
+
.enum(["x402.biwas.xyz", "x402.aibtc.com", "stx402.com", "aibtc.com", "directory", "all"])
|
|
147
146
|
.optional()
|
|
148
147
|
.default("all")
|
|
149
148
|
.describe("Filter by API source"),
|
|
150
149
|
category: z
|
|
151
150
|
.string()
|
|
152
151
|
.optional()
|
|
153
|
-
.describe("Filter by category (
|
|
152
|
+
.describe("Filter by category (case-insensitive)"),
|
|
154
153
|
search: z
|
|
155
154
|
.string()
|
|
156
155
|
.optional()
|
|
@@ -163,12 +162,42 @@ Sources:
|
|
|
163
162
|
.boolean()
|
|
164
163
|
.optional()
|
|
165
164
|
.describe("Only show paid endpoints (require x402 payment)"),
|
|
165
|
+
includeUnverified: z
|
|
166
|
+
.boolean()
|
|
167
|
+
.optional()
|
|
168
|
+
.default(false)
|
|
169
|
+
.describe("Include unverified third-party entries from the stx402.com directory"),
|
|
166
170
|
},
|
|
167
|
-
}, async ({ source, category, search, showFreeOnly, showPaidOnly }) => {
|
|
171
|
+
}, async ({ source, category, search, showFreeOnly, showPaidOnly, includeUnverified }) => {
|
|
168
172
|
try {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
173
|
+
const wanted = source ?? "all";
|
|
174
|
+
const unavailable = [];
|
|
175
|
+
let endpoints = STATIC_ENDPOINTS.filter((ep) => wanted === "all" || ep.source === wanted);
|
|
176
|
+
if (wanted === "all" || wanted === "x402.aibtc.com" || wanted === "stx402.com") {
|
|
177
|
+
const live = await discoverOpenApiEndpoints();
|
|
178
|
+
endpoints.push(...live.endpoints.filter((ep) => wanted === "all" || ep.source === wanted));
|
|
179
|
+
unavailable.push(...live.unavailable.filter((u) => wanted === "all" || u.source === wanted));
|
|
180
|
+
}
|
|
181
|
+
let directory = [];
|
|
182
|
+
// Directory entries carry no method or price, so they only answer
|
|
183
|
+
// unfiltered or keyword/category browsing, not free/paid filters.
|
|
184
|
+
if ((wanted === "all" || wanted === "directory") && !showFreeOnly && !showPaidOnly) {
|
|
185
|
+
if (NETWORK !== "mainnet") {
|
|
186
|
+
if (wanted === "directory") {
|
|
187
|
+
unavailable.push({ source: "directory", error: "the stx402.com directory lists mainnet endpoints only" });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
try {
|
|
192
|
+
directory = (await fetchDirectoryEntries()).filter((e) => includeUnverified || e.status === "verified");
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
unavailable.push({
|
|
196
|
+
source: "directory",
|
|
197
|
+
error: error instanceof Error ? error.message : String(error),
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
172
201
|
}
|
|
173
202
|
if (showFreeOnly) {
|
|
174
203
|
endpoints = endpoints.filter((ep) => ep.cost === "FREE");
|
|
@@ -177,38 +206,51 @@ Sources:
|
|
|
177
206
|
endpoints = endpoints.filter((ep) => ep.cost !== "FREE");
|
|
178
207
|
}
|
|
179
208
|
if (category) {
|
|
180
|
-
|
|
209
|
+
const c = category.toLowerCase();
|
|
210
|
+
endpoints = endpoints.filter((ep) => ep.category.toLowerCase() === c);
|
|
211
|
+
directory = directory.filter((e) => e.category.toLowerCase() === c);
|
|
181
212
|
}
|
|
182
213
|
if (search) {
|
|
183
|
-
const
|
|
184
|
-
endpoints = endpoints.filter((ep) =>
|
|
214
|
+
const q = search.toLowerCase();
|
|
215
|
+
endpoints = endpoints.filter((ep) => ep.path.toLowerCase().includes(q) ||
|
|
216
|
+
ep.description.toLowerCase().includes(q) ||
|
|
217
|
+
ep.category.toLowerCase().includes(q));
|
|
218
|
+
directory = directory.filter((e) => e.name.toLowerCase().includes(q) ||
|
|
219
|
+
e.url.toLowerCase().includes(q) ||
|
|
220
|
+
e.category.toLowerCase().includes(q));
|
|
185
221
|
}
|
|
186
|
-
|
|
187
|
-
|
|
222
|
+
const unavailableText = unavailable.length > 0
|
|
223
|
+
? `\n\n## Unavailable sources\n${unavailable.map((u) => `- ${u.source}: ${u.error}`).join("\n")}`
|
|
224
|
+
: "";
|
|
225
|
+
if (endpoints.length === 0 && directory.length === 0) {
|
|
188
226
|
return {
|
|
189
227
|
content: [
|
|
190
228
|
{
|
|
191
229
|
type: "text",
|
|
192
|
-
text: `No endpoints found matching your criteria
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
Sources: ${ALL_SOURCES}
|
|
197
|
-
|
|
198
|
-
If you're looking to perform a direct blockchain action (transfer STX, call a contract), those are available via separate tools.`,
|
|
230
|
+
text: `No endpoints found matching your criteria (source: ${wanted}).` +
|
|
231
|
+
unavailableText +
|
|
232
|
+
`\n\nIf you're looking to perform a direct blockchain action (transfer STX, call a contract), those are available via separate tools.`,
|
|
199
233
|
},
|
|
200
234
|
],
|
|
201
235
|
};
|
|
202
236
|
}
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
237
|
+
const directoryText = directory.length > 0
|
|
238
|
+
? `\n\n## Directory (stx402.com, third-party)\n` +
|
|
239
|
+
directory
|
|
240
|
+
.map((e) => `- ${e.name} [${e.category}, ${e.status}]\n ${e.url}`)
|
|
241
|
+
.join("\n")
|
|
242
|
+
: "";
|
|
207
243
|
return {
|
|
208
244
|
content: [
|
|
209
245
|
{
|
|
210
246
|
type: "text",
|
|
211
|
-
text: `# Available x402 Endpoints (${endpoints.length} total)\n\n
|
|
247
|
+
text: `# Available x402 Endpoints (${endpoints.length + directory.length} total)\n\n` +
|
|
248
|
+
`Source: ${wanted}\nDefault API: ${API_URL}\n` +
|
|
249
|
+
(endpoints.length > 0 ? `\n${formatEndpointsTable(endpoints)}` : "") +
|
|
250
|
+
directoryText +
|
|
251
|
+
unavailableText +
|
|
252
|
+
`\n\n---\nUse execute_x402_endpoint to call an endpoint (full url for directory entries). ` +
|
|
253
|
+
`Use probe_x402_endpoint first to see the exact price.`,
|
|
212
254
|
},
|
|
213
255
|
],
|
|
214
256
|
};
|
|
@@ -224,7 +266,7 @@ If you're looking to perform a direct blockchain action (transfer STX, call a co
|
|
|
224
266
|
Supported sources:
|
|
225
267
|
- x402.biwas.xyz (default): Use path like "/api/pools/trending"
|
|
226
268
|
- x402.aibtc.com (mainnet) / x402.aibtc.dev (testnet): Use apiUrl="https://x402.aibtc.com" with path like "/inference/openrouter/chat"
|
|
227
|
-
- stx402.com: Use apiUrl="https://stx402.com" with path like "/
|
|
269
|
+
- stx402.com: Use apiUrl="https://stx402.com" with path like "/registry/list"
|
|
228
270
|
- aibtc.com (mainnet) / aibtc.dev (testnet): Use apiUrl="https://aibtc.com" with path like "/api/inbox/{address}"
|
|
229
271
|
- Any x402-compatible URL: Use url parameter with full endpoint URL
|
|
230
272
|
|
|
@@ -240,7 +282,7 @@ For aibtc.com inbox messages, use send_inbox_message_direct instead — it signs
|
|
|
240
282
|
.string()
|
|
241
283
|
.url()
|
|
242
284
|
.optional()
|
|
243
|
-
.describe("Full endpoint URL (e.g., 'https://
|
|
285
|
+
.describe("Full endpoint URL (e.g., 'https://x402.aibtc.com/hashing/sha256'). Takes precedence over path+apiUrl."),
|
|
244
286
|
path: z
|
|
245
287
|
.string()
|
|
246
288
|
.optional()
|
|
@@ -317,8 +359,13 @@ For aibtc.com inbox messages, use send_inbox_message_direct instead — it signs
|
|
|
317
359
|
},
|
|
318
360
|
});
|
|
319
361
|
const response = await api.request({ method, url: parsed.requestPath, params, data });
|
|
362
|
+
const paymentResponseTxid = decodePaymentResponse(response.headers?.[X402_HEADERS.PAYMENT_RESPONSE])?.transaction ||
|
|
363
|
+
undefined;
|
|
364
|
+
const paymentBodyTxid = response.data?.payment?.txid;
|
|
320
365
|
const rawTxid = response.data?.txid ||
|
|
321
366
|
response.data?.payment_txid ||
|
|
367
|
+
paymentResponseTxid ||
|
|
368
|
+
(typeof paymentBodyTxid === "string" ? paymentBodyTxid : undefined) ||
|
|
322
369
|
response.headers?.['x-transaction-id'] ||
|
|
323
370
|
undefined;
|
|
324
371
|
// Detect whether a payment was made by checking for the payment-signature
|
|
@@ -459,7 +506,7 @@ After probing a paid endpoint, use execute_x402_endpoint to actually execute and
|
|
|
459
506
|
Supported sources:
|
|
460
507
|
- x402.biwas.xyz (default): Use path like "/api/pools/trending"
|
|
461
508
|
- x402.aibtc.com (mainnet) / x402.aibtc.dev (testnet): Use apiUrl="https://x402.aibtc.com" with path like "/inference/openrouter/chat"
|
|
462
|
-
- stx402.com: Use apiUrl="https://stx402.com" with path like "/
|
|
509
|
+
- stx402.com: Use apiUrl="https://stx402.com" with path like "/registry/list"
|
|
463
510
|
- aibtc.com (mainnet) / aibtc.dev (testnet): Use apiUrl="https://aibtc.com" with path like "/api/inbox/{address}"
|
|
464
511
|
- Any x402-compatible URL: Use url parameter with full endpoint URL`,
|
|
465
512
|
inputSchema: {
|
|
@@ -471,7 +518,7 @@ Supported sources:
|
|
|
471
518
|
.string()
|
|
472
519
|
.url()
|
|
473
520
|
.optional()
|
|
474
|
-
.describe("Full endpoint URL (e.g., 'https://
|
|
521
|
+
.describe("Full endpoint URL (e.g., 'https://x402.aibtc.com/hashing/sha256'). Takes precedence over path+apiUrl."),
|
|
475
522
|
path: z
|
|
476
523
|
.string()
|
|
477
524
|
.optional()
|
package/dist/tools/index.js
CHANGED
|
@@ -32,6 +32,8 @@ import { registerTeneroTools } from "./tenero.tools.js";
|
|
|
32
32
|
import { registerOrdinalsP2PTools } from "./ordinals-p2p.tools.js";
|
|
33
33
|
import { registerOrdinalsMarketplaceTools } from "./ordinals-marketplace.tools.js";
|
|
34
34
|
import { registerTaprootMultisigTools } from "./taproot-multisig.tools.js";
|
|
35
|
+
import { registerPsbtTools } from "./psbt.tools.js";
|
|
36
|
+
import { registerSettingsTools } from "./settings.tools.js";
|
|
35
37
|
import { registerJingswapTools } from "./jingswap.tools.js";
|
|
36
38
|
import { registerSigningTools } from "./signing.tools.js";
|
|
37
39
|
import { registerInferenceMarketplaceTools } from "./inference-marketplace.tools.js";
|
|
@@ -161,13 +163,17 @@ export function registerAllTools(server) {
|
|
|
161
163
|
registerOrdinalsMarketplaceTools(server);
|
|
162
164
|
// Taproot Multisig (M-of-N coordination via OP_CHECKSIGADD, BIP-341/342)
|
|
163
165
|
registerTaprootMultisigTools(server);
|
|
166
|
+
// PSBT sign/broadcast/decode (used by the ordinals marketplace, P2P and taproot multisig flows)
|
|
167
|
+
registerPsbtTools(server);
|
|
168
|
+
// Settings (Hiro API key, custom Stacks API URL, server version)
|
|
169
|
+
registerSettingsTools(server);
|
|
164
170
|
// Jingswap Auction (blind batch auctions for STX/sBTC)
|
|
165
171
|
registerJingswapTools(server);
|
|
166
172
|
// Message Signing (BTC BIP-322, Stacks SIWS, SIP-018 structured data, Nostr NIP-01)
|
|
167
173
|
registerSigningTools(server);
|
|
168
174
|
// AIBTC Inference Marketplace (list/manage a paid model endpoint via wallet signature)
|
|
169
175
|
registerInferenceMarketplaceTools(server);
|
|
170
|
-
// AIBTC News (
|
|
176
|
+
// AIBTC News (deprecated — API retired; each tool redirects to legion_*)
|
|
171
177
|
registerNewsTools(server);
|
|
172
178
|
// AIBTC News Legion (mainnet aibtc-news-gov — inscribe, propose, vote, conclude)
|
|
173
179
|
registerLegionTools(server);
|
|
@@ -1,36 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AIBTC News
|
|
2
|
+
* AIBTC News tools — deprecated.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Correspondent tools (read-only, no auth required):
|
|
9
|
-
* - news_list_signals — Browse the signal feed with optional filters
|
|
10
|
-
* - news_front_page — Get the latest compiled intelligence brief
|
|
11
|
-
* - news_leaderboard — Ranked correspondents with signal counts and streaks
|
|
12
|
-
* - news_check_status — Signal counts, streak, and earnings for a BTC address
|
|
13
|
-
* - news_list_beats — List all registered beats
|
|
14
|
-
* - news_list_editors — List editors registered on a beat
|
|
15
|
-
*
|
|
16
|
-
* Authenticated tools (require unlocked wallet with bc1q/tb1q address):
|
|
17
|
-
* - news_file_signal — File a signal on a beat (BIP-322 signed)
|
|
18
|
-
* - news_claim_beat — Create or join a beat (BIP-322 signed)
|
|
19
|
-
* - news_editor_review_signal — Approve or reject a signal (editor or publisher)
|
|
20
|
-
* - news_editor_file_review — Submit structured editorial review for a signal
|
|
21
|
-
* - news_editor_check_earnings — Check editor earnings for an address
|
|
22
|
-
* - news_register_editor — Register an editor on a beat (publisher only)
|
|
23
|
-
* - news_deactivate_editor — Deactivate an editor on a beat (publisher only)
|
|
24
|
-
* - news_file_correction — File a correction on a signal
|
|
25
|
-
* - news_publisher_compile_brief — Compile the daily intelligence brief (publisher only)
|
|
26
|
-
* - news_publisher_set_beat_config — Update beat details and config (publisher only)
|
|
27
|
-
* - news_record_editor_payout — Record payout txid for an editor earning (publisher only)
|
|
28
|
-
*
|
|
29
|
-
* Authentication: BIP-322 simple signature (P2WPKH, bc1q mainnet / tb1q testnet).
|
|
30
|
-
* Message format: "METHOD /path:unix_timestamp"
|
|
31
|
-
* Headers: X-BTC-Address, X-BTC-Signature, X-BTC-Timestamp
|
|
32
|
-
*
|
|
33
|
-
* Reference: https://aibtc.news/api (GET /api for full spec)
|
|
4
|
+
* aibtc.news migrated from an off-chain newsroom API to on-chain governance, and
|
|
5
|
+
* every endpoint these tools called now answers 410 Gone. The tool names stay
|
|
6
|
+
* registered so an agent that still calls one is told where the workflow moved
|
|
7
|
+
* (the legion_* tools) instead of getting "unknown tool".
|
|
34
8
|
*/
|
|
35
9
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
36
10
|
export declare function registerNewsTools(server: McpServer): void;
|