@secondlayer/mcp 3.2.0 → 3.3.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/dist/index.js CHANGED
@@ -67,6 +67,34 @@ function jsonResponse(data, isError) {
67
67
  };
68
68
  }
69
69
 
70
+ // src/lib/tool.ts
71
+ var registeredToolNames = new Set;
72
+ function getRegisteredToolNames() {
73
+ return [...registeredToolNames];
74
+ }
75
+ function defineTool(server, name, description, schema, handler) {
76
+ const wrappedHandler = async (args) => {
77
+ try {
78
+ return await handler(args);
79
+ } catch (err) {
80
+ const message = err instanceof Error ? err.message : String(err);
81
+ const status = err instanceof Error && "status" in err ? err.status : 0;
82
+ const type = status === 401 ? "unauthorized" : status === 404 ? "not_found" : status === 429 ? "rate_limited" : status >= 500 ? "server_error" : "error";
83
+ return {
84
+ content: [
85
+ {
86
+ type: "text",
87
+ text: JSON.stringify({ error: { type, status, message } })
88
+ }
89
+ ],
90
+ isError: true
91
+ };
92
+ }
93
+ };
94
+ registeredToolNames.add(name);
95
+ server.tool(name, description, schema, wrappedHandler);
96
+ }
97
+
70
98
  // src/resources.ts
