@secondlayer/mcp 3.0.1 → 3.1.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 +316 -118
- package/dist/bin-http.js.map +11 -7
- package/dist/bin.js +316 -118
- package/dist/bin.js.map +11 -7
- package/dist/index.js +316 -118
- package/dist/index.js.map +11 -7
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,6 +4,69 @@ import { dirname, join } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
6
|
|
|
7
|
+
// src/lib/client.ts
|
|
8
|
+
import { SecondLayer } from "@secondlayer/sdk";
|
|
9
|
+
var instance = null;
|
|
10
|
+
function readApiKey() {
|
|
11
|
+
return process.env.SL_API_KEY;
|
|
12
|
+
}
|
|
13
|
+
function getClient() {
|
|
14
|
+
if (!instance) {
|
|
15
|
+
const apiKey = readApiKey();
|
|
16
|
+
const baseUrl = process.env.SECONDLAYER_API_URL;
|
|
17
|
+
instance = new SecondLayer({
|
|
18
|
+
...apiKey ? { apiKey } : {},
|
|
19
|
+
origin: "mcp",
|
|
20
|
+
...baseUrl ? { baseUrl } : {}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return instance;
|
|
24
|
+
}
|
|
25
|
+
var keyHint = " — set SL_API_KEY to an sk-sl_ API key from " + "https://secondlayer.tools/platform/api-keys for write and account operations";
|
|
26
|
+
async function apiRequest(method, path, body) {
|
|
27
|
+
const apiKey = readApiKey();
|
|
28
|
+
const baseUrl = process.env.SECONDLAYER_API_URL || "https://api.secondlayer.tools";
|
|
29
|
+
const res = await fetch(`${baseUrl}${path}`, {
|
|
30
|
+
method,
|
|
31
|
+
headers: {
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
|
|
34
|
+
},
|
|
35
|
+
body: body ? JSON.stringify(body) : undefined
|
|
36
|
+
});
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const text = await res.text().catch(() => "");
|
|
39
|
+
const needsKey = !apiKey && (res.status === 401 || res.status === 403);
|
|
40
|
+
throw Object.assign(new Error((text || `HTTP ${res.status}`) + (needsKey ? keyHint : "")), { status: res.status });
|
|
41
|
+
}
|
|
42
|
+
if (res.status === 204)
|
|
43
|
+
return;
|
|
44
|
+
return res.json();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/lib/format.ts
|
|
48
|
+
function formatSubgraphSummary(s) {
|
|
49
|
+
return {
|
|
50
|
+
name: s.name,
|
|
51
|
+
status: s.status,
|
|
52
|
+
tables: Array.isArray(s.tables) ? s.tables : Object.keys(s.tables),
|
|
53
|
+
lastProcessedBlock: s.lastProcessedBlock
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function withCap(items, cap) {
|
|
57
|
+
return {
|
|
58
|
+
items: items.slice(0, cap),
|
|
59
|
+
truncated: items.length > cap,
|
|
60
|
+
total: items.length
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function jsonResponse(data, isError) {
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
66
|
+
...isError && { isError: true }
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
7
70
|
// src/resources.ts
|
|
8
71
|
var FILTERS_REFERENCE = [
|
|
9
72
|
{
|
|
@@ -59,7 +122,54 @@ var COLUMN_TYPES = [
|
|
|
59
122
|
description: "Column options: nullable allows NULL, indexed creates a B-tree index, search enables full-text search"
|
|
60
123
|
}
|
|
61
124
|
];
|
|
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."
|
|
136
|
+
};
|
|
137
|
+
var READ_AUTH_TIERS = {
|
|
138
|
+
datasets: "open — no API key required",
|
|
139
|
+
index: "anonymous reads allowed; free-tier API keys are rejected (Build+ required)",
|
|
140
|
+
streams: "API key required (SL_API_KEY) — keyless calls return 401",
|
|
141
|
+
subgraphs: "reads public during open beta; writes require an API key"
|
|
142
|
+
};
|
|
143
|
+
async function buildContext(deps = {
|
|
144
|
+
clientProvider: getClient,
|
|
145
|
+
accountRequest: () => apiRequest("GET", "/api/accounts/me")
|
|
146
|
+
}) {
|
|
147
|
+
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);
|
|
154
|
+
return {
|
|
155
|
+
authState: { apiKeySet: Boolean(process.env.SL_API_KEY) },
|
|
156
|
+
whatExists: { subgraphs, subscriptions, account },
|
|
157
|
+
whatYouCanDo: CAPABILITIES,
|
|
158
|
+
readAuthTiers: READ_AUTH_TIERS
|
|
159
|
+
};
|
|
160
|
+
}
|
|
62
161
|
function registerResources(server) {
|
|
162
|
+
server.resource("context", "secondlayer://context", {
|
|
163
|
+
description: "Live agent context — what exists (your subgraphs, subscriptions, account), what you can do, and read-auth tiers. Read this first."
|
|
164
|
+
}, async () => ({
|
|
165
|
+
contents: [
|
|
166
|
+
{
|
|
167
|
+
uri: "secondlayer://context",
|
|
168
|
+
mimeType: "application/json",
|
|
169
|
+
text: JSON.stringify(await buildContext(), null, 2)
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
}));
|
|
63
173
|
server.resource("filters", "secondlayer://filters", { description: "Event filter types and their available fields" }, async () => ({
|
|
64
174
|
contents: [
|
|
65
175
|
{
|
|
@@ -80,68 +190,8 @@ function registerResources(server) {
|
|
|
80
190
|
}));
|
|
81
191
|
}
|
|
82
192
|
|
|
83
|
-
// src/
|
|
84
|
-
import {
|
|
85
|
-
var instance = null;
|
|
86
|
-
function readApiKey() {
|
|
87
|
-
return process.env.SL_API_KEY;
|
|
88
|
-
}
|
|
89
|
-
function getClient() {
|
|
90
|
-
if (!instance) {
|
|
91
|
-
const apiKey = readApiKey();
|
|
92
|
-
const baseUrl = process.env.SECONDLAYER_API_URL;
|
|
93
|
-
instance = new SecondLayer({
|
|
94
|
-
...apiKey ? { apiKey } : {},
|
|
95
|
-
origin: "mcp",
|
|
96
|
-
...baseUrl ? { baseUrl } : {}
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
return instance;
|
|
100
|
-
}
|
|
101
|
-
var keyHint = " — set SL_API_KEY to an sk-sl_ API key from " + "https://secondlayer.tools/platform/api-keys for write and account operations";
|
|
102
|
-
async function apiRequest(method, path, body) {
|
|
103
|
-
const apiKey = readApiKey();
|
|
104
|
-
const baseUrl = process.env.SECONDLAYER_API_URL || "https://api.secondlayer.tools";
|
|
105
|
-
const res = await fetch(`${baseUrl}${path}`, {
|
|
106
|
-
method,
|
|
107
|
-
headers: {
|
|
108
|
-
"Content-Type": "application/json",
|
|
109
|
-
...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
|
|
110
|
-
},
|
|
111
|
-
body: body ? JSON.stringify(body) : undefined
|
|
112
|
-
});
|
|
113
|
-
if (!res.ok) {
|
|
114
|
-
const text = await res.text().catch(() => "");
|
|
115
|
-
const needsKey = !apiKey && (res.status === 401 || res.status === 403);
|
|
116
|
-
throw Object.assign(new Error((text || `HTTP ${res.status}`) + (needsKey ? keyHint : "")), { status: res.status });
|
|
117
|
-
}
|
|
118
|
-
if (res.status === 204)
|
|
119
|
-
return;
|
|
120
|
-
return res.json();
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// src/lib/format.ts
|
|
124
|
-
function formatSubgraphSummary(s) {
|
|
125
|
-
return {
|
|
126
|
-
name: s.name,
|
|
127
|
-
status: s.status,
|
|
128
|
-
tables: Array.isArray(s.tables) ? s.tables : Object.keys(s.tables),
|
|
129
|
-
lastProcessedBlock: s.lastProcessedBlock
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
function withCap(items, cap) {
|
|
133
|
-
return {
|
|
134
|
-
items: items.slice(0, cap),
|
|
135
|
-
truncated: items.length > cap,
|
|
136
|
-
total: items.length
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
function jsonResponse(data, isError) {
|
|
140
|
-
return {
|
|
141
|
-
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
142
|
-
...isError && { isError: true }
|
|
143
|
-
};
|
|
144
|
-
}
|
|
193
|
+
// src/tools/account.ts
|
|
194
|
+
import { z } from "zod/v4";
|
|
145
195
|
|
|
146
196
|
// src/lib/tool.ts
|
|
147
197
|
function defineTool(server, name, description, schema, handler) {
|
|
@@ -172,11 +222,113 @@ function registerAccountTools(server) {
|
|
|
172
222
|
const result = await apiRequest("GET", "/api/accounts/me");
|
|
173
223
|
return jsonResponse(result);
|
|
174
224
|
});
|
|
225
|
+
defineTool(server, "account_update", "Update the authenticated account's profile. Requires an API key.", {
|
|
226
|
+
displayName: z.string().optional().describe("Display name"),
|
|
227
|
+
bio: z.string().optional().describe("Profile bio"),
|
|
228
|
+
slug: z.string().optional().describe("Account URL slug")
|
|
229
|
+
}, async ({ displayName, bio, slug }) => {
|
|
230
|
+
const body = {};
|
|
231
|
+
if (displayName !== undefined)
|
|
232
|
+
body.display_name = displayName;
|
|
233
|
+
if (bio !== undefined)
|
|
234
|
+
body.bio = bio;
|
|
235
|
+
if (slug !== undefined)
|
|
236
|
+
body.slug = slug;
|
|
237
|
+
const result = await apiRequest("PATCH", "/api/accounts/me", body);
|
|
238
|
+
return jsonResponse(result);
|
|
239
|
+
});
|
|
240
|
+
defineTool(server, "account_billing", "Show the account's plan and subscription/billing status. Requires an API key.", {}, async () => {
|
|
241
|
+
const result = await apiRequest("GET", "/api/billing/status");
|
|
242
|
+
return jsonResponse(result);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// src/tools/contracts.ts
|
|
247
|
+
import { z as z2 } from "zod/v4";
|
|
248
|
+
function registerContractTools(server, clientProvider = getClient) {
|
|
249
|
+
defineTool(server, "contracts_find", 'Discover deployed Stacks contracts conforming to a trait (e.g. "sip-010", "sip-009", "sip-013"). The discovery endpoint for "which contracts implement X". Reads are public.', {
|
|
250
|
+
trait: z2.string().describe('Required. Trait to match (e.g. "sip-010").'),
|
|
251
|
+
conformance: z2.enum(["declared", "inferred", "any"]).optional().describe("declared = parsed from source, inferred = ABI shape-match, any = either (default)"),
|
|
252
|
+
include: z2.literal("abi").optional().describe(`Set to "abi" to include each contract's full ABI`),
|
|
253
|
+
limit: z2.number().optional().describe("Page size, 1–500 (default 100)"),
|
|
254
|
+
cursor: z2.string().optional().describe("Opaque cursor from a prior response's next_cursor")
|
|
255
|
+
}, async (params) => jsonResponse(await clientProvider().contracts.list(params)));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/tools/datasets.ts
|
|
259
|
+
import { z as z3 } from "zod/v4";
|
|
260
|
+
function registerDatasetTools(server, clientProvider = getClient) {
|
|
261
|
+
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 () => {
|
|
262
|
+
const catalog = await clientProvider().datasets.listDatasets();
|
|
263
|
+
return jsonResponse(catalog);
|
|
264
|
+
});
|
|
265
|
+
defineTool(server, "datasets_query", 'Query a cursor-paginated Foundation Dataset by slug (e.g. "stx-transfers", "sbtc/events", "pox-4/calls", "bns/events"). Filters are passed through as documented query params (e.g. {"sender": "SP...", "from_block": "150000"}). Returns { rows, next_cursor, tip }. Call datasets_list first to discover slugs.', {
|
|
266
|
+
slug: z3.string().describe("Dataset slug from datasets_list (e.g. stx-transfers)"),
|
|
267
|
+
filters: z3.record(z3.string(), z3.string()).optional().describe("Documented per-dataset query params (snake_case values)"),
|
|
268
|
+
limit: z3.number().optional().describe("Max rows for this page"),
|
|
269
|
+
cursor: z3.string().optional().describe("Opaque cursor from a prior response's next_cursor")
|
|
270
|
+
}, async ({ slug, filters, limit, cursor }) => {
|
|
271
|
+
const params = { ...filters ?? {} };
|
|
272
|
+
if (limit !== undefined)
|
|
273
|
+
params.limit = limit;
|
|
274
|
+
if (cursor !== undefined)
|
|
275
|
+
params.cursor = cursor;
|
|
276
|
+
const result = await clientProvider().datasets.query(slug, params);
|
|
277
|
+
return jsonResponse(result);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/tools/index.ts
|
|
282
|
+
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
|
+
];
|
|
296
|
+
var rangeFilters = {
|
|
297
|
+
contractId: z4.string().optional().describe("Filter by contract id"),
|
|
298
|
+
fromHeight: z4.number().optional().describe("Start block height (inclusive)"),
|
|
299
|
+
toHeight: z4.number().optional().describe("End block height (inclusive)"),
|
|
300
|
+
cursor: z4.string().optional().describe("Opaque cursor from a prior response's next_cursor"),
|
|
301
|
+
limit: z4.number().optional().describe("Max rows for this page")
|
|
302
|
+
};
|
|
303
|
+
function registerIndexTools(server, clientProvider = getClient) {
|
|
304
|
+
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
|
+
...rangeFilters,
|
|
306
|
+
sender: z4.string().optional().describe("Filter by sender principal"),
|
|
307
|
+
recipient: z4.string().optional().describe("Filter by recipient principal")
|
|
308
|
+
}, async (params) => jsonResponse(await clientProvider().index.ftTransfers.list(params)));
|
|
309
|
+
defineTool(server, "index_nft_transfers", "List decoded SIP-009 non-fungible-token transfers from the Index. Anonymous reads allowed (free-tier keys rejected).", {
|
|
310
|
+
...rangeFilters,
|
|
311
|
+
sender: z4.string().optional().describe("Filter by sender principal"),
|
|
312
|
+
recipient: z4.string().optional().describe("Filter by recipient principal"),
|
|
313
|
+
assetIdentifier: z4.string().optional().describe("Filter by asset identifier (contract::asset)")
|
|
314
|
+
}, async (params) => jsonResponse(await clientProvider().index.nftTransfers.list(params)));
|
|
315
|
+
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). For ft/nft transfers prefer index_ft_transfers / index_nft_transfers.", {
|
|
316
|
+
eventType: z4.enum(INDEX_EVENT_TYPES).describe("Required. Decoded event type to list."),
|
|
317
|
+
...rangeFilters,
|
|
318
|
+
sender: z4.string().optional().describe("Filter by sender principal"),
|
|
319
|
+
recipient: z4.string().optional().describe("Filter by recipient principal"),
|
|
320
|
+
assetIdentifier: z4.string().optional().describe("Filter by asset identifier where applicable")
|
|
321
|
+
}, async (params) => jsonResponse(await clientProvider().index.events.list(params)));
|
|
322
|
+
defineTool(server, "index_contract_calls", "List decoded contract calls from the Index (function name, args, result). Note: contract-call cursors are a SEPARATE keyspace from event cursors — they are not interchangeable.", {
|
|
323
|
+
...rangeFilters,
|
|
324
|
+
functionName: z4.string().optional().describe("Filter by called function name"),
|
|
325
|
+
sender: z4.string().optional().describe("Filter by caller principal")
|
|
326
|
+
}, async (params) => jsonResponse(await clientProvider().index.contractCalls.list(params)));
|
|
175
327
|
}
|
|
176
328
|
|
|
177
329
|
// src/tools/scaffold.ts
|
|
178
330
|
import { generateSubgraphCode } from "@secondlayer/scaffold";
|
|
179
|
-
import { z } from "zod/v4";
|
|
331
|
+
import { z as z5 } from "zod/v4";
|
|
180
332
|
var API_BASE = process.env.SECONDLAYER_API_URL || "https://api.secondlayer.tools";
|
|
181
333
|
async function fetchAbi(contractId) {
|
|
182
334
|
const res = await fetch(`${API_BASE}/api/node/contracts/${contractId}/abi`, {
|
|
@@ -195,17 +347,17 @@ async function fetchAbi(contractId) {
|
|
|
195
347
|
}
|
|
196
348
|
function registerScaffoldTools(server) {
|
|
197
349
|
defineTool(server, "scaffold_from_contract", "Generate a subgraph scaffold from a deployed Stacks contract. Fetches the ABI automatically.", {
|
|
198
|
-
contractId:
|
|
199
|
-
subgraphName:
|
|
350
|
+
contractId: z5.string().describe("Fully qualified contract ID (e.g. SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-pool-v2-01)"),
|
|
351
|
+
subgraphName: z5.string().optional().describe("Override the subgraph name (defaults to contract name)")
|
|
200
352
|
}, async ({ contractId, subgraphName }) => {
|
|
201
353
|
const { functions, maps } = await fetchAbi(contractId);
|
|
202
354
|
const code = generateSubgraphCode(contractId, functions, subgraphName, maps);
|
|
203
355
|
return { content: [{ type: "text", text: code }] };
|
|
204
356
|
});
|
|
205
357
|
defineTool(server, "scaffold_from_abi", "Generate a subgraph scaffold from a provided ABI JSON. Use when you already have the ABI.", {
|
|
206
|
-
abi:
|
|
207
|
-
contractId:
|
|
208
|
-
subgraphName:
|
|
358
|
+
abi: z5.string().describe("ABI JSON string (the full contract ABI object)"),
|
|
359
|
+
contractId: z5.string().describe("Fully qualified contract ID"),
|
|
360
|
+
subgraphName: z5.string().optional().describe("Override the subgraph name")
|
|
209
361
|
}, async ({ abi, contractId, subgraphName }) => {
|
|
210
362
|
let parsed;
|
|
211
363
|
try {
|
|
@@ -221,9 +373,51 @@ function registerScaffoldTools(server) {
|
|
|
221
373
|
});
|
|
222
374
|
}
|
|
223
375
|
|
|
376
|
+
// src/tools/streams.ts
|
|
377
|
+
import { AuthError } from "@secondlayer/sdk";
|
|
378
|
+
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
|
+
];
|
|
392
|
+
async function withStreamsAuthHint(fn) {
|
|
393
|
+
try {
|
|
394
|
+
return await fn();
|
|
395
|
+
} catch (err) {
|
|
396
|
+
if (err instanceof AuthError) {
|
|
397
|
+
throw Object.assign(new Error(err.message + keyHint), { status: 401 });
|
|
398
|
+
}
|
|
399
|
+
throw err;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function registerStreamsTools(server, clientProvider = getClient) {
|
|
403
|
+
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())));
|
|
404
|
+
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.", {
|
|
405
|
+
types: z6.array(z6.enum(STREAMS_EVENT_TYPES)).optional().describe("Event types to include"),
|
|
406
|
+
notTypes: z6.array(z6.enum(STREAMS_EVENT_TYPES)).optional().describe("Event types to exclude (applied after types)"),
|
|
407
|
+
contractId: z6.string().optional().describe("Filter by contract id"),
|
|
408
|
+
sender: z6.string().optional().describe("Filter by sender principal"),
|
|
409
|
+
recipient: z6.string().optional().describe("Filter by recipient principal"),
|
|
410
|
+
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)"),
|
|
413
|
+
cursor: z6.string().optional().describe("Opaque cursor from a prior response"),
|
|
414
|
+
limit: z6.number().optional().describe("Max events for this page")
|
|
415
|
+
}, async (params) => withStreamsAuthHint(async () => jsonResponse(await clientProvider().streams.events.list(params))));
|
|
416
|
+
}
|
|
417
|
+
|
|
224
418
|
// src/tools/subgraphs.ts
|
|
225
419
|
import { bundleSubgraphCode } from "@secondlayer/bundler";
|
|
226
|
-
import { z as
|
|
420
|
+
import { z as z7 } from "zod/v4";
|
|
227
421
|
function registerSubgraphTools(server, clientProvider = getClient) {
|
|
228
422
|
defineTool(server, "subgraphs_list", "List all deployed subgraphs. Returns summary fields only.", {}, async () => {
|
|
229
423
|
const { data } = await clientProvider().subgraphs.list();
|
|
@@ -236,16 +430,16 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
236
430
|
]
|
|
237
431
|
};
|
|
238
432
|
});
|
|
239
|
-
defineTool(server, "subgraphs_get", "Get full details of a subgraph including schema, health, and table columns.", { name:
|
|
433
|
+
defineTool(server, "subgraphs_get", "Get full details of a subgraph including schema, health, and table columns.", { name: z7.string().describe("Subgraph name") }, async ({ name }) => {
|
|
240
434
|
const detail = await clientProvider().subgraphs.get(name);
|
|
241
435
|
return {
|
|
242
436
|
content: [{ type: "text", text: JSON.stringify(detail, null, 2) }]
|
|
243
437
|
};
|
|
244
438
|
});
|
|
245
439
|
defineTool(server, "subgraphs_spec", "Get generated API documentation for a subgraph. Defaults to compact agent schema; supports OpenAPI JSON and Markdown.", {
|
|
246
|
-
name:
|
|
247
|
-
format:
|
|
248
|
-
serverUrl:
|
|
440
|
+
name: z7.string().describe("Subgraph name"),
|
|
441
|
+
format: z7.enum(["agent", "openapi", "markdown"]).optional().describe("Spec format to return. Defaults to agent."),
|
|
442
|
+
serverUrl: z7.string().optional().describe("Override the server URL embedded in generated docs.")
|
|
249
443
|
}, async ({ name, format = "agent", serverUrl }) => {
|
|
250
444
|
const options = serverUrl ? { serverUrl } : undefined;
|
|
251
445
|
const spec = format === "openapi" ? await clientProvider().subgraphs.openapi(name, options) : format === "markdown" ? await clientProvider().subgraphs.markdown(name, options) : await clientProvider().subgraphs.schema(name, options);
|
|
@@ -259,15 +453,15 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
259
453
|
};
|
|
260
454
|
});
|
|
261
455
|
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.', {
|
|
262
|
-
name:
|
|
263
|
-
table:
|
|
264
|
-
filters:
|
|
265
|
-
sort:
|
|
266
|
-
order:
|
|
267
|
-
limit:
|
|
268
|
-
offset:
|
|
269
|
-
fields:
|
|
270
|
-
count:
|
|
456
|
+
name: z7.string().describe("Subgraph name"),
|
|
457
|
+
table: z7.string().describe("Table name"),
|
|
458
|
+
filters: z7.record(z7.string(), z7.string()).optional().describe('Column filters — plain values or with operators (e.g. {"amount.gte": "1000", "sender": "SP..."})'),
|
|
459
|
+
sort: z7.string().optional().describe("Column to sort by"),
|
|
460
|
+
order: z7.enum(["asc", "desc"]).optional().describe("Sort order"),
|
|
461
|
+
limit: z7.number().max(200).optional().describe("Max rows (default 50, max 200)"),
|
|
462
|
+
offset: z7.number().optional().describe("Offset for pagination"),
|
|
463
|
+
fields: z7.string().optional().describe('Comma-separated column list to return (e.g. "sender,amount")'),
|
|
464
|
+
count: z7.boolean().optional().describe("If true, return row count instead of rows")
|
|
271
465
|
}, async ({
|
|
272
466
|
name,
|
|
273
467
|
table,
|
|
@@ -300,9 +494,9 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
300
494
|
};
|
|
301
495
|
});
|
|
302
496
|
defineTool(server, "subgraphs_reindex", "Reindex a subgraph from a specific block range.", {
|
|
303
|
-
name:
|
|
304
|
-
fromBlock:
|
|
305
|
-
toBlock:
|
|
497
|
+
name: z7.string().describe("Subgraph name"),
|
|
498
|
+
fromBlock: z7.number().optional().describe("Start block (defaults to beginning)"),
|
|
499
|
+
toBlock: z7.number().optional().describe("End block (defaults to latest)")
|
|
306
500
|
}, async ({ name, fromBlock, toBlock }) => {
|
|
307
501
|
const result = await clientProvider().subgraphs.reindex(name, {
|
|
308
502
|
fromBlock,
|
|
@@ -312,13 +506,13 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
312
506
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
313
507
|
};
|
|
314
508
|
});
|
|
315
|
-
defineTool(server, "subgraphs_delete", "Delete a subgraph permanently.", { name:
|
|
509
|
+
defineTool(server, "subgraphs_delete", "Delete a subgraph permanently.", { name: z7.string().describe("Subgraph name") }, async ({ name }) => {
|
|
316
510
|
const result = await clientProvider().subgraphs.delete(name);
|
|
317
511
|
return { content: [{ type: "text", text: result.message }] };
|
|
318
512
|
});
|
|
319
513
|
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. Call `subgraphs_reindex` separately if you need a forced reindex.", {
|
|
320
|
-
code:
|
|
321
|
-
startBlock:
|
|
514
|
+
code: z7.string().describe("TypeScript source code containing a defineSubgraph() call"),
|
|
515
|
+
startBlock: z7.number().int().nonnegative().optional().describe("Override the definition startBlock for this deploy")
|
|
322
516
|
}, async ({ code, startBlock }) => {
|
|
323
517
|
const bundled = await bundleSubgraphCode(code);
|
|
324
518
|
const result = await clientProvider().subgraphs.deploy({
|
|
@@ -335,7 +529,7 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
335
529
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
336
530
|
};
|
|
337
531
|
});
|
|
338
|
-
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:
|
|
532
|
+
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 }) => {
|
|
339
533
|
const source = await clientProvider().subgraphs.getSource(name);
|
|
340
534
|
return {
|
|
341
535
|
content: [{ type: "text", text: JSON.stringify(source, null, 2) }]
|
|
@@ -344,7 +538,7 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
344
538
|
}
|
|
345
539
|
|
|
346
540
|
// src/tools/subscriptions.ts
|
|
347
|
-
import { z as
|
|
541
|
+
import { z as z8 } from "zod/v4";
|
|
348
542
|
function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
349
543
|
defineTool(server, "subscriptions_list", "List all subscriptions for the current account. Returns summary fields (no secrets).", {}, async () => {
|
|
350
544
|
const { data } = await clientProvider().subscriptions.list();
|
|
@@ -352,18 +546,18 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
|
352
546
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
353
547
|
};
|
|
354
548
|
});
|
|
355
|
-
defineTool(server, "subscriptions_get", "Get full detail for a subscription (filter, auth, retry config, circuit state).", { id:
|
|
549
|
+
defineTool(server, "subscriptions_get", "Get full detail for a subscription (filter, auth, retry config, circuit state).", { id: z8.string().describe("Subscription id") }, async ({ id }) => {
|
|
356
550
|
const detail = await clientProvider().subscriptions.get(id);
|
|
357
551
|
return {
|
|
358
552
|
content: [{ type: "text", text: JSON.stringify(detail, null, 2) }]
|
|
359
553
|
};
|
|
360
554
|
});
|
|
361
555
|
defineTool(server, "subscriptions_create", "Create a subscription. Returns `signingSecret` ONCE — forward it to the user so they can wire it into their receiver.", {
|
|
362
|
-
name:
|
|
363
|
-
subgraphName:
|
|
364
|
-
tableName:
|
|
365
|
-
url:
|
|
366
|
-
format:
|
|
556
|
+
name: z8.string().describe("Human-readable name, unique per account"),
|
|
557
|
+
subgraphName: z8.string().describe("Subgraph to subscribe to"),
|
|
558
|
+
tableName: z8.string().describe("Table within the subgraph"),
|
|
559
|
+
url: z8.string().describe("Webhook URL"),
|
|
560
|
+
format: z8.enum([
|
|
367
561
|
"standard-webhooks",
|
|
368
562
|
"inngest",
|
|
369
563
|
"trigger",
|
|
@@ -371,8 +565,8 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
|
371
565
|
"cloudevents",
|
|
372
566
|
"raw"
|
|
373
567
|
]).optional().describe("Wire format (default standard-webhooks)"),
|
|
374
|
-
runtime:
|
|
375
|
-
filter:
|
|
568
|
+
runtime: z8.enum(["inngest", "trigger", "cloudflare", "node"]).optional().describe("Receiver runtime label (display only)"),
|
|
569
|
+
filter: z8.record(z8.string(), z8.unknown()).optional().describe('Scalar filter DSL, e.g. {"amount": {"gte": 100}, "sender": "SP..."}')
|
|
376
570
|
}, async (input) => {
|
|
377
571
|
const res = await clientProvider().subscriptions.create(input);
|
|
378
572
|
return {
|
|
@@ -380,10 +574,10 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
|
380
574
|
};
|
|
381
575
|
});
|
|
382
576
|
defineTool(server, "subscriptions_update", "Patch a subscription (url, filter, format, runtime, retry, timeout, concurrency).", {
|
|
383
|
-
id:
|
|
384
|
-
url:
|
|
385
|
-
filter:
|
|
386
|
-
format:
|
|
577
|
+
id: z8.string(),
|
|
578
|
+
url: z8.string().optional(),
|
|
579
|
+
filter: z8.record(z8.string(), z8.unknown()).optional(),
|
|
580
|
+
format: z8.enum([
|
|
387
581
|
"standard-webhooks",
|
|
388
582
|
"inngest",
|
|
389
583
|
"trigger",
|
|
@@ -391,44 +585,44 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
|
391
585
|
"cloudevents",
|
|
392
586
|
"raw"
|
|
393
587
|
]).optional(),
|
|
394
|
-
runtime:
|
|
395
|
-
maxRetries:
|
|
396
|
-
timeoutMs:
|
|
397
|
-
concurrency:
|
|
588
|
+
runtime: z8.enum(["inngest", "trigger", "cloudflare", "node"]).nullable().optional(),
|
|
589
|
+
maxRetries: z8.number().int().min(0).optional(),
|
|
590
|
+
timeoutMs: z8.number().int().min(100).optional(),
|
|
591
|
+
concurrency: z8.number().int().min(1).optional()
|
|
398
592
|
}, async ({ id, ...patch }) => {
|
|
399
593
|
const res = await clientProvider().subscriptions.update(id, patch);
|
|
400
594
|
return {
|
|
401
595
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
402
596
|
};
|
|
403
597
|
});
|
|
404
|
-
defineTool(server, "subscriptions_pause", "Pause a subscription. Pending rows remain queued until resumed.", { id:
|
|
598
|
+
defineTool(server, "subscriptions_pause", "Pause a subscription. Pending rows remain queued until resumed.", { id: z8.string() }, async ({ id }) => {
|
|
405
599
|
const res = await clientProvider().subscriptions.pause(id);
|
|
406
600
|
return {
|
|
407
601
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
408
602
|
};
|
|
409
603
|
});
|
|
410
|
-
defineTool(server, "subscriptions_resume", "Resume a paused or circuit-open subscription and reset circuit failures.", { id:
|
|
604
|
+
defineTool(server, "subscriptions_resume", "Resume a paused or circuit-open subscription and reset circuit failures.", { id: z8.string() }, async ({ id }) => {
|
|
411
605
|
const res = await clientProvider().subscriptions.resume(id);
|
|
412
606
|
return {
|
|
413
607
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
414
608
|
};
|
|
415
609
|
});
|
|
416
|
-
defineTool(server, "subscriptions_delete", "Delete a subscription. Pending outbox rows are cascade-deleted.", { id:
|
|
610
|
+
defineTool(server, "subscriptions_delete", "Delete a subscription. Pending outbox rows are cascade-deleted.", { id: z8.string() }, async ({ id }) => {
|
|
417
611
|
const res = await clientProvider().subscriptions.delete(id);
|
|
418
612
|
return {
|
|
419
613
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
420
614
|
};
|
|
421
615
|
});
|
|
422
|
-
defineTool(server, "subscriptions_rotate_secret", "Rotate a subscription signing secret. Returns the new plaintext secret once.", { id:
|
|
616
|
+
defineTool(server, "subscriptions_rotate_secret", "Rotate a subscription signing secret. Returns the new plaintext secret once.", { id: z8.string() }, async ({ id }) => {
|
|
423
617
|
const res = await clientProvider().subscriptions.rotateSecret(id);
|
|
424
618
|
return {
|
|
425
619
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
426
620
|
};
|
|
427
621
|
});
|
|
428
622
|
defineTool(server, "subscriptions_replay", "Replay a block range for a subscription. Replays run at 10% of batch capacity — use sparingly.", {
|
|
429
|
-
id:
|
|
430
|
-
fromBlock:
|
|
431
|
-
toBlock:
|
|
623
|
+
id: z8.string(),
|
|
624
|
+
fromBlock: z8.number().int().nonnegative(),
|
|
625
|
+
toBlock: z8.number().int().nonnegative()
|
|
432
626
|
}, async ({ id, fromBlock, toBlock }) => {
|
|
433
627
|
const res = await clientProvider().subscriptions.replay(id, {
|
|
434
628
|
fromBlock,
|
|
@@ -438,22 +632,22 @@ function registerSubscriptionTools(server, clientProvider = getClient) {
|
|
|
438
632
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
439
633
|
};
|
|
440
634
|
});
|
|
441
|
-
defineTool(server, "subscriptions_dead", "Return the last 100 dead-letter outbox rows for a subscription.", { id:
|
|
635
|
+
defineTool(server, "subscriptions_dead", "Return the last 100 dead-letter outbox rows for a subscription.", { id: z8.string() }, async ({ id }) => {
|
|
442
636
|
const { data } = await clientProvider().subscriptions.dead(id);
|
|
443
637
|
return {
|
|
444
638
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
445
639
|
};
|
|
446
640
|
});
|
|
447
641
|
defineTool(server, "subscriptions_requeue_dead", "Requeue one dead-letter outbox row for delivery retry.", {
|
|
448
|
-
id:
|
|
449
|
-
outboxId:
|
|
642
|
+
id: z8.string(),
|
|
643
|
+
outboxId: z8.string()
|
|
450
644
|
}, async ({ id, outboxId }) => {
|
|
451
645
|
const res = await clientProvider().subscriptions.requeueDead(id, outboxId);
|
|
452
646
|
return {
|
|
453
647
|
content: [{ type: "text", text: JSON.stringify(res, null, 2) }]
|
|
454
648
|
};
|
|
455
649
|
});
|
|
456
|
-
defineTool(server, "subscriptions_recent_deliveries", "Return the last 100 delivery attempts (attempt #, status code, duration, truncated response).", { id:
|
|
650
|
+
defineTool(server, "subscriptions_recent_deliveries", "Return the last 100 delivery attempts (attempt #, status code, duration, truncated response).", { id: z8.string() }, async ({ id }) => {
|
|
457
651
|
const { data } = await clientProvider().subscriptions.recentDeliveries(id);
|
|
458
652
|
return {
|
|
459
653
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
@@ -473,6 +667,10 @@ function createServer() {
|
|
|
473
667
|
registerSubgraphTools(server);
|
|
474
668
|
registerSubscriptionTools(server);
|
|
475
669
|
registerAccountTools(server);
|
|
670
|
+
registerDatasetTools(server);
|
|
671
|
+
registerIndexTools(server);
|
|
672
|
+
registerStreamsTools(server);
|
|
673
|
+
registerContractTools(server);
|
|
476
674
|
registerResources(server);
|
|
477
675
|
return server;
|
|
478
676
|
}
|
|
@@ -480,5 +678,5 @@ export {
|
|
|
480
678
|
createServer
|
|
481
679
|
};
|
|
482
680
|
|
|
483
|
-
//# debugId=
|
|
681
|
+
//# debugId=BA0BE1DE0E196D9164756E2164756E21
|
|
484
682
|
//# sourceMappingURL=index.js.map
|