@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/bin-http.js CHANGED
@@ -75,6 +75,34 @@ function jsonResponse(data, isError) {
75
75
  };
76
76
  }
77
77
 
78
+ // src/lib/tool.ts
79
+ var registeredToolNames = new Set;
80
+ function getRegisteredToolNames() {
81
+ return [...registeredToolNames];
82
+ }
83
+ function defineTool(server, name, description, schema, handler) {
84
+ const wrappedHandler = async (args) => {
85
+ try {
86
+ return await handler(args);
87
+ } catch (err) {
88
+ const message = err instanceof Error ? err.message : String(err);
89
+ const status = err instanceof Error && "status" in err ? err.status : 0;
90
+ const type = status === 401 ? "unauthorized" : status === 404 ? "not_found" : status === 429 ? "rate_limited" : status >= 500 ? "server_error" : "error";
91
+ return {
92
+ content: [
93
+ {
94
+ type: "text",
95
+ text: JSON.stringify({ error: { type, status, message } })
96
+ }
97
+ ],
98
+ isError: true
99
+ };
100
+ }
101
+ };
102
+ registeredToolNames.add(name);
103
+ server.tool(name, description, schema, wrappedHandler);
104
+ }
105
+
78
106
  // src/resources.ts
79
107
  var FILTERS_REFERENCE = [
80
108
  {
@@ -130,39 +158,69 @@ var COLUMN_TYPES = [
130
158
  description: "Column options: nullable allows NULL, indexed creates a B-tree index, search enables full-text search"
131
159
  }
132
160
  ];
133
- var CAPABILITIES = {
134
- products: [
135
- "datasets public foundation datasets (datasets_list, datasets_query)",
136
- "index decoded L2 events + contract calls (index_ft_transfers, index_nft_transfers, index_events, index_contract_calls)",
137
- "streams raw chain event firehose (streams_tip, streams_events)",
138
- "contracts trait-based contract discovery (contracts_find)",
139
- "subgraphs author/deploy/query custom indexes (subgraphs_deploy, subgraphs_query, subgraphs_list, subgraphs_get, subgraphs_reindex, subgraphs_delete)",
140
- "subscriptions — webhook delivery of subgraph rows (subscriptions_create, subscriptions_list, subscriptions_update, …)",
141
- "account identity + plan (account_whoami)"
142
- ],
143
- discoverFirst: "Call datasets_list / contracts_find to learn what exists before querying."
161
+ var PRODUCT_BLURBS = {
162
+ datasets: "public foundation datasets",
163
+ index: "decoded L2 events, contract calls, blocks, transactions, stacking, mempool",
164
+ streams: "raw canonical chain event firehose",
165
+ contracts: "trait-based contract discovery",
166
+ subgraphs: "author/deploy/query custom indexes",
167
+ subscriptions: "webhook delivery on subgraph rows or raw chain events",
168
+ account: "identity, plan, billing, and API keys",
169
+ scaffold: "generate typed contract clients from a deployment or ABI"
144
170
  };
171
+ var PRODUCT_ORDER = [
172
+ "datasets",
173
+ "index",
174
+ "streams",
175
+ "contracts",
176
+ "subgraphs",
177
+ "subscriptions",
178
+ "account",
179
+ "scaffold"
180
+ ];
181
+ function buildCapabilities() {
182
+ const byPrefix = new Map;
183
+ for (const name of getRegisteredToolNames()) {
184
+ const prefix = name.slice(0, name.indexOf("_"));
185
+ const tools = byPrefix.get(prefix) ?? [];
186
+ tools.push(name);
187
+ byPrefix.set(prefix, tools);
188
+ }
189
+ const order = [
190
+ ...PRODUCT_ORDER.filter((p) => byPrefix.has(p)),
191
+ ...[...byPrefix.keys()].filter((p) => !PRODUCT_ORDER.includes(p))
192
+ ];
193
+ const products = order.map((p) => {
194
+ const tools = byPrefix.get(p) ?? [];
195
+ const blurb = PRODUCT_BLURBS[p];
196
+ return blurb ? `${p} — ${blurb} (${tools.join(", ")})` : `${p} (${tools.join(", ")})`;
197
+ });
198
+ return {
199
+ products,
200
+ discoverFirst: "Call datasets_list / contracts_find to learn what exists before querying."
201
+ };
202
+ }
145
203
  var READ_AUTH_TIERS = {
146
204
  datasets: "open — no API key required",
147
205
  index: "anonymous reads allowed; free-tier API keys are rejected (Build+ required)",
148
206
  streams: "API key required (SL_API_KEY) — keyless calls return 401",
149
207
  subgraphs: "reads public during open beta; writes require an API key"
150
208
  };
151
- async function buildContext(deps = {
152
- clientProvider: getClient,
153
- accountRequest: () => apiRequest("GET", "/api/accounts/me")
154
- }) {
209
+ async function buildContext(deps = { clientProvider: getClient }) {
155
210
  const unavailable = "unavailable: set SL_API_KEY";
156
- const subgraphs = await deps.clientProvider().subgraphs.list().then((r) => r.data.map(formatSubgraphSummary)).catch(() => unavailable);
157
- const subscriptions = await deps.clientProvider().subscriptions.list().then((r) => ({
158
- count: r.data.length,
159
- statuses: r.data.map((s) => s.status)
160
- })).catch(() => unavailable);
161
- const account = await deps.accountRequest().catch(() => unavailable);
211
+ const orNull = (v) => v == null ? unavailable : v;
212
+ const snap = await deps.clientProvider().context().catch(() => null);
162
213
  return {
163
214
  authState: { apiKeySet: Boolean(process.env.SL_API_KEY) },
164
- whatExists: { subgraphs, subscriptions, account },
165
- whatYouCanDo: CAPABILITIES,
215
+ whatExists: {
216
+ account: orNull(snap?.account),
217
+ streamsTip: orNull(snap?.streamsTip),
218
+ indexTip: orNull(snap?.indexTip),
219
+ subgraphs: snap?.subgraphs ? snap.subgraphs.map(formatSubgraphSummary) : unavailable,
220
+ subscriptions: orNull(snap?.subscriptions),
221
+ activeOperations: orNull(snap?.activeOperations)
222
+ },
223
+ whatYouCanDo: buildCapabilities(),
166
224
  readAuthTiers: READ_AUTH_TIERS
167
225
  };
168
226
  }
@@ -200,31 +258,6 @@ function registerResources(server) {
200
258
 
201
259
  // src/tools/account.ts
202
260
  import { z } from "zod/v4";
203
-
204
- // src/lib/tool.ts
205
- function defineTool(server, name, description, schema, handler) {
206
- const wrappedHandler = async (args) => {
207
- try {
208
- return await handler(args);
209
- } catch (err) {
210
- const message = err instanceof Error ? err.message : String(err);
211
- const status = err instanceof Error && "status" in err ? err.status : 0;
212
- const type = status === 401 ? "unauthorized" : status === 404 ? "not_found" : status === 429 ? "rate_limited" : status >= 500 ? "server_error" : "error";
213
- return {
214
- content: [
215
- {
216
- type: "text",
217
- text: JSON.stringify({ error: { type, status, message } })
218
- }
219
- ],
220
- isError: true
221
- };
222
- }
223
- };
224
- server.tool(name, description, schema, wrappedHandler);
225
- }
226
-
227
- // src/tools/account.ts
228
261
  function registerAccountTools(server) {
229
262
  defineTool(server, "account_whoami", "Show the authenticated account's email and plan.", {}, async () => {
230
263
  const result = await apiRequest("GET", "/api/accounts/me");
@@ -249,6 +282,10 @@ function registerAccountTools(server) {
249
282
  const result = await apiRequest("GET", "/api/billing/status");
250
283
  return jsonResponse(result);
251
284
  });
285
+ 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.", {
286
+ product: z.enum(["streams", "index"]).optional().describe("Key scope (default streams)"),
287
+ name: z.string().optional().describe("Optional label for the key")
288
+ }, async ({ product, name }) => jsonResponse(await getClient().apiKeys.create({ product, name })));
252
289
  }
253
290
 
254
291
  // src/tools/contracts.ts
@@ -287,20 +324,9 @@ function registerDatasetTools(server, clientProvider = getClient) {
287
324
  }
288
325
 
289
326
  // src/tools/index.ts
327
+ import { DECODED_EVENT_TYPES } from "@secondlayer/shared";
290
328
  import { z as z4 } from "zod/v4";
291
- var INDEX_EVENT_TYPES = [
292
- "ft_transfer",
293
- "nft_transfer",
294
- "stx_transfer",
295
- "stx_mint",
296
- "stx_burn",
297
- "stx_lock",
298
- "ft_mint",
299
- "ft_burn",
300
- "nft_mint",
301
- "nft_burn",
302
- "print"
303
- ];
329
+ var INDEX_EVENT_TYPES = DECODED_EVENT_TYPES;
304
330
  var rangeFilters = {
305
331
  contractId: z4.string().optional().describe("Filter by contract id"),
306
332
  fromHeight: z4.number().optional().describe("Start block height (inclusive)"),
@@ -308,6 +334,13 @@ var rangeFilters = {
308
334
  cursor: z4.string().optional().describe("Opaque cursor from a prior response's next_cursor"),
309
335
  limit: z4.number().optional().describe("Max rows for this page")
310
336
  };
337
+ var heightFilters = {
338
+ fromHeight: rangeFilters.fromHeight,
339
+ toHeight: rangeFilters.toHeight,
340
+ cursor: rangeFilters.cursor,
341
+ limit: rangeFilters.limit
342
+ };
343
+ var notFound = (message) => jsonResponse({ error: { type: "not_found", status: 404, message } }, true);
311
344
  function registerIndexTools(server, clientProvider = getClient) {
312
345
  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).", {
313
346
  ...rangeFilters,
@@ -332,6 +365,41 @@ function registerIndexTools(server, clientProvider = getClient) {
332
365
  functionName: z4.string().optional().describe("Filter by called function name"),
333
366
  sender: z4.string().optional().describe("Filter by caller principal")
334
367
  }, async (params) => jsonResponse(await clientProvider().index.contractCalls.list(params)));
368
+ 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)));
369
+ 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)));
370
+ defineTool(server, "index_block", "Get a single block from the Index by height or block hash. Returns not_found if unknown.", {
371
+ ref: z4.string().describe("Block height (digits) or block hash (0x… string)")
372
+ }, async ({ ref }) => {
373
+ const block = await clientProvider().index.blocks.get(/^\d+$/.test(ref) ? Number(ref) : ref);
374
+ return block ? jsonResponse(block) : notFound(`No block for ref ${ref}`);
375
+ });
376
+ defineTool(server, "index_transactions", "List decoded transactions from the Index. Filter by type, sender, or contract. Anonymous reads allowed (free-tier keys rejected).", {
377
+ ...rangeFilters,
378
+ type: z4.string().optional().describe("Filter by transaction type"),
379
+ sender: z4.string().optional().describe("Filter by sender principal")
380
+ }, async (params) => jsonResponse(await clientProvider().index.transactions.list(params)));
381
+ 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 }) => {
382
+ const tx = await clientProvider().index.transactions.get(txId);
383
+ return tx ? jsonResponse(tx) : notFound(`No transaction for ${txId}`);
384
+ });
385
+ 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).", {
386
+ ...heightFilters,
387
+ functionName: z4.string().optional().describe("Filter by PoX function name"),
388
+ stacker: z4.string().optional().describe("Filter by stacker principal"),
389
+ caller: z4.string().optional().describe("Filter by caller principal")
390
+ }, async (params) => jsonResponse(await clientProvider().index.stacking.list(params)));
391
+ 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).", {
392
+ sender: z4.string().optional().describe("Filter by sender principal"),
393
+ type: z4.string().optional().describe("Filter by transaction type"),
394
+ contractId: z4.string().optional().describe("Filter to pending calls to a single contract"),
395
+ cursor: z4.string().optional().describe("Opaque cursor from a prior response's next_cursor"),
396
+ limit: z4.number().optional().describe("Max rows for this page")
397
+ }, async (params) => jsonResponse(await clientProvider().index.mempool.list(params)));
398
+ 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 }) => {
399
+ const tx = await clientProvider().index.mempool.get(txId);
400
+ return tx ? jsonResponse(tx) : notFound(`No pending tx for ${txId}`);
401
+ });
402
+ 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()));
335
403
  }