71
99
  var FILTERS_REFERENCE = [
72
100
  {
@@ -122,39 +150,69 @@ var COLUMN_TYPES = [
122
150
  description: "Column options: nullable allows NULL, indexed creates a B-tree index, search enables full-text search"
123
151
  }
124
152
  ];
125
- var CAPABILITIES = {
126
- products: [
127
- "datasets public foundation datasets (datasets_list, datasets_query)",
128
- "index decoded L2 events + contract calls (index_ft_transfers, index_nft_transfers, index_events, index_contract_calls)",
129
- "streams raw chain event firehose (streams_tip, streams_events)",
130
- "contracts trait-based contract discovery (contracts_find)",
131
- "subgraphs author/deploy/query custom indexes (subgraphs_deploy, subgraphs_query, subgraphs_list, subgraphs_get, subgraphs_reindex, subgraphs_delete)",
132
- "subscriptions — webhook delivery of subgraph rows (subscriptions_create, subscriptions_list, subscriptions_update, …)",
133
- "account identity + plan (account_whoami)"
134
- ],
135
- discoverFirst: "Call datasets_list / contracts_find to learn what exists before querying."
153
+ var PRODUCT_BLURBS = {
154
+ datasets: "public foundation datasets",
155
+ index: "decoded L2 events, contract calls, blocks, transactions, stacking, mempool",
156
+ streams: "raw canonical chain event firehose",
157
+ contracts: "trait-based contract discovery",
158
+ subgraphs: "author/deploy/query custom indexes",
159
+ subscriptions: "webhook delivery on subgraph rows or raw chain events",
160
+ account: "identity, plan, billing, and API keys",
161
+ scaffold: "generate typed contract clients from a deployment or ABI"
136
162
  };
163
+ var PRODUCT_ORDER = [
164
+ "datasets",
165
+ "index",
166
+ "streams",
167
+ "contracts",
168
+ "subgraphs",
169
+ "subscriptions",
170
+ "account",
171
+ "scaffold"
172
+ ];
173
+ function buildCapabilities() {
174
+ const byPrefix = new Map;
175
+ for (const name of getRegisteredToolNames()) {
176
+ const prefix = name.slice(0, name.indexOf("_"));
177
+ const tools = byPrefix.get(prefix) ?? [];
178
+ tools.push(name);
179
+ byPrefix.set(prefix, tools);
180
+ }
181
+ const order = [
182
+ ...PRODUCT_ORDER.filter((p) => byPrefix.has(p)),
183
+ ...[...byPrefix.keys()].filter((p) => !PRODUCT_ORDER.includes(p))
184
+ ];
185
+ const products = order.map((p) => {
186
+ const tools = byPrefix.get(p) ?? [];
187
+ const blurb = PRODUCT_BLURBS[p];
188
+ return blurb ? `${p} — ${blurb} (${tools.join(", ")})` : `${p} (${tools.join(", ")})`;
189
+ });
190
+ return {
191
+ products,
192
+ discoverFirst: "Call datasets_list / contracts_find to learn what exists before querying."
193
+ };
194
+ }
137
195
  var READ_AUTH_TIERS = {
138
196
  datasets: "open — no API key required",
139
197
  index: "anonymous reads allowed; free-tier API keys are rejected (Build+ required)",
140
198
  streams: "API key required (SL_API_KEY) — keyless calls return 401",
141
199
  subgraphs: "reads public during open beta; writes require an API key"
142
200
  };
143
- async function buildContext(deps = {
144
- clientProvider: getClient,
145
- accountRequest: () => apiRequest("GET", "/api/accounts/me")
146
- }) {
201
+ async function buildContext(deps = { clientProvider: getClient }) {
147
202
  const unavailable = "unavailable: set SL_API_KEY";
148
- const subgraphs = await deps.clientProvider().subgraphs.list().then((r) => r.data.map(formatSubgraphSummary)).catch(() => unavailable);
149
- const subscriptions = await deps.clientProvider().subscriptions.list().then((r) => ({
150
- count: r.data.length,
151
- statuses: r.data.map((s) => s.status)
152
- })).catch(() => unavailable);
153
- const account = await deps.accountRequest().catch(() => unavailable);
203
+ const orNull = (v) => v == null ? unavailable : v;
204
+ const snap = await deps.clientProvider().context().catch(() => null);
154
205
  return {
155
206
  authState: { apiKeySet: Boolean(process.env.SL_API_KEY) },
156
- whatExists: { subgraphs, subscriptions, account },
157
- whatYouCanDo: CAPABILITIES,
207
+ whatExists: {
208
+ account: orNull(snap?.account),
209
+ streamsTip: orNull(snap?.streamsTip),
210
+ indexTip: orNull(snap?.indexTip),
211
+ subgraphs: snap?.subgraphs ? snap.subgraphs.map(formatSubgraphSummary) : unavailable,
212
+ subscriptions: orNull(snap?.subscriptions),
213
+ activeOperations: orNull(snap?.activeOperations)
214
+ },
215
+ whatYouCanDo: buildCapabilities(),
158
216
  readAuthTiers: READ_AUTH_TIERS
159
217
  };
160
218
  }
@@ -192,31 +250,6 @@ function registerResources(server) {
192
250
 
193
251
  // src/tools/account.ts
194
252
  import { z } from "zod/v4";
195
-
196
- // src/lib/tool.ts
197
- function defineTool(server, name, description, schema, handler) {
198
- const wrappedHandler = async (args) => {
199
- try {
200
- return await handler(args);
201
- } catch (err) {
202
- const message = err instanceof Error ? err.message : String(err);
203
- const status = err instanceof Error && "status" in err ? err.status : 0;
204
- const type = status === 401 ? "unauthorized" : status === 404 ? "not_found" : status === 429 ? "rate_limited" : status >= 500 ? "server_error" : "error";
205
- return {
206
- content: [
207
- {
208
- type: "text",
209
- text: JSON.stringify({ error: { type, status, message } })
210
- }
211
- ],
212
- isError: true
213
- };
214
- }
215
- };
216
- server.tool(name, description, schema, wrappedHandler);
217
- }
218
-
219
- // src/tools/account.ts
220
253
  function registerAccountTools(server) {
221
254
  defineTool(server, "account_whoami", "Show the authenticated account's email and plan.", {}, async () => {
222
255
  const result = await apiRequest("GET", "/api/accounts/me");
@@ -241,6 +274,10 @@ function registerAccountTools(server) {
241
274
  const result = await apiRequest("GET", "/api/billing/status");
242
275
  return jsonResponse(result);
243
276
  });
277
+ defineTool(server, "account_create_key", "Mint a scoped streams/index read API key so the agent can self-provision access. Requires an account-level (owner) API key. The returned `key` is shown ONCE — forward it to the user to set as SL_API_KEY.", {
278
+ product: z.enum(["streams", "index"]).optional().describe("Key scope (default streams)"),
279
+ name: z.string().optional().describe("Optional label for the key")
280
+ }, async ({ product, name }) => jsonResponse(await getClient().apiKeys.create({ product, name })));
244
281
  }
245
282
 
246
283
  // src/tools/contracts.ts
@@ -279,20 +316,9 @@ function registerDatasetTools(server, clientProvider = getClient) {
279
316
  }
280
317
 
281
318
  // src/tools/index.ts
319
+ import { DECODED_EVENT_TYPES } from "@secondlayer/shared";
282
320
  import { z as z4 } from "zod/v4";
283
- var INDEX_EVENT_TYPES = [
284
- "ft_transfer",
285
- "nft_transfer",
286
- "stx_transfer",
287
- "stx_mint",
288
- "stx_burn",
289
- "stx_lock",
290
- "ft_mint",
291
- "ft_burn",
292
- "nft_mint",
293
- "nft_burn",
294
- "print"
295
- ];
321
+ var INDEX_EVENT_TYPES = DECODED_EVENT_TYPES;
296
322
  var rangeFilters = {
297
323
  contractId: z4.string().optional().describe("Filter by contract id"),
298
324
  fromHeight: z4.number().optional().describe("Start block height (inclusive)"),
@@ -300,6 +326,13 @@ var rangeFilters = {
300
326
  cursor: z4.string().optional().describe("Opaque cursor from a prior response's next_cursor"),
301
327
  limit: z4.number().optional().describe("Max rows for this page")
302
328
  };
329
+ var heightFilters = {
330
+ fromHeight: rangeFilters.fromHeight,
331
+ toHeight: rangeFilters.toHeight,
332
+ cursor: rangeFilters.cursor,
333
+ limit: rangeFilters.limit
334
+ };
335
+ var notFound = (message) => jsonResponse({ error: { type: "not_found", status: 404, message } }, true);
303
336
  function registerIndexTools(server, clientProvider = getClient) {
304
337
  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).", {
305
338
  ...rangeFilters,
@@ -324,6 +357,41 @@ function registerIndexTools(server, clientProvider = getClient) {
324
357
  functionName: z4.string().optional().describe("Filter by called function name"),
325
358
  sender: z4.string().optional().describe("Filter by caller principal")
326
359
  }, async (params) => jsonResponse(await clientProvider().index.contractCalls.list(params)));
360
+ 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)));
361
+ 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)));
362
+ defineTool(server, "index_block", "Get a single block from the Index by height or block hash. Returns not_found if unknown.", {
363
+ ref: z4.string().describe("Block height (digits) or block hash (0x… string)")
364
+ }, async ({ ref }) => {
365
+ const block = await clientProvider().index.blocks.get(/^\d+$/.test(ref) ? Number(ref) : ref);
366
+ return block ? jsonResponse(block) : notFound(`No block for ref ${ref}`);
367
+ });
368
+ defineTool(server, "index_transactions", "List decoded transactions from the Index. Filter by type, sender, or contract. Anonymous reads allowed (free-tier keys rejected).", {
369
+ ...rangeFilters,
370
+ type: z4.string().optional().describe("Filter by transaction type"),
371
+ sender: z4.string().optional().describe("Filter by sender principal")
372
+ }, async (params) => jsonResponse(await clientProvider().index.transactions.list(params)));
373
+ defineTool(server, "index_transaction", "Get a single transaction from the Index by tx_id. Returns not_found if unknown.", { txId: z4.string().describe("Transaction id (0x… hash)") }, async ({ txId }) => {
374
+ const tx = await clientProvider().index.transactions.get(txId);
375
+ return tx ? jsonResponse(tx) : notFound(`No transaction for ${txId}`);
376
+ });
377
+ 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).", {
378
+ ...heightFilters,
379
+ functionName: z4.string().optional().describe("Filter by PoX function name"),
380
+ stacker: z4.string().optional().describe("Filter by stacker principal"),
381
+ caller: z4.string().optional().describe("Filter by caller principal")
382
+ }, async (params) => jsonResponse(await clientProvider().index.stacking.list(params)));
383
+ 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).", {
384
+ sender: z4.string().optional().describe("Filter by sender principal"),
385
+ type: z4.string().optional().describe("Filter by transaction type"),
386
+ contractId: z4.string().optional().describe("Filter to pending calls to a single contract"),
387
+ cursor: z4.string().optional().describe("Opaque cursor from a prior response's next_cursor"),
388
+ limit: z4.number().optional().describe("Max rows for this page")
389
+ }, async (params) => jsonResponse(await clientProvider().index.mempool.list(params)));
390
+ 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: z4.string().describe("Transaction id (0x… hash)") }, async ({ txId }) => {
391
+ const tx = await clientProvider().index.mempool.get(txId);
392
+ return tx ? jsonResponse(tx) : notFound(`No pending tx for ${txId}`);
393
+ });
394
+ 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()));
327
395
  }
