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