336
404
 
337
405
  // src/tools/scaffold.ts
@@ -383,20 +451,9 @@ function registerScaffoldTools(server) {
383
451
 
384
452
  // src/tools/streams.ts
385
453
  import { AuthError } from "@secondlayer/sdk";
454
+ import { DECODED_EVENT_TYPES as DECODED_EVENT_TYPES2 } from "@secondlayer/shared";
386
455
  import { z as z6 } from "zod/v4";
387
- var STREAMS_EVENT_TYPES = [
388
- "stx_transfer",
389
- "stx_mint",
390
- "stx_burn",
391
- "stx_lock",
392
- "ft_transfer",
393
- "ft_mint",
394
- "ft_burn",
395
- "nft_transfer",
396
- "nft_mint",
397
- "nft_burn",
398
- "print"
399
- ];
456
+ var STREAMS_EVENT_TYPES = DECODED_EVENT_TYPES2;
400
457
  async function withStreamsAuthHint(fn) {
401
458
  try {
402
459
  return await fn();
@@ -416,11 +473,21 @@ function registerStreamsTools(server, clientProvider = getClient) {
416
473
  sender: z6.string().optional().describe("Filter by sender principal"),
417
474
  recipient: z6.string().optional().describe("Filter by recipient principal"),
418
475
  assetIdentifier: z6.string().optional().describe("Filter by asset identifier"),
419
- fromBlock: z6.number().optional().describe("Start block (inclusive)"),
420
- toBlock: z6.number().optional().describe("End block (inclusive)"),
476
+ fromHeight: z6.number().optional().describe("Start block height (inclusive)"),
477
+ toHeight: z6.number().optional().describe("End block height (inclusive)"),
421
478
  cursor: z6.string().optional().describe("Opaque cursor from a prior response"),
422
479
  limit: z6.number().optional().describe("Max events for this page")
423
480
  }, async (params) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.events.list(params))));