328
396
 
329
397
  // src/tools/scaffold.ts
@@ -375,20 +443,9 @@ function registerScaffoldTools(server) {
375
443
 
376
444
  // src/tools/streams.ts
377
445
  import { AuthError } from "@secondlayer/sdk";
446
+ import { DECODED_EVENT_TYPES as DECODED_EVENT_TYPES2 } from "@secondlayer/shared";
378
447
  import { z as z6 } from "zod/v4";
379
- var STREAMS_EVENT_TYPES = [
380
- "stx_transfer",
381
- "stx_mint",
382
- "stx_burn",
383
- "stx_lock",
384
- "ft_transfer",
385
- "ft_mint",
386
- "ft_burn",
387
- "nft_transfer",
388
- "nft_mint",
389
- "nft_burn",
390
- "print"
391
- ];
448
+ var STREAMS_EVENT_TYPES = DECODED_EVENT_TYPES2;
392
449
  async function withStreamsAuthHint(fn) {
393
450
  try {
394
451
  return await fn();
@@ -408,11 +465,21 @@ function registerStreamsTools(server, clientProvider = getClient) {
408
465
  sender: z6.string().optional().describe("Filter by sender principal"),
409
466
  recipient: z6.string().optional().describe("Filter by recipient principal"),
410
467
  assetIdentifier: z6.string().optional().describe("Filter by asset identifier"),
411
- fromBlock: z6.number().optional().describe("Start block (inclusive)"),
412
- toBlock: z6.number().optional().describe("End block (inclusive)"),
468
+ fromHeight: z6.number().optional().describe("Start block height (inclusive)"),
469
+ toHeight: z6.number().optional().describe("End block height (inclusive)"),
413
470
  cursor: z6.string().optional().describe("Opaque cursor from a prior response"),
414
471
  limit: z6.number().optional().describe("Max events for this page")
415
472
  }, async (params) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.events.list(params))));
