@secondlayer/mcp 3.8.0 → 3.10.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 +6 -2
- package/dist/bin-http.js +252 -217
- package/dist/bin-http.js.map +10 -11
- package/dist/bin.js +252 -217
- package/dist/bin.js.map +10 -11
- package/dist/index.js +252 -217
- package/dist/index.js.map +10 -11
- package/package.json +5 -5
package/dist/bin-http.js
CHANGED
|
@@ -18,21 +18,49 @@ import { TRAIT_STANDARDS } from "@secondlayer/stacks/clarity";
|
|
|
18
18
|
import { TYPE_MAP } from "@secondlayer/subgraphs/schema";
|
|
19
19
|
|
|
20
20
|
// src/lib/client.ts
|
|
21
|
-
import { SecondLayer } from "@secondlayer/sdk";
|
|
21
|
+
import { SecondLayer, readX402Receipt, withX402 } from "@secondlayer/sdk";
|
|
22
|
+
import { privateKeyToAccount } from "@secondlayer/stacks/accounts";
|
|
22
23
|
var instance = null;
|
|
23
24
|
function readApiKey() {
|
|
24
25
|
return process.env.SL_API_KEY;
|
|
25
26
|
}
|
|
27
|
+
function buildFetchImpl() {
|
|
28
|
+
const key = process.env.X402_PRIVATE_KEY;
|
|
29
|
+
if (!key)
|
|
30
|
+
return;
|
|
31
|
+
const account = privateKeyToAccount(key);
|
|
32
|
+
const topUpUsd = Number(process.env.X402_TOPUP_USD ?? "");
|
|
33
|
+
const paid = withX402(fetch, {
|
|
34
|
+
account,
|
|
35
|
+
...Number.isFinite(topUpUsd) && topUpUsd > 0 ? {
|
|
36
|
+
topUp: {
|
|
37
|
+
usd: topUpUsd,
|
|
38
|
+
whenBelow: Number(process.env.X402_TOPUP_WHEN_BELOW ?? "0.5")
|
|
39
|
+
}
|
|
40
|
+
} : {}
|
|
41
|
+
});
|
|
42
|
+
const wrapped = async (input, init) => {
|
|
43
|
+
const res = await paid(input, init);
|
|
44
|
+
const receipt = readX402Receipt(res);
|
|
45
|
+
if (receipt) {
|
|
46
|
+
console.error(`[x402] paid call settled tier=${receipt.state ?? "confirmed"} txid=${receipt.txid}`);
|
|
47
|
+
}
|
|
48
|
+
return res;
|
|
49
|
+
};
|
|
50
|
+
return wrapped;
|
|
51
|
+
}
|
|
26
52
|
function getClient() {
|
|
27
53
|
if (!instance) {
|
|
28
54
|
const apiKey = readApiKey();
|
|
29
55
|
const baseUrl = process.env.SECONDLAYER_API_URL;
|
|
30
56
|
const dumpsBaseUrl = process.env.SL_STREAMS_DUMPS_URL;
|
|
57
|
+
const fetchImpl = buildFetchImpl();
|
|
31
58
|
instance = new SecondLayer({
|
|
32
59
|
...apiKey ? { apiKey } : {},
|
|
33
60
|
origin: "mcp",
|
|
34
61
|
...baseUrl ? { baseUrl } : {},
|
|
35
|
-
...dumpsBaseUrl ? { dumpsBaseUrl } : {}
|
|
62
|
+
...dumpsBaseUrl ? { dumpsBaseUrl } : {},
|
|
63
|
+
...fetchImpl ? { fetchImpl } : {}
|
|
36
64
|
});
|
|
37
65
|
}
|
|
38
66
|
return instance;
|
|
@@ -61,11 +89,14 @@ async function apiRequest(method, path, body) {
|
|
|
61
89
|
|
|
62
90
|
// src/lib/format.ts
|
|
63
91
|
function formatSubgraphSummary(s) {
|
|
92
|
+
const apiUrl = process.env.SECONDLAYER_API_URL || "https://api.secondlayer.tools";
|
|
64
93
|
return {
|
|
65
94
|
name: s.name,
|
|
66
95
|
status: s.status,
|
|
67
96
|
tables: Array.isArray(s.tables) ? s.tables : Object.keys(s.tables),
|
|
68
|
-
lastProcessedBlock: s.lastProcessedBlock
|
|
97
|
+
lastProcessedBlock: s.lastProcessedBlock,
|
|
98
|
+
...s.visibility ? { visibility: s.visibility } : {},
|
|
99
|
+
...s.visibility === "public" ? { publicUrl: `${apiUrl}/v1/subgraphs/${s.name}` } : {}
|
|
69
100
|
};
|
|
70
101
|
}
|
|
71
102
|
function withCap(items, cap) {
|
|
@@ -170,7 +201,6 @@ var COLUMN_TYPES = [
|
|
|
170
201
|
}
|
|
171
202
|
];
|
|
172
203
|
var PRODUCT_BLURBS = {
|
|
173
|
-
datasets: "public foundation datasets",
|
|
174
204
|
index: "decoded L2 events, contract calls, blocks, transactions, stacking, mempool",
|
|
175
205
|
streams: "raw canonical chain event firehose",
|
|
176
206
|
contracts: "trait-based contract discovery",
|
|
@@ -181,7 +211,6 @@ var PRODUCT_BLURBS = {
|
|
|
181
211
|
scaffold: "generate typed contract clients from a deployment or ABI"
|
|
182
212
|
};
|
|
183
213
|
var PRODUCT_ORDER = [
|
|
184
|
-
"datasets",
|
|
185
214
|
"index",
|
|
186
215
|
"streams",
|
|
187
216
|
"contracts",
|
|
@@ -210,21 +239,30 @@ function buildCapabilities() {
|
|
|
210
239
|
});
|
|
211
240
|
return {
|
|
212
241
|
products,
|
|
213
|
-
discoverFirst: "Call
|
|
242
|
+
discoverFirst: "Call index_discover / contracts_find to learn what exists (and which filters each surface accepts) before querying."
|
|
214
243
|
};
|
|
215
244
|
}
|
|
245
|
+
var X402_CAPABILITY = {
|
|
246
|
+
what: "Index and Streams reads (/v1/index/*, /v1/streams/*) accept x402 v2 pay-per-call (network stacks:1, sponsored transfers — the payer holds sBTC/STX/USDCx, never gas). Index grants 1,000 free reads/day/IP before any 402; a paid Streams call opens a 500-call/1h PAYMENT-SESSION.",
|
|
247
|
+
paidWrites: "POST /v1/subgraphs (x402 $2) deploys a subgraph owned by the paying wallet — live from deploy, 7-day TTL, renewable via POST /v1/subgraphs/{name}/renew ($0.50/wk); claiming the account clears the expiry.",
|
|
248
|
+
prepaid: "POST /v1/x402/deposit?usd=N loads a prepaid tab (PAYMENT-BALANCE token, $0.25 min) — calls debit it instantly, no per-call on-chain settle. GET /v1/x402/balance reads it.",
|
|
249
|
+
discovery: "GET /v1/x402/supported on the API host for scheme, assets, prices, quotas, sessions, and prepaid metadata.",
|
|
250
|
+
autopay: "Set X402_PRIVATE_KEY (a Stacks private key holding an accepted token) and this MCP server pays 402 challenges automatically (sessions replayed). Add X402_TOPUP_USD (and optionally X402_TOPUP_WHEN_BELOW) for an autonomous prepaid tab that refills itself. Receipts are logged per paid call."
|
|
251
|
+
};
|
|
216
252
|
var READ_AUTH_TIERS = {
|
|
217
|
-
datasets: "open — no API key required",
|
|
218
253
|
index: "anonymous reads allowed; free-tier API keys are rejected (Build+ required)",
|
|
219
254
|
streams: "API key required (SL_API_KEY) — keyless calls return 401",
|
|
220
|
-
subgraphs: "
|
|
255
|
+
subgraphs: "public subgraphs anon-readable at /v1/subgraphs/<name>/<table> ({ rows, next_cursor, tip } cursor envelope); private subgraphs need the owning account's API key (anon → 404); writes require an API key"
|
|
221
256
|
};
|
|
222
257
|
async function buildContext(deps = { clientProvider: getClient }) {
|
|
223
258
|
const unavailable = "unavailable: set SL_API_KEY";
|
|
224
259
|
const orNull = (v) => v == null ? unavailable : v;
|
|
225
260
|
const snap = await deps.clientProvider().context().catch(() => null);
|
|
226
261
|
return {
|
|
227
|
-
authState: {
|
|
262
|
+
authState: {
|
|
263
|
+
apiKeySet: Boolean(process.env.SL_API_KEY),
|
|
264
|
+
x402WalletSet: Boolean(process.env.X402_PRIVATE_KEY)
|
|
265
|
+
},
|
|
228
266
|
whatExists: {
|
|
229
267
|
account: orNull(snap?.account),
|
|
230
268
|
streamsTip: orNull(snap?.streamsTip),
|
|
@@ -236,7 +274,8 @@ async function buildContext(deps = { clientProvider: getClient }) {
|
|
|
236
274
|
activeOperations: orNull(snap?.activeOperations)
|
|
237
275
|
},
|
|
238
276
|
whatYouCanDo: buildCapabilities(),
|
|
239
|
-
readAuthTiers: READ_AUTH_TIERS
|
|
277
|
+
readAuthTiers: READ_AUTH_TIERS,
|
|
278
|
+
payPerCall: X402_CAPABILITY
|
|
240
279
|
};
|
|
241
280
|
}
|
|
242
281
|
function registerResources(server) {
|
|
@@ -424,43 +463,20 @@ function registerContractTools(server, clientProvider = getClient) {
|
|
|
424
463
|
});
|
|
425
464
|
}
|
|
426
465
|
|
|
427
|
-
// src/tools/datasets.ts
|
|
428
|
-
import { z as z3 } from "zod/v4";
|
|
429
|
-
function registerDatasetTools(server, clientProvider = getClient) {
|
|
430
|
-
defineTool(server, "datasets_list", "List the Foundation Datasets catalog with freshness — the discovery endpoint for what dataset slugs exist and how current each is. Reads are public.", {}, async () => {
|
|
431
|
-
const catalog = await clientProvider().datasets.listDatasets();
|
|
432
|
-
return jsonResponse(catalog);
|
|
433
|
-
});
|
|
434
|
-
defineTool(server, "datasets_query", 'Query ANY Foundation Dataset by slug — every family returned by datasets_list is queryable, including bespoke ones (bns/resolve with {"fqn":"alice.btc"}, bns/names, bns/namespaces, network-health/summary) and any dataset added later. Accepts family ("sbtc-events") or path ("sbtc/events") slug forms. Filters are passed through as documented query params (e.g. {"sender": "SP...", "from_block": "150000"}). Returns { rows, next_cursor, tip }; single-record datasets like bns/resolve return 0-or-1 rows (empty = not found). Call datasets_list first to discover slugs and their filters.', {
|
|
435
|
-
slug: z3.string().describe("Dataset slug from datasets_list (e.g. stx-transfers)"),
|
|
436
|
-
filters: z3.record(z3.string(), z3.string()).optional().describe("Documented per-dataset query params (snake_case values)"),
|
|
437
|
-
limit: z3.number().optional().describe("Max rows for this page"),
|
|
438
|
-
cursor: z3.string().optional().describe("Opaque cursor from a prior response's next_cursor")
|
|
439
|
-
}, async ({ slug, filters, limit, cursor }) => {
|
|
440
|
-
const params = { ...filters ?? {} };
|
|
441
|
-
if (limit !== undefined)
|
|
442
|
-
params.limit = limit;
|
|
443
|
-
if (cursor !== undefined)
|
|
444
|
-
params.cursor = cursor;
|
|
445
|
-
const result = await clientProvider().datasets.get(slug, params);
|
|
446
|
-
return jsonResponse(result);
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
|
|
450
466
|
// src/tools/index.ts
|
|
451
467
|
import { DECODED_EVENT_TYPES as DECODED_EVENT_TYPES2 } from "@secondlayer/shared";
|
|
452
468
|
import {
|
|
453
469
|
INDEX_CODEGEN_TABLES,
|
|
454
470
|
generateIndexSchema
|
|
455
471
|
} from "@secondlayer/subgraphs";
|
|
456
|
-
import { z as
|
|
472
|
+
import { z as z3 } from "zod/v4";
|
|
457
473
|
var INDEX_EVENT_TYPES = DECODED_EVENT_TYPES2;
|
|
458
474
|
var rangeFilters = {
|
|
459
|
-
contractId:
|
|
460
|
-
fromHeight:
|
|
461
|
-
toHeight:
|
|
462
|
-
cursor:
|
|
463
|
-
limit:
|
|
475
|
+
contractId: z3.string().optional().describe("Filter by contract id"),
|
|
476
|
+
fromHeight: z3.number().optional().describe("Start block height (inclusive)"),
|
|
477
|
+
toHeight: z3.number().optional().describe("End block height (inclusive)"),
|
|
478
|
+
cursor: z3.string().optional().describe("Opaque cursor from a prior response's next_cursor"),
|
|
479
|
+
limit: z3.number().optional().describe("Max rows for this page")
|
|
464
480
|
};
|
|
465
481
|
var heightFilters = {
|
|
466
482
|
fromHeight: rangeFilters.fromHeight,
|
|
@@ -472,89 +488,95 @@ var notFound = (message) => jsonResponse({ error: { type: "not_found", status: 4
|
|
|
472
488
|
function registerIndexTools(server, clientProvider = getClient) {
|
|
473
489
|
defineTool(server, "index_ft_transfers", "List decoded SIP-010 fungible-token transfers from the Index (L2 decoded layer). Anonymous reads allowed (free-tier API keys are rejected — Build+ required).", {
|
|
474
490
|
...rangeFilters,
|
|
475
|
-
sender:
|
|
476
|
-
recipient:
|
|
491
|
+
sender: z3.string().optional().describe("Filter by sender principal"),
|
|
492
|
+
recipient: z3.string().optional().describe("Filter by recipient principal")
|
|
477
493
|
}, async (params) => jsonResponse(await clientProvider().index.ftTransfers.list(params)));
|
|
478
494
|
defineTool(server, "index_nft_transfers", "List decoded SIP-009 non-fungible-token transfers from the Index. Anonymous reads allowed (free-tier keys rejected).", {
|
|
479
495
|
...rangeFilters,
|
|
480
|
-
sender:
|
|
481
|
-
recipient:
|
|
482
|
-
assetIdentifier:
|
|
496
|
+
sender: z3.string().optional().describe("Filter by sender principal"),
|
|
497
|
+
recipient: z3.string().optional().describe("Filter by recipient principal"),
|
|
498
|
+
assetIdentifier: z3.string().optional().describe("Filter by asset identifier (contract::asset)")
|
|
483
499
|
}, async (params) => jsonResponse(await clientProvider().index.nftTransfers.list(params)));
|
|
484
500
|
defineTool(server, "index_events", "List decoded chain events from the Index by event type. Use this for event types without a dedicated tool (stx_*, ft_mint/burn, nft_mint/burn, print), and for trait-scoped queries: set `trait` (e.g. sip-010) to match all contracts conforming to a standard — pair with contracts_find to discover traits. For ft/nft transfers without a trait prefer index_ft_transfers / index_nft_transfers.", {
|
|
485
|
-
eventType:
|
|
501
|
+
eventType: z3.enum(INDEX_EVENT_TYPES).describe("Required. Decoded event type to list."),
|
|
486
502
|
...rangeFilters,
|
|
487
|
-
sender:
|
|
488
|
-
recipient:
|
|
489
|
-
assetIdentifier:
|
|
490
|
-
trait:
|
|
503
|
+
sender: z3.string().optional().describe("Filter by sender principal"),
|
|
504
|
+
recipient: z3.string().optional().describe("Filter by recipient principal"),
|
|
505
|
+
assetIdentifier: z3.string().optional().describe("Filter by asset identifier where applicable"),
|
|
506
|
+
trait: z3.string().optional().describe("Match contracts conforming to a trait/standard (e.g. sip-010). Mutually exclusive with contractId; contract-keyed event types only.")
|
|
491
507
|
}, async (params) => jsonResponse(await clientProvider().index.events.list(params)));
|
|
492
508
|
defineTool(server, "index_contract_calls", "List decoded contract calls from the Index (function name, args, result). Set `trait` (e.g. sip-010) to match calls to all contracts conforming to a standard. Note: contract-call cursors are a SEPARATE keyspace from event cursors — they are not interchangeable.", {
|
|
493
509
|
...rangeFilters,
|
|
494
|
-
functionName:
|
|
495
|
-
sender:
|
|
496
|
-
trait:
|
|
510
|
+
functionName: z3.string().optional().describe("Filter by called function name"),
|
|
511
|
+
sender: z3.string().optional().describe("Filter by caller principal"),
|
|
512
|
+
trait: z3.string().optional().describe("Match contracts conforming to a trait/standard (e.g. sip-010). Mutually exclusive with contractId.")
|
|
497
513
|
}, async (params) => jsonResponse(await clientProvider().index.contractCalls.list(params)));
|
|
498
514
|
defineTool(server, "index_canonical", "List the canonical Stacks block sequence from the Index (height + hash). Anonymous reads allowed (free-tier keys rejected).", { ...heightFilters }, async (params) => jsonResponse(await clientProvider().index.canonical.list(params)));
|
|
499
515
|
defineTool(server, "index_blocks", "List decoded blocks from the Index. Anonymous reads allowed (free-tier keys rejected).", { ...heightFilters }, async (params) => jsonResponse(await clientProvider().index.blocks.list(params)));
|
|
500
516
|
defineTool(server, "index_block", "Get a single block from the Index by height or block hash. Returns not_found if unknown.", {
|
|
501
|
-
ref:
|
|
517
|
+
ref: z3.string().describe("Block height (digits) or block hash (0x… string)")
|
|
502
518
|
}, async ({ ref }) => {
|
|
503
519
|
const block = await clientProvider().index.blocks.get(/^\d+$/.test(ref) ? Number(ref) : ref);
|
|
504
520
|
return block ? jsonResponse(block) : notFound(`No block for ref ${ref}`);
|
|
505
521
|
});
|
|
506
522
|
defineTool(server, "index_transactions", "List decoded transactions from the Index. Filter by type, sender, or contract. Anonymous reads allowed (free-tier keys rejected).", {
|
|
507
523
|
...rangeFilters,
|
|
508
|
-
type:
|
|
509
|
-
sender:
|
|
524
|
+
type: z3.string().optional().describe("Filter by transaction type"),
|
|
525
|
+
sender: z3.string().optional().describe("Filter by sender principal")
|
|
510
526
|
}, async (params) => jsonResponse(await clientProvider().index.transactions.list(params)));
|
|
511
|
-
defineTool(server, "index_transaction", "Get a single transaction from the Index by tx_id. Returns not_found if unknown.", { txId:
|
|
527
|
+
defineTool(server, "index_transaction", "Get a single transaction from the Index by tx_id. Returns not_found if unknown.", { txId: z3.string().describe("Transaction id (0x… hash)") }, async ({ txId }) => {
|
|
512
528
|
const tx = await clientProvider().index.transactions.get(txId);
|
|
513
529
|
return tx ? jsonResponse(tx) : notFound(`No transaction for ${txId}`);
|
|
514
530
|
});
|
|
515
|
-
defineTool(server, "index_transaction_proof", "Fetch a transaction's inclusion proof (raw tx + signed Nakamoto block header + merkle path) so it can be verified trustlessly client-side with the SDK's verifyTransactionProof. Returns not_found if the tx/block is unknown; a 503 means the proof can't be assembled on this deployment right now (PROOF_TX_SET_INCOMPLETE, or PROOF_NODE_UNAVAILABLE when the stacks-node header source isn't configured).", { txId:
|
|
531
|
+
defineTool(server, "index_transaction_proof", "Fetch a transaction's inclusion proof (raw tx + signed Nakamoto block header + merkle path) so it can be verified trustlessly client-side with the SDK's verifyTransactionProof. Returns not_found if the tx/block is unknown; a 503 means the proof can't be assembled on this deployment right now (PROOF_TX_SET_INCOMPLETE, or PROOF_NODE_UNAVAILABLE when the stacks-node header source isn't configured).", { txId: z3.string().describe("Transaction id (0x… hash)") }, async ({ txId }) => {
|
|
516
532
|
const proof = await clientProvider().index.transactions.getProof(txId);
|
|
517
533
|
return proof ? jsonResponse(proof) : notFound(`No proof available for ${txId}`);
|
|
518
534
|
});
|
|
519
535
|
defineTool(server, "index_stacking", "List decoded PoX-4 stacking actions from the Index (stack-stx, delegate-stx, etc.). Anonymous reads allowed (free-tier keys rejected).", {
|
|
520
536
|
...heightFilters,
|
|
521
|
-
functionName:
|
|
522
|
-
stacker:
|
|
523
|
-
caller:
|
|
537
|
+
functionName: z3.string().optional().describe("Filter by PoX function name"),
|
|
538
|
+
stacker: z3.string().optional().describe("Filter by stacker principal"),
|
|
539
|
+
caller: z3.string().optional().describe("Filter by caller principal")
|
|
524
540
|
}, async (params) => jsonResponse(await clientProvider().index.stacking.list(params)));
|
|
525
541
|
defineTool(server, "index_mempool", "List pending (unconfirmed) transactions from the Index mempool. Sequence-cursor paginated (no height range). Anonymous reads allowed (free-tier keys rejected).", {
|
|
526
|
-
sender:
|
|
527
|
-
type:
|
|
528
|
-
contractId:
|
|
529
|
-
cursor:
|
|
530
|
-
limit:
|
|
542
|
+
sender: z3.string().optional().describe("Filter by sender principal"),
|
|
543
|
+
type: z3.string().optional().describe("Filter by transaction type"),
|
|
544
|
+
contractId: z3.string().optional().describe("Filter to pending calls to a single contract"),
|
|
545
|
+
cursor: z3.string().optional().describe("Opaque cursor from a prior response's next_cursor"),
|
|
546
|
+
limit: z3.number().optional().describe("Max rows for this page")
|
|
531
547
|
}, async (params) => jsonResponse(await clientProvider().index.mempool.list(params)));
|
|
532
|
-
defineTool(server, "index_mempool_tx", "Get a single pending transaction from the Index mempool by tx_id. Returns not_found once it is mined or dropped.", { txId:
|
|
548
|
+
defineTool(server, "index_mempool_tx", "Get a single pending transaction from the Index mempool by tx_id. Returns not_found once it is mined or dropped.", { txId: z3.string().describe("Transaction id (0x… hash)") }, async ({ txId }) => {
|
|
533
549
|
const tx = await clientProvider().index.mempool.get(txId);
|
|
534
550
|
return tx ? jsonResponse(tx) : notFound(`No pending tx for ${txId}`);
|
|
535
551
|
});
|
|
536
552
|
defineTool(server, "index_discover", "Discover the Index vocabulary: every event type and its columns, allowed/equality filters, and required-non-null fields (and which types accept `trait`). Read this before building Index queries instead of guessing filters. Anonymous read.", {}, async () => jsonResponse(await clientProvider().index.discover()));
|
|
537
553
|
defineTool(server, "index_usage", "Your own Index consumption (decoded events today + this month) and tier limits. Requires a Build+ API key (anonymous reads can't report usage).", {}, async () => jsonResponse(await clientProvider().index.usage()));
|
|
538
554
|
defineTool(server, "index_codegen", `Generate a typed schema (Prisma, Kysely, Drizzle, or JSON-Schema) for the public Index domain tables so they can be mirrored into a BYO database with full types. Returns the schema as text. Tables: ${INDEX_CODEGEN_TABLES.join(", ")}.`, {
|
|
539
|
-
target:
|
|
540
|
-
tables:
|
|
541
|
-
schemaName:
|
|
555
|
+
target: z3.enum(["prisma", "kysely", "drizzle", "json-schema"]).optional().describe("Output target (default kysely)"),
|
|
556
|
+
tables: z3.array(z3.string()).optional().describe("Subset of Index tables (default: all)"),
|
|
557
|
+
schemaName: z3.string().optional().describe("Postgres schema to qualify table names with")
|
|
542
558
|
}, async ({ target = "kysely", tables, schemaName }) => {
|
|
543
559
|
const out = generateIndexSchema(target, { tables, schemaName });
|
|
544
560
|
return { content: [{ type: "text", text: out }] };
|
|
545
561
|
});
|
|
562
|
+
defineTool(server, "batch_query", "Run up to 10 public /v1 reads in one round trip (POST /v1/batch). Each item keeps its own auth/quota/pay-per-call semantics; results return in order with per-item status. Paths must start with /v1/index, /v1/subgraphs, /v1/streams, or /v1/contracts.", {
|
|
563
|
+
requests: z3.array(z3.object({
|
|
564
|
+
path: z3.string().describe("Public /v1 read path"),
|
|
565
|
+
params: z3.record(z3.string(), z3.string()).optional()
|
|
566
|
+
})).min(1).max(10).describe("Read descriptors, executed concurrently")
|
|
567
|
+
}, async (params) => jsonResponse(await clientProvider().batch(params.requests)));
|
|
546
568
|
}
|
|
547
569
|
|
|
548
570
|
// src/tools/projects.ts
|
|
549
|
-
import { z as
|
|
571
|
+
import { z as z4 } from "zod/v4";
|
|
550
572
|
function registerProjectTools(server, clientProvider = getClient) {
|
|
551
573
|
defineTool(server, "project_list", "List the account's projects. Requires an account-level (owner) API key.", {}, async () => jsonResponse(await clientProvider().projects.list()));
|
|
552
|
-
defineTool(server, "project_get", "Get a single project by slug.", { slug:
|
|
574
|
+
defineTool(server, "project_get", "Get a single project by slug.", { slug: z4.string().describe("Project slug") }, async ({ slug }) => jsonResponse(await clientProvider().projects.get(slug)));
|
|
553
575
|
defineTool(server, "project_create", "Create a project. The slug is derived from the name when omitted. Requires an account-level (owner) API key.", {
|
|
554
|
-
name:
|
|
555
|
-
slug:
|
|
556
|
-
network:
|
|
557
|
-
nodeRpc:
|
|
576
|
+
name: z4.string().describe("Project name"),
|
|
577
|
+
slug: z4.string().optional().describe("URL slug (auto-derived from name if omitted)"),
|
|
578
|
+
network: z4.string().optional().describe("Network (e.g. mainnet, testnet)"),
|
|
579
|
+
nodeRpc: z4.string().optional().describe("Custom node RPC URL")
|
|
558
580
|
}, async ({ name, slug, network, nodeRpc }) => jsonResponse(await clientProvider().projects.create({
|
|
559
581
|
name,
|
|
560
582
|
slug,
|
|
@@ -562,12 +584,12 @@ function registerProjectTools(server, clientProvider = getClient) {
|
|
|
562
584
|
nodeRpc
|
|
563
585
|
})));
|
|
564
586
|
defineTool(server, "project_update", "Update a project. `slug` selects the project; `newSlug` renames it. Requires an account-level (owner) API key.", {
|
|
565
|
-
slug:
|
|
566
|
-
newSlug:
|
|
567
|
-
name:
|
|
568
|
-
network:
|
|
569
|
-
nodeRpc:
|
|
570
|
-
settings:
|
|
587
|
+
slug: z4.string().describe("Slug of the project to update"),
|
|
588
|
+
newSlug: z4.string().optional().describe("New slug (renames the project)"),
|
|
589
|
+
name: z4.string().optional().describe("New display name"),
|
|
590
|
+
network: z4.string().optional().describe("Network (e.g. mainnet, testnet)"),
|
|
591
|
+
nodeRpc: z4.string().optional().describe("Custom node RPC URL"),
|
|
592
|
+
settings: z4.record(z4.string(), z4.unknown()).optional().describe("Arbitrary project settings to merge")
|
|
571
593
|
}, async ({ slug, newSlug, name, network, nodeRpc, settings }) => jsonResponse(await clientProvider().projects.update(slug, {
|
|
572
594
|
...newSlug !== undefined ? { slug: newSlug } : {},
|
|
573
595
|
...name !== undefined ? { name } : {},
|
|
@@ -575,8 +597,8 @@ function registerProjectTools(server, clientProvider = getClient) {
|
|
|
575
597
|
...nodeRpc !== undefined ? { nodeRpc } : {},
|
|
576
598
|
...settings !== undefined ? { settings } : {}
|
|
577
599
|
})));
|
|
578
|
-
defineTool(server, "project_delete", "Delete a project permanently. The account's last remaining project cannot be deleted.", { slug:
|
|
579
|
-
defineTool(server, "project_team_list", "List a project's team members and pending invitations.", { slug:
|
|
600
|
+
defineTool(server, "project_delete", "Delete a project permanently. The account's last remaining project cannot be deleted.", { slug: z4.string().describe("Project slug") }, async ({ slug }) => jsonResponse(await clientProvider().projects.delete(slug)));
|
|
601
|
+
defineTool(server, "project_team_list", "List a project's team members and pending invitations.", { slug: z4.string().describe("Project slug") }, async ({ slug }) => jsonResponse(await clientProvider().projects.team(slug)));
|
|
580
602
|
}
|
|
581
603
|
|
|
582
604
|
// src/tools/scaffold.ts
|
|
@@ -585,7 +607,7 @@ import {
|
|
|
585
607
|
generateTraitSubgraph
|
|
586
608
|
} from "@secondlayer/scaffold";
|
|
587
609
|
import { TRAIT_STANDARDS as TRAIT_STANDARDS2 } from "@secondlayer/stacks/clarity";
|
|
588
|
-
import { z as
|
|
610
|
+
import { z as z5 } from "zod/v4";
|
|
589
611
|
async function fetchAbi(contractId) {
|
|
590
612
|
const contract = await getClient().contracts.get(contractId, {
|
|
591
613
|
includeAbi: true
|
|
@@ -600,24 +622,24 @@ async function fetchAbi(contractId) {
|
|
|
600
622
|
}
|
|
601
623
|
function registerScaffoldTools(server) {
|
|
602
624
|
defineTool(server, "scaffold_from_trait", "Generate a deploy-ready subgraph scaffold that indexes EVERY contract conforming to a SIP trait (no specific contract needed) — sip-009 → an nft_transfer source, sip-010/sip-013 → ft_transfer. Use scaffold_from_contract/abi instead when targeting one contract. See the secondlayer://traits resource for valid trait ids.", {
|
|
603
|
-
trait:
|
|
604
|
-
subgraphName:
|
|
625
|
+
trait: z5.enum(TRAIT_STANDARDS2).describe("SIP standard to index (sip-009 | sip-010 | sip-013)"),
|
|
626
|
+
subgraphName: z5.string().optional().describe("Override the subgraph name (defaults to <trait>-transfers)")
|
|
605
627
|
}, async ({ trait, subgraphName }) => {
|
|
606
628
|
const code = generateTraitSubgraph({ trait, name: subgraphName });
|
|
607
629
|
return { content: [{ type: "text", text: code }] };
|
|
608
630
|
});
|
|
609
631
|
defineTool(server, "scaffold_from_contract", "Generate a subgraph scaffold from a deployed Stacks contract. Fetches the ABI automatically.", {
|
|
610
|
-
contractId:
|
|
611
|
-
subgraphName:
|
|
632
|
+
contractId: z5.string().describe("Fully qualified contract ID (e.g. SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-pool-v2-01)"),
|
|
633
|
+
subgraphName: z5.string().optional().describe("Override the subgraph name (defaults to contract name)")
|
|
612
634
|
}, async ({ contractId, subgraphName }) => {
|
|
613
635
|
const { functions, maps } = await fetchAbi(contractId);
|
|
614
636
|
const code = generateSubgraphCode(contractId, functions, subgraphName, maps);
|
|
615
637
|
return { content: [{ type: "text", text: code }] };
|
|
616
638
|
});
|
|
617
639
|
defineTool(server, "scaffold_from_abi", "Generate a subgraph scaffold from a provided ABI JSON. Use when you already have the ABI.", {
|
|
618
|
-
abi:
|
|
619
|
-
contractId:
|
|
620
|
-
subgraphName:
|
|
640
|
+
abi: z5.string().describe("ABI JSON string (the full contract ABI object)"),
|
|
641
|
+
contractId: z5.string().describe("Fully qualified contract ID"),
|
|
642
|
+
subgraphName: z5.string().optional().describe("Override the subgraph name")
|
|
621
643
|
}, async ({ abi, contractId, subgraphName }) => {
|
|
622
644
|
let parsed;
|
|
623
645
|
try {
|
|
@@ -636,7 +658,7 @@ function registerScaffoldTools(server) {
|
|
|
636
658
|
// src/tools/streams.ts
|
|
637
659
|
import { AuthError } from "@secondlayer/sdk";
|
|
638
660
|
import { DECODED_EVENT_TYPES as DECODED_EVENT_TYPES3 } from "@secondlayer/shared";
|
|
639
|
-
import { z as
|
|
661
|
+
import { z as z6 } from "zod/v4";
|
|
640
662
|
var STREAMS_EVENT_TYPES = DECODED_EVENT_TYPES3;
|
|
641
663
|
async function withStreamsAuthHint(fn) {
|
|
642
664
|
try {
|
|
@@ -651,28 +673,28 @@ async function withStreamsAuthHint(fn) {
|
|
|
651
673
|
function registerStreamsTools(server, clientProvider = getClient) {
|
|
652
674
|
defineTool(server, "streams_tip", "Get the current Streams chain tip (latest processed block + lag). Streams requires an API key (SL_API_KEY).", {}, async () => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.tip())));
|
|
653
675
|
defineTool(server, "streams_events", "List raw chain events from the Streams firehose. Streams requires an API key (SL_API_KEY). Filter by event types, principals, contract, asset, or block range; page with cursor.", {
|
|
654
|
-
types:
|
|
655
|
-
notTypes:
|
|
656
|
-
contractId:
|
|
657
|
-
sender:
|
|
658
|
-
recipient:
|
|
659
|
-
assetIdentifier:
|
|
660
|
-
fromHeight:
|
|
661
|
-
toHeight:
|
|
662
|
-
cursor:
|
|
663
|
-
limit:
|
|
676
|
+
types: z6.array(z6.enum(STREAMS_EVENT_TYPES)).optional().describe("Event types to include"),
|
|
677
|
+
notTypes: z6.array(z6.enum(STREAMS_EVENT_TYPES)).optional().describe("Event types to exclude (applied after types)"),
|
|
678
|
+
contractId: z6.string().optional().describe("Filter by contract id"),
|
|
679
|
+
sender: z6.string().optional().describe("Filter by sender principal"),
|
|
680
|
+
recipient: z6.string().optional().describe("Filter by recipient principal"),
|
|
681
|
+
assetIdentifier: z6.string().optional().describe("Filter by asset identifier"),
|
|
682
|
+
fromHeight: z6.number().optional().describe("Start block height (inclusive)"),
|
|
683
|
+
toHeight: z6.number().optional().describe("End block height (inclusive)"),
|
|
684
|
+
cursor: z6.string().optional().describe("Opaque cursor from a prior response"),
|
|
685
|
+
limit: z6.number().optional().describe("Max events for this page")
|
|
664
686
|
}, async (params) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.events.list(params))));
|
|
665
687
|
defineTool(server, "streams_consume", "Consume a bounded, reorg-aware run of Streams events from a cursor. Walks up to maxPages pages and returns the events, any reorgs observed, and a resume `cursor` to pass back as fromCursor next call — the agent-native consume/resume primitive. Streams requires an API key (SL_API_KEY).", {
|
|
666
|
-
fromCursor:
|
|
667
|
-
types:
|
|
668
|
-
notTypes:
|
|
669
|
-
contractId:
|
|
670
|
-
sender:
|
|
671
|
-
recipient:
|
|
672
|
-
assetIdentifier:
|
|
673
|
-
batchSize:
|
|
674
|
-
maxPages:
|
|
675
|
-
finalizedOnly:
|
|
688
|
+
fromCursor: z6.string().optional().describe("Resume cursor from a prior consume (omit to start at genesis)"),
|
|
689
|
+
types: z6.array(z6.enum(STREAMS_EVENT_TYPES)).optional().describe("Event types to include"),
|
|
690
|
+
notTypes: z6.array(z6.enum(STREAMS_EVENT_TYPES)).optional().describe("Event types to exclude"),
|
|
691
|
+
contractId: z6.string().optional().describe("Filter by contract id"),
|
|
692
|
+
sender: z6.string().optional().describe("Filter by sender principal"),
|
|
693
|
+
recipient: z6.string().optional().describe("Filter by recipient principal"),
|
|
694
|
+
assetIdentifier: z6.string().optional().describe("Filter by asset identifier"),
|
|
695
|
+
batchSize: z6.number().optional().describe("Events per page (1–1000, default 100)"),
|
|
696
|
+
maxPages: z6.number().optional().describe("Max pages to walk this call (1–20, default 5)"),
|
|
697
|
+
finalizedOnly: z6.boolean().optional().describe("Only emit finalized events; skip reorg handling")
|
|
676
698
|
}, async (params) => withStreamsAuthHint(async () => {
|
|
677
699
|
const maxPages = Math.min(Math.max(params.maxPages ?? 5, 1), 20);
|
|
678
700
|
const batchSize = Math.min(Math.max(params.batchSize ?? 100, 1), 1000);
|
|
@@ -704,15 +726,15 @@ function registerStreamsTools(server, clientProvider = getClient) {
|
|
|
704
726
|
pages: result.pages
|
|
705
727
|
});
|
|
706
728
|
}));
|
|
707
|
-
defineTool(server, "streams_event_by_txid", "List all Streams events emitted by a single transaction. Streams requires an API key (SL_API_KEY).", { txId:
|
|
729
|
+
defineTool(server, "streams_event_by_txid", "List all Streams events emitted by a single transaction. Streams requires an API key (SL_API_KEY).", { txId: z6.string().describe("Transaction id (0x… hash)") }, async ({ txId }) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.events.byTxId(txId))));
|
|
708
730
|
defineTool(server, "streams_block_events", "List all Streams events in a single block, by height or block hash. Streams requires an API key (SL_API_KEY).", {
|
|
709
|
-
heightOrHash:
|
|
731
|
+
heightOrHash: z6.string().describe("Block height (digits) or block hash (0x… string)")
|
|
710
732
|
}, async ({ heightOrHash }) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.blocks.events(/^\d+$/.test(heightOrHash) ? Number(heightOrHash) : heightOrHash))));
|
|
711
733
|
defineTool(server, "streams_reorgs", "List chain reorgs observed by Streams since a cursor. Streams requires an API key (SL_API_KEY).", {
|
|
712
|
-
since:
|
|
713
|
-
limit:
|
|
734
|
+
since: z6.string().describe("Cursor to list reorgs since (block:index or ISO timestamp)"),
|
|
735
|
+
limit: z6.number().optional().describe("Max reorgs to return")
|
|
714
736
|
}, async (params) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.reorgs.list(params))));
|
|
715
|
-
defineTool(server, "streams_canonical", "Get the canonical block at a given height from Streams (height + hashes + is_canonical). Streams requires an API key (SL_API_KEY).", { height:
|
|
737
|
+
defineTool(server, "streams_canonical", "Get the canonical block at a given height from Streams (height + hashes + is_canonical). Streams requires an API key (SL_API_KEY).", { height: z6.number().describe("Block height") }, async ({ height }) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.canonical(height))));
|
|
716
738
|
defineTool(server, "streams_usage", "Your own Streams consumption (events today + this month) and tier limits (rate limit, retention). Streams requires an API key (SL_API_KEY).", {}, async () => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.usage())));
|
|
717
739
|
defineTool(server, "streams_dumps", "List the Streams bulk parquet dumps manifest — coverage range, latest_finalized_cursor, and per-file metadata (block range, row count, size, sha256, signed URL). This is the cold backfill path for downloading all raw data; fetch the file URLs directly (e.g. with DuckDB). Requires the dumps base URL to be configured (SL_STREAMS_DUMPS_URL).", {}, async () => jsonResponse(await clientProvider().streams.dumps.list()));
|
|
718
740
|
}
|
|
@@ -725,9 +747,9 @@ import {
|
|
|
725
747
|
generateKyselySchema,
|
|
726
748
|
generatePrismaSchema
|
|
727
749
|
} from "@secondlayer/subgraphs";
|
|
728
|
-
import { z as
|
|
750
|
+
import { z as z7 } from "zod/v4";
|
|
729
751
|
function registerSubgraphTools(server, clientProvider = getClient) {
|
|
730
|
-
defineTool(server, "subgraphs_list", "List all deployed subgraphs. Returns summary fields only
|
|
752
|
+
defineTool(server, "subgraphs_list", "List all deployed subgraphs. Returns summary fields only, including visibility — public subgraphs are anon-readable at /v1/subgraphs/<name>.", {}, async () => {
|
|
731
753
|
const { data } = await clientProvider().subgraphs.list();
|
|
732
754
|
return {
|
|
733
755
|
content: [
|
|
@@ -738,16 +760,16 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
738
760
|
]
|
|
739
761
|
};
|
|
740
762
|
});
|
|
741
|
-
defineTool(server, "subgraphs_get", "Get full details of a subgraph including schema, health, and table columns.", { name:
|
|
763
|
+
defineTool(server, "subgraphs_get", "Get full details of a subgraph including schema, health, and table columns.", { name: z7.string().describe("Subgraph name") }, async ({ name }) => {
|
|
742
764
|
const detail = await clientProvider().subgraphs.get(name);
|
|
743
765
|
return {
|
|
744
766
|
content: [{ type: "text", text: JSON.stringify(detail, null, 2) }]
|
|
745
767
|
};
|
|
746
768
|
});
|
|
747
769
|
defineTool(server, "subgraphs_spec", "Get generated API documentation for a subgraph. Defaults to compact agent schema; supports OpenAPI JSON and Markdown.", {
|
|
748
|
-
name:
|
|
749
|
-
format:
|
|
750
|
-
serverUrl:
|
|
770
|
+
name: z7.string().describe("Subgraph name"),
|
|
771
|
+
format: z7.enum(["agent", "openapi", "markdown"]).optional().describe("Spec format to return. Defaults to agent."),
|
|
772
|
+
serverUrl: z7.string().optional().describe("Override the server URL embedded in generated docs.")
|
|
751
773
|
}, async ({ name, format = "agent", serverUrl }) => {
|
|
752
774
|
const options = serverUrl ? { serverUrl } : undefined;
|
|
753
775
|
const spec = format === "openapi" ? await clientProvider().subgraphs.openapi(name, options) : format === "markdown" ? await clientProvider().subgraphs.markdown(name, options) : await clientProvider().subgraphs.schema(name, options);
|
|
@@ -760,16 +782,16 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
760
782
|
]
|
|
761
783
|
};
|
|
762
784
|
});
|
|
763
|
-
defineTool(server, "subgraphs_query", 'Query rows from a subgraph table (max 200 rows). Filters support operators: "amount.gte": "1000", "sender.neq": "SP...", "name.like": "%token%". Available operators: eq, neq, gt, gte, lt, lte, like. To TAIL new rows (no streaming over MCP): sort=_id, order=desc for the latest, then poll forward with the filter {"_id.gt": "<last _id seen>"}, order=asc. Fetch one row by id with {"_id": "<id>"}.', {
|
|
764
|
-
name:
|
|
765
|
-
table:
|
|
766
|
-
filters:
|
|
767
|
-
sort:
|
|
768
|
-
order:
|
|
769
|
-
limit:
|
|
770
|
-
offset:
|
|
771
|
-
fields:
|
|
772
|
-
count:
|
|
785
|
+
defineTool(server, "subgraphs_query", 'Query rows from a subgraph table (max 200 rows). Filters support operators: "amount.gte": "1000", "sender.neq": "SP...", "name.like": "%token%". Available operators: eq, neq, gt, gte, lt, lte, like. To TAIL new rows (no streaming over MCP): sort=_id, order=desc for the latest, then poll forward with the filter {"_id.gt": "<last _id seen>"}, order=asc. Fetch one row by id with {"_id": "<id>"}. Public subgraphs are also keyless over HTTP at GET /v1/subgraphs/<name>/<table> — { rows, next_cursor, tip } envelope, resume with ?cursor=<next_cursor> + _order=asc|desc (no _offset/_sort on /v1); hand that URL to third parties.', {
|
|
786
|
+
name: z7.string().describe("Subgraph name"),
|
|
787
|
+
table: z7.string().describe("Table name"),
|
|
788
|
+
filters: z7.record(z7.string(), z7.string()).optional().describe('Column filters — plain values or with operators (e.g. {"amount.gte": "1000", "sender": "SP..."})'),
|
|
789
|
+
sort: z7.string().optional().describe("Column to sort by"),
|
|
790
|
+
order: z7.enum(["asc", "desc"]).optional().describe("Sort order"),
|
|
791
|
+
limit: z7.number().max(200).optional().describe("Max rows (default 50, max 200)"),
|
|
792
|
+
offset: z7.number().optional().describe("Offset for pagination"),
|
|
793
|
+
fields: z7.string().optional().describe('Comma-separated column list to return (e.g. "sender,amount")'),
|
|
794
|
+
count: z7.boolean().optional().describe("If true, return row count instead of rows")
|
|
773
795
|
}, async ({
|
|
774
796
|
name,
|
|
775
797
|
table,
|
|
@@ -802,14 +824,14 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
802
824
|
};
|
|
803
825
|
});
|
|
804
826
|
defineTool(server, "subgraphs_aggregate", `Compute scalar aggregates over a subgraph table's filtered rows. Supports count, countDistinct, and sum/min/max (numeric columns only — uint/int plus the system _block_height). Filters use the same grammar as subgraphs_query (e.g. {"amount.gte": "1000"}). sum/min/max come back as lossless strings; counts as numbers. With no aggregate requested, returns the row count.`, {
|
|
805
|
-
name:
|
|
806
|
-
table:
|
|
807
|
-
filters:
|
|
808
|
-
count:
|
|
809
|
-
countDistinct:
|
|
810
|
-
sum:
|
|
811
|
-
min:
|
|
812
|
-
max:
|
|
827
|
+
name: z7.string().describe("Subgraph name"),
|
|
828
|
+
table: z7.string().describe("Table name"),
|
|
829
|
+
filters: z7.record(z7.string(), z7.string()).optional().describe('Column filters — plain values or with operators (e.g. {"amount.gte": "1000", "sender": "SP..."})'),
|
|
830
|
+
count: z7.boolean().optional().describe("Include COUNT(*) of matching rows"),
|
|
831
|
+
countDistinct: z7.array(z7.string()).optional().describe("Columns to count distinct values of"),
|
|
832
|
+
sum: z7.array(z7.string()).optional().describe("Numeric columns to sum (lossless string result)"),
|
|
833
|
+
min: z7.array(z7.string()).optional().describe("Numeric columns to take the minimum of"),
|
|
834
|
+
max: z7.array(z7.string()).optional().describe("Numeric columns to take the maximum of")
|
|
813
835
|
}, async ({ name, table, filters, count, countDistinct, sum, min, max }) => {
|
|
814
836
|
const result = await clientProvider().subgraphs.queryTableAggregate(name, table, { filters, count, countDistinct, sum, min, max });
|
|
815
837
|
return {
|
|
@@ -817,9 +839,9 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
817
839
|
};
|
|
818
840
|
});
|
|
819
841
|
defineTool(server, "subgraphs_reindex", "Reindex a subgraph from a specific block range. Returns an operationId — poll subgraphs_operation to track progress to completion.", {
|
|
820
|
-
name:
|
|
821
|
-
fromBlock:
|
|
822
|
-
toBlock:
|
|
842
|
+
name: z7.string().describe("Subgraph name"),
|
|
843
|
+
fromBlock: z7.number().optional().describe("Start block (defaults to beginning)"),
|
|
844
|
+
toBlock: z7.number().optional().describe("End block (defaults to latest)")
|
|
823
845
|
}, async ({ name, fromBlock, toBlock }) => {
|
|
824
846
|
const result = await clientProvider().subgraphs.reindex(name, {
|
|
825
847
|
fromBlock,
|
|
@@ -830,8 +852,8 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
830
852
|
};
|
|
831
853
|
});
|
|
832
854
|
defineTool(server, "subgraphs_operation", "Check reindex/backfill progress. With operationId, returns that operation's status (poll until status is completed/failed/cancelled); without it, lists recent operations for the subgraph.", {
|
|
833
|
-
name:
|
|
834
|
-
operationId:
|
|
855
|
+
name: z7.string().describe("Subgraph name"),
|
|
856
|
+
operationId: z7.string().optional().describe("Operation id from reindex/backfill/stop; omit to list recent operations")
|
|
835
857
|
}, async ({ name, operationId }) => {
|
|
836
858
|
const result = operationId ? await clientProvider().subgraphs.getOperation(name, operationId) : await clientProvider().subgraphs.operations(name);
|
|
837
859
|
return {
|
|
@@ -839,9 +861,9 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
839
861
|
};
|
|
840
862
|
});
|
|
841
863
|
defineTool(server, "subgraphs_backfill", "Backfill a subgraph over a block range. Non-destructive forward fill (does not drop existing data) — unlike subgraphs_reindex, and the only data-fill path for BYO subgraphs (reindex is blocked there). Both blocks required. Returns an operationId — poll subgraphs_operation to track progress.", {
|
|
842
|
-
name:
|
|
843
|
-
fromBlock:
|
|
844
|
-
toBlock:
|
|
864
|
+
name: z7.string().describe("Subgraph name"),
|
|
865
|
+
fromBlock: z7.number().int().nonnegative().describe("Start block (inclusive)"),
|
|
866
|
+
toBlock: z7.number().int().nonnegative().describe("End block (inclusive)")
|
|
845
867
|
}, async ({ name, fromBlock, toBlock }) => {
|
|
846
868
|
const result = await clientProvider().subgraphs.backfill(name, {
|
|
847
869
|
fromBlock,
|
|
@@ -851,17 +873,17 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
851
873
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
852
874
|
};
|
|
853
875
|
});
|
|
854
|
-
defineTool(server, "subgraphs_stop", "Cancel an in-flight reindex or backfill operation for a subgraph. Returns the stop request status; poll subgraphs_operation to confirm it reaches a terminal state.", { name:
|
|
876
|
+
defineTool(server, "subgraphs_stop", "Cancel an in-flight reindex or backfill operation for a subgraph. Returns the stop request status; poll subgraphs_operation to confirm it reaches a terminal state.", { name: z7.string().describe("Subgraph name") }, async ({ name }) => {
|
|
855
877
|
const result = await clientProvider().subgraphs.stop(name);
|
|
856
878
|
return {
|
|
857
879
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
858
880
|
};
|
|
859
881
|
});
|
|
860
882
|
defineTool(server, "subgraphs_gaps", "List indexing gaps (missing block ranges) for a subgraph. Each gap reports start/end/size, reason, and detected/resolved timestamps. Feed an unresolved gap's range into subgraphs_backfill to fill it. Defaults to unresolved gaps.", {
|
|
861
|
-
name:
|
|
862
|
-
limit:
|
|
863
|
-
offset:
|
|
864
|
-
resolved:
|
|
883
|
+
name: z7.string().describe("Subgraph name"),
|
|
884
|
+
limit: z7.number().int().positive().optional().describe("Max gaps to return"),
|
|
885
|
+
offset: z7.number().int().nonnegative().optional().describe("Pagination offset"),
|
|
886
|
+
resolved: z7.boolean().optional().describe("Filter by resolved state (omit for unresolved only)")
|
|
865
887
|
}, async ({ name, limit, offset, resolved }) => {
|
|
866
888
|
const result = await clientProvider().subgraphs.gaps(name, {
|
|
867
889
|
limit,
|
|
@@ -872,16 +894,17 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
872
894
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
873
895
|
};
|
|
874
896
|
});
|
|
875
|
-
defineTool(server, "subgraphs_delete", "Delete a subgraph permanently.", { name:
|
|
897
|
+
defineTool(server, "subgraphs_delete", "Delete a subgraph permanently.", { name: z7.string().describe("Subgraph name") }, async ({ name }) => {
|
|
876
898
|
const result = await clientProvider().subgraphs.delete(name);
|
|
877
899
|
return { content: [{ type: "text", text: result.message }] };
|
|
878
900
|
});
|
|
879
|
-
defineTool(server, "subgraphs_deploy", "Deploy a subgraph from TypeScript code. Pass the full defineSubgraph() source — it will be bundled, validated, and deployed. Optional startBlock overrides the source definition for this deploy. Set dryRun to validate and preview the schema/DDL without writing anything. Set databaseUrl to deploy to your own Postgres (BYO data plane) — the server verifies the connection first; with dryRun it returns the DDL + grant script. A breaking BYO schema change is refused and returns a migration plan (drop + rebuild DDL) instead of deploying. Call `subgraphs_reindex` separately if you need a forced reindex.", {
|
|
880
|
-
code:
|
|
881
|
-
startBlock:
|
|
882
|
-
databaseUrl:
|
|
883
|
-
dryRun:
|
|
884
|
-
|
|
901
|
+
defineTool(server, "subgraphs_deploy", "Deploy a subgraph from TypeScript code. Pass the full defineSubgraph() source — it will be bundled, validated, and deployed. Optional startBlock overrides the source definition for this deploy. Set dryRun to validate and preview the schema/DDL without writing anything. Set databaseUrl to deploy to your own Postgres (BYO data plane) — the server verifies the connection first; with dryRun it returns the DDL + grant script. A breaking BYO schema change is refused and returns a migration plan (drop + rebuild DDL) instead of deploying. Visibility defaults: managed deploys are public (anon-readable at /v1/subgraphs/<name>, name claimed in the global public namespace), BYO deploys are private. Call `subgraphs_reindex` separately if you need a forced reindex.", {
|
|
902
|
+
code: z7.string().describe("TypeScript source code containing a defineSubgraph() call"),
|
|
903
|
+
startBlock: z7.number().int().nonnegative().optional().describe("Override the definition startBlock for this deploy"),
|
|
904
|
+
databaseUrl: z7.string().optional().describe("BYO data plane: Postgres connection string to host the subgraph's schema and rows in your own database"),
|
|
905
|
+
dryRun: z7.boolean().optional().describe("Validate and preview the deploy (schema/DDL, BYO connection) without writing changes"),
|
|
906
|
+
visibility: z7.enum(["public", "private"]).optional().describe("Read visibility: public = anon /v1 reads + global name claim; private = owning account's key only. Defaults: managed → public, BYO → private.")
|
|
907
|
+
}, async ({ code, startBlock, databaseUrl, dryRun, visibility }) => {
|
|
885
908
|
const bundled = await bundleSubgraphCode(code);
|
|
886
909
|
try {
|
|
887
910
|
const result = await clientProvider().subgraphs.deploy({
|
|
@@ -894,7 +917,8 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
894
917
|
sourceCode: code,
|
|
895
918
|
...startBlock !== undefined ? { startBlock } : {},
|
|
896
919
|
...databaseUrl !== undefined ? { databaseUrl } : {},
|
|
897
|
-
...dryRun !== undefined ? { dryRun } : {}
|
|
920
|
+
...dryRun !== undefined ? { dryRun } : {},
|
|
921
|
+
...visibility !== undefined ? { visibility } : {}
|
|
898
922
|
});
|
|
899
923
|
return {
|
|
900
924
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
@@ -913,17 +937,29 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
913
937
|
throw err;
|
|
914
938
|
}
|
|
915
939
|
});
|
|
916
|
-
defineTool(server, "
|
|
940
|
+
defineTool(server, "subgraphs_publish", "Make a subgraph publicly readable at /v1/subgraphs/<name> — anyone (or any agent) can read it without a key. Claims the name in the global public namespace; fails with PUBLIC_NAME_TAKEN if another account holds it.", { name: z7.string().describe("Subgraph name") }, async ({ name }) => {
|
|
941
|
+
const result = await clientProvider().subgraphs.publish(name);
|
|
942
|
+
return {
|
|
943
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
944
|
+
};
|
|
945
|
+
});
|
|
946
|
+
defineTool(server, "subgraphs_unpublish", "Make a subgraph private again — /v1 reads then require the owning account's bearer key, and the global public name claim is released.", { name: z7.string().describe("Subgraph name") }, async ({ name }) => {
|
|
947
|
+
const result = await clientProvider().subgraphs.unpublish(name);
|
|
948
|
+
return {
|
|
949
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
950
|
+
};
|
|
951
|
+
});
|
|
952
|
+
defineTool(server, "subgraphs_read_source", "Fetch the deployed TypeScript source of a subgraph (plus its stored version). Returns a readOnly payload for subgraphs deployed before source capture — in that case the caller should redeploy via CLI before editing.", { name: z7.string().describe("Subgraph name") }, async ({ name }) => {
|
|
917
953
|
const source = await clientProvider().subgraphs.getSource(name);
|
|
918
954
|
return {
|
|
919
955
|
content: [{ type: "text", text: JSON.stringify(source, null, 2) }]
|
|
920
956
|
};
|
|
921
957
|
});
|
|
922
958
|
defineTool(server, "subgraphs_codegen", "Generate a typed ORM schema (Prisma, Drizzle, or Kysely) for a subgraph's tables so they can be queried from a BYO database. Pass either `code` (defineSubgraph source) or `name` (a deployed subgraph — its captured source is used). Returns the schema as text.", {
|
|
923
|
-
code:
|
|
924
|
-
name:
|
|
925
|
-
target:
|
|
926
|
-
schemaName:
|
|
959
|
+
code: z7.string().optional().describe("defineSubgraph() source (mutually exclusive with name)"),
|
|
960
|
+
name: z7.string().optional().describe("Deployed subgraph name (mutually exclusive with code)"),
|
|
961
|
+
target: z7.enum(["prisma", "drizzle", "kysely"]).optional().describe("ORM target (default prisma)"),
|
|
962
|
+
schemaName: z7.string().optional().describe("Postgres schema name (defaults to subgraph_<name>)")
|
|
927
963
|
}, async ({ code, name, target = "prisma", schemaName }) => {
|
|
928
964
|
if (code && name || !code && !name) {
|
|
929
965
|
throw new Error("Provide exactly one of `code` or `name`.");
|
|
@@ -952,7 +988,7 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
952
988
|
|
|
953
989
|
// src/tools/subscriptions.ts
|
|
954
990
|
import { CHAIN_TRIGGER_TYPES } from "@secondlayer/shared";
|
|
955
|
-
import { z as
|
|
991
|
+
import { z as z8 } from "zod/v4";
|
|
956
992
|
function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
957
993
|
defineTool(server, "subscriptions_list", "List all subscriptions for the current account. Returns summary fields (no secrets).", {}, async () => {
|
|
958
994
|
const { data } = await clientProvider().subscriptions.list();
|
|
@@ -960,34 +996,34 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
|
960
996
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
961
997
|
};
|
|
962
998
|
});
|
|
963
|
-
defineTool(server, "subscriptions_get", "Get full detail for a subscription (filter, auth, retry config, circuit state).", { id:
|
|
999
|
+
defineTool(server, "subscriptions_get", "Get full detail for a subscription (filter, auth, retry config, circuit state).", { id: z8.string().describe("Subscription id") }, async ({ id }) => {
|
|
964
1000
|
const detail = await clientProvider().subscriptions.get(id);
|
|
965
1001
|
return {
|
|
966
1002
|
content: [{ type: "text", text: JSON.stringify(detail, null, 2) }]
|
|
967
1003
|
};
|
|
968
1004
|
});
|
|
969
1005
|
defineTool(server, "subscriptions_create", "Create a subscription. Two kinds (mutually exclusive): a SUBGRAPH subscription fires on a subgraph table's rows (set subgraphName + tableName + optional filter); a CHAIN subscription fires on raw chain events with no subgraph (set triggers). Returns `signingSecret` ONCE — forward it to the user so they can wire it into their receiver.", {
|
|
970
|
-
name:
|
|
971
|
-
subgraphName:
|
|
972
|
-
tableName:
|
|
973
|
-
triggers:
|
|
974
|
-
type:
|
|
975
|
-
contractId:
|
|
976
|
-
functionName:
|
|
977
|
-
caller:
|
|
978
|
-
sender:
|
|
979
|
-
recipient:
|
|
980
|
-
assetIdentifier:
|
|
981
|
-
deployer:
|
|
982
|
-
contractName:
|
|
983
|
-
topic:
|
|
984
|
-
lockedAddress:
|
|
985
|
-
trait:
|
|
986
|
-
minAmount:
|
|
987
|
-
maxAmount:
|
|
1006
|
+
name: z8.string().describe("Human-readable name, unique per account"),
|
|
1007
|
+
subgraphName: z8.string().optional().describe("Subgraph to subscribe to (subgraph subscription)"),
|
|
1008
|
+
tableName: z8.string().optional().describe("Table within the subgraph (subgraph subscription)"),
|
|
1009
|
+
triggers: z8.array(z8.object({
|
|
1010
|
+
type: z8.enum(CHAIN_TRIGGER_TYPES),
|
|
1011
|
+
contractId: z8.string().optional(),
|
|
1012
|
+
functionName: z8.string().optional(),
|
|
1013
|
+
caller: z8.string().optional(),
|
|
1014
|
+
sender: z8.string().optional(),
|
|
1015
|
+
recipient: z8.string().optional(),
|
|
1016
|
+
assetIdentifier: z8.string().optional(),
|
|
1017
|
+
deployer: z8.string().optional(),
|
|
1018
|
+
contractName: z8.string().optional(),
|
|
1019
|
+
topic: z8.string().optional(),
|
|
1020
|
+
lockedAddress: z8.string().optional(),
|
|
1021
|
+
trait: z8.string().optional(),
|
|
1022
|
+
minAmount: z8.union([z8.string(), z8.number()]).optional(),
|
|
1023
|
+
maxAmount: z8.union([z8.string(), z8.number()]).optional()
|
|
988
1024
|
})).optional().describe("Chain triggers (chain subscription) — provide INSTEAD of subgraphName/tableName. Each targets a raw chain event/tx; string fields accept `*` wildcards, `trait` scopes to a SIP/trait. Per-type accepted fields: see the secondlayer://chain-triggers resource. Forward-looking: starts at chain tip, no backfill."),
|
|
989
|
-
url:
|
|
990
|
-
format:
|
|
1025
|
+
url: z8.string().describe("Webhook URL"),
|
|
1026
|
+
format: z8.enum([
|
|
991
1027
|
"standard-webhooks",
|
|
992
1028
|
"inngest",
|
|
993
1029
|
"trigger",
|
|
@@ -995,9 +1031,9 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
|
995
1031
|
"cloudevents",
|
|
996
1032
|
"raw"
|
|
997
1033
|
]).optional().describe("Wire format (default standard-webhooks)"),
|
|
998
|
-
runtime:
|
|
999
|
-
filter:
|
|
1000
|
-
authConfig:
|
|
1034
|
+
runtime: z8.enum(["inngest", "trigger", "cloudflare", "node"]).optional().describe("Receiver runtime label (display only)"),
|
|
1035
|
+
filter: z8.record(z8.string(), z8.unknown()).optional().describe('Scalar filter DSL, e.g. {"amount": {"gte": 100}, "sender": "SP..."}'),
|
|
1036
|
+
authConfig: z8.record(z8.string(), z8.unknown()).optional().describe('Receiver auth sent with each delivery, e.g. {"type": "bearer", "token": "..."}')
|
|
1001
1037
|
}, async (input) => {
|
|
1002
1038
|
const res = await clientProvider().subscriptions.create(input);
|
|
1003
1039
|
return {
|
|
@@ -1005,12 +1041,12 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
|
1005
1041
|
};
|
|
1006
1042
|
});
|
|
1007
1043
|
defineTool(server, "subscriptions_update", "Patch a subscription (name, url, filter, authConfig, format, runtime, retry, timeout, concurrency).", {
|
|
1008
|
-
id:
|
|
1009
|
-
name:
|
|
1010
|
-
url:
|
|
1011
|
-
filter:
|
|
1012
|
-
authConfig:
|
|
1013
|
-
format:
|
|
1044
|
+
id: z8.string(),
|
|
1045
|
+
name: z8.string().optional().describe("Rename the subscription"),
|
|
1046
|
+
url: z8.string().optional(),
|
|
1047
|
+
filter: z8.record(z8.string(), z8.unknown()).optional(),
|
|
1048
|
+
authConfig: z8.record(z8.string(), z8.unknown()).optional().describe("Receiver auth sent with each delivery (bearer/etc.)"),
|
|
1049
|
+
format: z8.enum([
|
|
1014
1050
|
"standard-webhooks",
|
|
1015
1051
|
"inngest",
|
|
1016
1052
|
"trigger",
|
|
@@ -1018,51 +1054,51 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
|
1018
1054
|
"cloudevents",
|
|
1019
1055
|
"raw"
|
|
1020
1056
|
]).optional(),
|
|
1021
|
-
runtime:
|
|
1022
|
-
maxRetries:
|
|
1023
|
-
timeoutMs:
|
|
1024
|
-
concurrency:
|
|
1057
|
+
runtime: z8.enum(["inngest", "trigger", "cloudflare", "node"]).nullable().optional(),
|
|
1058
|
+
maxRetries: z8.number().int().min(0).optional(),
|
|
1059
|
+
timeoutMs: z8.number().int().min(100).optional(),
|
|
1060
|
+
concurrency: z8.number().int().min(1).optional()
|
|
1025
1061
|
}, async ({ id, ...patch }) => {
|
|
1026
1062
|
const res = await clientProvider().subscriptions.update(id, patch);
|
|
1027
1063
|
return {
|
|
1028
1064
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
1029
1065
|
};
|
|
1030
1066
|
});
|
|
1031
|
-
defineTool(server, "subscriptions_pause", "Pause a subscription. Pending rows remain queued until resumed.", { id:
|
|
1067
|
+
defineTool(server, "subscriptions_pause", "Pause a subscription. Pending rows remain queued until resumed.", { id: z8.string() }, async ({ id }) => {
|
|
1032
1068
|
const res = await clientProvider().subscriptions.pause(id);
|
|
1033
1069
|
return {
|
|
1034
1070
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
1035
1071
|
};
|
|
1036
1072
|
});
|
|
1037
|
-
defineTool(server, "subscriptions_resume", "Resume a paused or circuit-open subscription and reset circuit failures.", { id:
|
|
1073
|
+
defineTool(server, "subscriptions_resume", "Resume a paused or circuit-open subscription and reset circuit failures.", { id: z8.string() }, async ({ id }) => {
|
|
1038
1074
|
const res = await clientProvider().subscriptions.resume(id);
|
|
1039
1075
|
return {
|
|
1040
1076
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
1041
1077
|
};
|
|
1042
1078
|
});
|
|
1043
|
-
defineTool(server, "subscriptions_delete", "Delete a subscription. Pending outbox rows are cascade-deleted.", { id:
|
|
1079
|
+
defineTool(server, "subscriptions_delete", "Delete a subscription. Pending outbox rows are cascade-deleted.", { id: z8.string() }, async ({ id }) => {
|
|
1044
1080
|
const res = await clientProvider().subscriptions.delete(id);
|
|
1045
1081
|
return {
|
|
1046
1082
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
1047
1083
|
};
|
|
1048
1084
|
});
|
|
1049
|
-
defineTool(server, "subscriptions_rotate_secret", "Rotate a subscription signing secret. Returns the new plaintext secret once.", { id:
|
|
1085
|
+
defineTool(server, "subscriptions_rotate_secret", "Rotate a subscription signing secret. Returns the new plaintext secret once.", { id: z8.string() }, async ({ id }) => {
|
|
1050
1086
|
const res = await clientProvider().subscriptions.rotateSecret(id);
|
|
1051
1087
|
return {
|
|
1052
1088
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
1053
1089
|
};
|
|
1054
1090
|
});
|
|
1055
|
-
defineTool(server, "subscriptions_test", "Send a one-off test webhook to a subscription's URL (built for its format, SSRF-guarded). Logged as a delivery row — check subscriptions_recent_deliveries. Returns {ok, statusCode, error, durationMs, deliveryId}.", { id:
|
|
1091
|
+
defineTool(server, "subscriptions_test", "Send a one-off test webhook to a subscription's URL (built for its format, SSRF-guarded). Logged as a delivery row — check subscriptions_recent_deliveries. Returns {ok, statusCode, error, durationMs, deliveryId}.", { id: z8.string().describe("Subscription id") }, async ({ id }) => {
|
|
1056
1092
|
const res = await clientProvider().subscriptions.test(id);
|
|
1057
1093
|
return {
|
|
1058
1094
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
1059
1095
|
};
|
|
1060
1096
|
});
|
|
1061
1097
|
defineTool(server, "subscriptions_replay", "Replay a block range for a subscription. Replays run at 10% of batch capacity — use sparingly. Pass `force` (a short idempotency suffix) to re-run a range that was already replayed.", {
|
|
1062
|
-
id:
|
|
1063
|
-
fromBlock:
|
|
1064
|
-
toBlock:
|
|
1065
|
-
force:
|
|
1098
|
+
id: z8.string(),
|
|
1099
|
+
fromBlock: z8.number().int().nonnegative(),
|
|
1100
|
+
toBlock: z8.number().int().nonnegative(),
|
|
1101
|
+
force: z8.string().optional().describe("Idempotency suffix to force a duplicate replay of the range")
|
|
1066
1102
|
}, async ({ id, fromBlock, toBlock, force }) => {
|
|
1067
1103
|
const res = await clientProvider().subscriptions.replay(id, {
|
|
1068
1104
|
fromBlock,
|
|
@@ -1073,22 +1109,22 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
|
1073
1109
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
1074
1110
|
};
|
|
1075
1111
|
});
|
|
1076
|
-
defineTool(server, "subscriptions_dead", "Return the last 100 dead-letter outbox rows for a subscription.", { id:
|
|
1112
|
+
defineTool(server, "subscriptions_dead", "Return the last 100 dead-letter outbox rows for a subscription.", { id: z8.string() }, async ({ id }) => {
|
|
1077
1113
|
const { data } = await clientProvider().subscriptions.dead(id);
|
|
1078
1114
|
return {
|
|
1079
1115
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
1080
1116
|
};
|
|
1081
1117
|
});
|
|
1082
1118
|
defineTool(server, "subscriptions_requeue_dead", "Requeue one dead-letter outbox row for delivery retry.", {
|
|
1083
|
-
id:
|
|
1084
|
-
outboxId:
|
|
1119
|
+
id: z8.string(),
|
|
1120
|
+
outboxId: z8.string()
|
|
1085
1121
|
}, async ({ id, outboxId }) => {
|
|
1086
1122
|
const res = await clientProvider().subscriptions.requeueDead(id, outboxId);
|
|
1087
1123
|
return {
|
|
1088
1124
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
1089
1125
|
};
|
|
1090
1126
|
});
|
|
1091
|
-
defineTool(server, "subscriptions_recent_deliveries", "Return the last 100 delivery attempts (attempt #, status code, duration, truncated response).", { id:
|
|
1127
|
+
defineTool(server, "subscriptions_recent_deliveries", "Return the last 100 delivery attempts (attempt #, status code, duration, truncated response).", { id: z8.string() }, async ({ id }) => {
|
|
1092
1128
|
const { data } = await clientProvider().subscriptions.recentDeliveries(id);
|
|
1093
1129
|
return {
|
|
1094
1130
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
@@ -1109,7 +1145,6 @@ function createServer() {
|
|
|
1109
1145
|
registerSubscriptionTools(server);
|
|
1110
1146
|
registerAccountTools(server);
|
|
1111
1147
|
registerProjectTools(server);
|
|
1112
|
-
registerDatasetTools(server);
|
|
1113
1148
|
registerIndexTools(server);
|
|
1114
1149
|
registerStreamsTools(server);
|
|
1115
1150
|
registerContractTools(server);
|
|
@@ -1203,5 +1238,5 @@ httpServer.listen(port, () => {
|
|
|
1203
1238
|
console.error("Warning: SECONDLAYER_MCP_SECRET not set, authentication disabled");
|
|
1204
1239
|
});
|
|
1205
1240
|
|
|
1206
|
-
//# debugId=
|
|
1241
|
+
//# debugId=C1AFC98747A5C42164756E2164756E21
|
|
1207
1242
|
//# sourceMappingURL=bin-http.js.map
|