481
+ 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))));
482
+ 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).", {
483
+ heightOrHash: z6.string().describe("Block height (digits) or block hash (0x… string)")
484
+ }, async ({ heightOrHash }) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.blocks.events(/^\d+$/.test(heightOrHash) ? Number(heightOrHash) : heightOrHash))));
485
+ defineTool(server, "streams_reorgs", "List chain reorgs observed by Streams since a cursor. Streams requires an API key (SL_API_KEY).", {
486
+ since: z6.string().describe("Cursor to list reorgs since (block:index or ISO timestamp)"),
487
+ limit: z6.number().optional().describe("Max reorgs to return")
488
+ }, async (params) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.reorgs.list(params))));
489
+ 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))));
490
+ 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())));
424
491
  }
425
492
 
426
493
  // src/tools/subgraphs.ts
@@ -501,7 +568,7 @@ function registerSubgraphTools(server, clientProvider = getClient) {
501
568
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
502
569
  };
503
570
  });
504
- defineTool(server, "subgraphs_reindex", "Reindex a subgraph from a specific block range.", {
571
+ defineTool(server, "subgraphs_reindex", "Reindex a subgraph from a specific block range. Returns an operationId — poll subgraphs_operation to track progress to completion.", {
505
572
  name: z7.string().describe("Subgraph name"),
506
573
  fromBlock: z7.number().optional().describe("Start block (defaults to beginning)"),
507
574
  toBlock: z7.number().optional().describe("End block (defaults to latest)")
@@ -514,6 +581,15 @@ function registerSubgraphTools(server, clientProvider = getClient) {
514
581
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
515
582
  };
516
583
  });
584
+ 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.", {
585
+ name: z7.string().describe("Subgraph name"),
586
+ operationId: z7.string().optional().describe("Operation id from reindex/backfill/stop; omit to list recent operations")
587
+ }, async ({ name, operationId }) => {
588
+ const result = operationId ? await clientProvider().subgraphs.getOperation(name, operationId) : await clientProvider().subgraphs.operations(name);
589
+ return {
590
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
591
+ };
592
+ });
517
593
  defineTool(server, "subgraphs_delete", "Delete a subgraph permanently.", { name: z7.string().describe("Subgraph name") }, async ({ name }) => {
518
594
  const result = await clientProvider().subgraphs.delete(name);
519
595
  return { content: [{ type: "text", text: result.message }] };
@@ -546,6 +622,7 @@ function registerSubgraphTools(server, clientProvider = getClient) {
546
622
  }
547
623
 
548
624
  // src/tools/subscriptions.ts
625
+ import { CHAIN_TRIGGER_TYPES } from "@secondlayer/shared";
549
626
  import { z as z8 } from "zod/v4";
550
627
  function registerSubscriptionTools(server, clientProvider = getClient) {
551
628
  defineTool(server, "subscriptions_list", "List all subscriptions for the current account. Returns summary fields (no secrets).", {}, async () => {
@@ -565,21 +642,7 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
565
642
  subgraphName: z8.string().optional().describe("Subgraph to subscribe to (subgraph subscription)"),
566
643
  tableName: z8.string().optional().describe("Table within the subgraph (subgraph subscription)"),
567
644
  triggers: z8.array(z8.object({
568
- type: z8.enum([
569
- "stx_transfer",
570
- "stx_mint",
571
- "stx_burn",
572
- "stx_lock",
573
- "ft_transfer",
574
- "ft_mint",
575
- "ft_burn",
576
- "nft_transfer",
577
- "nft_mint",
578
- "nft_burn",
579
- "contract_call",
580
- "contract_deploy",
581
- "print_event"
582
- ]),
645
+ type: z8.enum(CHAIN_TRIGGER_TYPES),
583
646
  contractId: z8.string().optional(),
584
647
  functionName: z8.string().optional(),
585
648
  caller: z8.string().optional(),
@@ -799,5 +862,5 @@ httpServer.listen(port, () => {
799
862
  console.error("Warning: SECONDLAYER_MCP_SECRET not set, authentication disabled");
800
863
  });
801
864
 
802
- //# debugId=F39D6403EC4F2E1664756E2164756E21
865
+ //# debugId=587F4DDF9A78B13764756E2164756E21
803
866
  //# sourceMappingURL=bin-http.js.map