473
+ 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))));
474
+ 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).", {
475
+ heightOrHash: z6.string().describe("Block height (digits) or block hash (0x… string)")
476
+ }, async ({ heightOrHash }) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.blocks.events(/^\d+$/.test(heightOrHash) ? Number(heightOrHash) : heightOrHash))));
477
+ defineTool(server, "streams_reorgs", "List chain reorgs observed by Streams since a cursor. Streams requires an API key (SL_API_KEY).", {
478
+ since: z6.string().describe("Cursor to list reorgs since (block:index or ISO timestamp)"),
479
+ limit: z6.number().optional().describe("Max reorgs to return")
480
+ }, async (params) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.reorgs.list(params))));
481
+ 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))));
482
+ 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())));
416
483
  }
417
484
 
418
485
  // src/tools/subgraphs.ts
@@ -493,7 +560,7 @@ function registerSubgraphTools(server, clientProvider = getClient) {
493
560
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
494
561
  };
495
562
  });
496
- defineTool(server, "subgraphs_reindex", "Reindex a subgraph from a specific block range.", {
563
+ defineTool(server, "subgraphs_reindex", "Reindex a subgraph from a specific block range. Returns an operationId — poll subgraphs_operation to track progress to completion.", {
497
564
  name: z7.string().describe("Subgraph name"),
498
565
  fromBlock: z7.number().optional().describe("Start block (defaults to beginning)"),
499
566
  toBlock: z7.number().optional().describe("End block (defaults to latest)")
@@ -506,6 +573,15 @@ function registerSubgraphTools(server, clientProvider = getClient) {
506
573
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
507
574
  };
508
575
  });
576
+ 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.", {
577
+ name: z7.string().describe("Subgraph name"),
578
+ operationId: z7.string().optional().describe("Operation id from reindex/backfill/stop; omit to list recent operations")
579
+ }, async ({ name, operationId }) => {
580
+ const result = operationId ? await clientProvider().subgraphs.getOperation(name, operationId) : await clientProvider().subgraphs.operations(name);
581
+ return {
582
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
583
+ };
584
+ });
509
585
  defineTool(server, "subgraphs_delete", "Delete a subgraph permanently.", { name: z7.string().describe("Subgraph name") }, async ({ name }) => {
510
586
  const result = await clientProvider().subgraphs.delete(name);
511
587
  return { content: [{ type: "text", text: result.message }] };
@@ -538,6 +614,7 @@ function registerSubgraphTools(server, clientProvider = getClient) {
538
614
  }
539
615
 
540
616
  // src/tools/subscriptions.ts
617
+ import { CHAIN_TRIGGER_TYPES } from "@secondlayer/shared";
541
618
  import { z as z8 } from "zod/v4";
542
619
  function registerSubscriptionTools(server, clientProvider = getClient) {
543
620
  defineTool(server, "subscriptions_list", "List all subscriptions for the current account. Returns summary fields (no secrets).", {}, async () => {
@@ -557,21 +634,7 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
557
634
  subgraphName: z8.string().optional().describe("Subgraph to subscribe to (subgraph subscription)"),
558
635
  tableName: z8.string().optional().describe("Table within the subgraph (subgraph subscription)"),
559
636
  triggers: z8.array(z8.object({
560
- type: z8.enum([
561
- "stx_transfer",
562
- "stx_mint",
563
- "stx_burn",
564
- "stx_lock",
565
- "ft_transfer",
566
- "ft_mint",
567
- "ft_burn",
568
- "nft_transfer",
569
- "nft_mint",
570
- "nft_burn",
571
- "contract_call",
572
- "contract_deploy",
573
- "print_event"
574
- ]),
637
+ type: z8.enum(CHAIN_TRIGGER_TYPES),
575
638
  contractId: z8.string().optional(),
576
639
  functionName: z8.string().optional(),
577
640
  caller: z8.string().optional(),
@@ -708,5 +771,5 @@ export {
708
771
  createServer
709
772
  };
710
773
 
711
- //# debugId=CEA79D88A41C6E0464756E2164756E21
774
+ //# debugId=49F00B0EF2B27D3964756E2164756E21
712
775
  //# sourceMappingURL=index.js.map