@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.
@@ -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
@@ -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., 'SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx-v2').
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: "BTC / sBTC rewards per PoX cycle",
19
- summary: "Lock STX to support Stacks consensus and earn Bitcoin rewards. Dual Stacking routes the yield as sBTC.",
20
- start_with: ["get_stacking_status", "stack_stx", "dual_stacking_enroll"],
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 { ALL_ENDPOINTS, searchEndpoints, formatEndpointsTable, getEndpointsBySource, getCategories, } from "../endpoints/registry.js";
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 known x402 API endpoints from ${ALL_SOURCES}.
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, OpenRouter integration, Stacks utilities, hashing, storage
142
- - stx402.com: AI services, cryptography, storage, utilities, agent registry
143
- - aibtc.com: Inbox messaging system`,
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 (use without value to see available categories)"),
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
- let endpoints = ALL_ENDPOINTS;
170
- if (source && source !== "all") {
171
- endpoints = getEndpointsBySource(source);
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
- endpoints = endpoints.filter((ep) => ep.category.toLowerCase() === category.toLowerCase());
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 searchResults = searchEndpoints(search);
184
- endpoints = endpoints.filter((ep) => searchResults.includes(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
- if (endpoints.length === 0) {
187
- const categories = getCategories();
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
- Available categories: ${categories.join(", ")}
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 formatted = formatEndpointsTable(endpoints);
204
- const sourceInfo = source === "all"
205
- ? `Sources: ${ALL_SOURCES}`
206
- : `Source: ${source}`;
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${sourceInfo}\nDefault API: ${API_URL}\n${formatted}\n\n---\nUse execute_x402_endpoint to call any of these endpoints.`,
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 "/ai/dad-joke"
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://stx402.com/ai/dad-joke'). Takes precedence over path+apiUrl."),
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 "/ai/dad-joke"
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://stx402.com/ai/dad-joke'). Takes precedence over path+apiUrl."),
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()
@@ -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 (signal feed, leaderboard, file signals)
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 Tools
2
+ * AIBTC News tools — deprecated.
3
3
  *
4
- * Tools for interacting with the aibtc.news decentralized intelligence network.
5
- * Agents can read signal feeds, check correspondent standings, and file signals
6
- * authenticated via BIP-322 signatures (bc1q P2WPKH addresses only).
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;