@secondlayer/mcp 3.7.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/bin-http.js +92 -22
- package/dist/bin-http.js.map +8 -8
- package/dist/bin.js +92 -22
- package/dist/bin.js.map +8 -8
- package/dist/index.js +92 -22
- package/dist/index.js.map +8 -8
- package/package.json +5 -5
package/dist/bin.js
CHANGED
|
@@ -58,11 +58,14 @@ async function apiRequest(method, path, body) {
|
|
|
58
58
|
|
|
59
59
|
// src/lib/format.ts
|
|
60
60
|
function formatSubgraphSummary(s) {
|
|
61
|
+
const apiUrl = process.env.SECONDLAYER_API_URL || "https://api.secondlayer.tools";
|
|
61
62
|
return {
|
|
62
63
|
name: s.name,
|
|
63
64
|
status: s.status,
|
|
64
65
|
tables: Array.isArray(s.tables) ? s.tables : Object.keys(s.tables),
|
|
65
|
-
lastProcessedBlock: s.lastProcessedBlock
|
|
66
|
+
lastProcessedBlock: s.lastProcessedBlock,
|
|
67
|
+
...s.visibility ? { visibility: s.visibility } : {},
|
|
68
|
+
...s.visibility === "public" ? { publicUrl: `${apiUrl}/v1/subgraphs/${s.name}` } : {}
|
|
66
69
|
};
|
|
67
70
|
}
|
|
68
71
|
function withCap(items, cap) {
|
|
@@ -214,7 +217,7 @@ var READ_AUTH_TIERS = {
|
|
|
214
217
|
datasets: "open — no API key required",
|
|
215
218
|
index: "anonymous reads allowed; free-tier API keys are rejected (Build+ required)",
|
|
216
219
|
streams: "API key required (SL_API_KEY) — keyless calls return 401",
|
|
217
|
-
subgraphs: "
|
|
220
|
+
subgraphs: "public subgraphs anon-readable at /v1/subgraphs/<name>/<table> ({ rows, next_cursor, tip } cursor envelope); private subgraphs need the owning account's API key (anon → 404); writes require an API key"
|
|
218
221
|
};
|
|
219
222
|
async function buildContext(deps = { clientProvider: getClient }) {
|
|
220
223
|
const unavailable = "unavailable: set SL_API_KEY";
|
|
@@ -368,6 +371,7 @@ function registerAccountTools(server) {
|
|
|
368
371
|
}
|
|
369
372
|
|
|
370
373
|
// src/tools/contracts.ts
|
|
374
|
+
import { generateContractInterface } from "@secondlayer/scaffold";
|
|
371
375
|
import { z as z2 } from "zod/v4";
|
|
372
376
|
function registerContractTools(server, clientProvider = getClient) {
|
|
373
377
|
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.', {
|
|
@@ -377,6 +381,47 @@ function registerContractTools(server, clientProvider = getClient) {
|
|
|
377
381
|
limit: z2.number().optional().describe("Page size, 1–500 (default 100)"),
|
|
378
382
|
cursor: z2.string().optional().describe("Opaque cursor from a prior response's next_cursor")
|
|
379
383
|
}, async (params) => jsonResponse(await clientProvider().contracts.list(params)));
|
|
384
|
+
defineTool(server, "get_contract_abi", "Fetch a single deployed contract's ABI from the registry (prod-safe). Returns the contract's metadata + full ABI (functions, maps, variables, fungible/non-fungible tokens). Returns not_found if the contract isn't in the registry. Feed the ABI into scaffold_from_abi or generate a typed client.", {
|
|
385
|
+
contractId: z2.string().describe("Fully qualified contract id (e.g. SP….amm-pool-v2-01)")
|
|
386
|
+
}, async ({ contractId }) => {
|
|
387
|
+
const contract = await clientProvider().contracts.get(contractId, {
|
|
388
|
+
includeAbi: true
|
|
389
|
+
});
|
|
390
|
+
return contract ? jsonResponse(contract) : jsonResponse({
|
|
391
|
+
error: {
|
|
392
|
+
type: "not_found",
|
|
393
|
+
status: 404,
|
|
394
|
+
message: `Contract not in registry: ${contractId}`
|
|
395
|
+
}
|
|
396
|
+
}, true);
|
|
397
|
+
});
|
|
398
|
+
defineTool(server, "generate_contract_interface", "Generate a typed TypeScript contract-client interface (typed methods + map/var/constant readers) from a deployed contract's ABI (fetched from the registry). Returns not_found if the contract isn't in the registry.", {
|
|
399
|
+
contractId: z2.string().describe("Fully qualified contract id (e.g. SP….amm-pool-v2-01)")
|
|
400
|
+
}, async ({ contractId }) => {
|
|
401
|
+
const c = await clientProvider().contracts.get(contractId, {
|
|
402
|
+
includeAbi: true
|
|
403
|
+
});
|
|
404
|
+
if (!c || !c.abi) {
|
|
405
|
+
return jsonResponse({
|
|
406
|
+
error: {
|
|
407
|
+
type: "not_found",
|
|
408
|
+
status: 404,
|
|
409
|
+
message: `Contract not in registry: ${contractId}`
|
|
410
|
+
}
|
|
411
|
+
}, true);
|
|
412
|
+
}
|
|
413
|
+
const [address, contractName] = contractId.split(".");
|
|
414
|
+
const name = (contractName ?? contractId).replace(/[^a-zA-Z0-9]/g, "_");
|
|
415
|
+
const code = generateContractInterface([
|
|
416
|
+
{
|
|
417
|
+
name,
|
|
418
|
+
address,
|
|
419
|
+
contractName: contractName ?? "",
|
|
420
|
+
abi: c.abi
|
|
421
|
+
}
|
|
422
|
+
]);
|
|
423
|
+
return { content: [{ type: "text", text: code }] };
|
|
424
|
+
});
|
|
380
425
|
}
|
|
381
426
|
|
|
382
427
|
// src/tools/datasets.ts
|
|
@@ -467,6 +512,10 @@ function registerIndexTools(server, clientProvider = getClient) {
|
|
|
467
512
|
const tx = await clientProvider().index.transactions.get(txId);
|
|
468
513
|
return tx ? jsonResponse(tx) : notFound(`No transaction for ${txId}`);
|
|
469
514
|
});
|
|
515
|
+
defineTool(server, "index_transaction_proof", "Fetch a transaction's inclusion proof (raw tx + signed Nakamoto block header + merkle path) so it can be verified trustlessly client-side with the SDK's verifyTransactionProof. Returns not_found if the tx/block is unknown; a 503 means the proof can't be assembled on this deployment right now (PROOF_TX_SET_INCOMPLETE, or PROOF_NODE_UNAVAILABLE when the stacks-node header source isn't configured).", { txId: z4.string().describe("Transaction id (0x… hash)") }, async ({ txId }) => {
|
|
516
|
+
const proof = await clientProvider().index.transactions.getProof(txId);
|
|
517
|
+
return proof ? jsonResponse(proof) : notFound(`No proof available for ${txId}`);
|
|
518
|
+
});
|
|
470
519
|
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).", {
|
|
471
520
|
...heightFilters,
|
|
472
521
|
functionName: z4.string().optional().describe("Filter by PoX function name"),
|
|
@@ -531,25 +580,32 @@ function registerProjectTools(server, clientProvider = getClient) {
|
|
|
531
580
|
}
|
|
532
581
|
|
|
533
582
|
// src/tools/scaffold.ts
|
|
534
|
-
import {
|
|
583
|
+
import {
|
|
584
|
+
generateSubgraphCode,
|
|
585
|
+
generateTraitSubgraph
|
|
586
|
+
} from "@secondlayer/scaffold";
|
|
587
|
+
import { TRAIT_STANDARDS as TRAIT_STANDARDS2 } from "@secondlayer/stacks/clarity";
|
|
535
588
|
import { z as z6 } from "zod/v4";
|
|
536
|
-
var API_BASE = process.env.SECONDLAYER_API_URL || "https://api.secondlayer.tools";
|
|
537
589
|
async function fetchAbi(contractId) {
|
|
538
|
-
const
|
|
539
|
-
|
|
590
|
+
const contract = await getClient().contracts.get(contractId, {
|
|
591
|
+
includeAbi: true
|
|
540
592
|
});
|
|
541
|
-
if (!
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
593
|
+
if (!contract)
|
|
594
|
+
throw new Error(`Contract not found: ${contractId}`);
|
|
595
|
+
const abi = contract.abi;
|
|
596
|
+
if (!abi) {
|
|
597
|
+
throw new Error(`No ABI available for ${contractId} (abi_status: ${contract.abi_status})`);
|
|
545
598
|
}
|
|
546
|
-
|
|
547
|
-
return {
|
|
548
|
-
functions: abi.functions ?? [],
|
|
549
|
-
maps: abi.maps ?? []
|
|
550
|
-
};
|
|
599
|
+
return { functions: abi.functions ?? [], maps: abi.maps ?? [] };
|
|
551
600
|
}
|
|
552
601
|
function registerScaffoldTools(server) {
|
|
602
|
+
defineTool(server, "scaffold_from_trait", "Generate a deploy-ready subgraph scaffold that indexes EVERY contract conforming to a SIP trait (no specific contract needed) — sip-009 → an nft_transfer source, sip-010/sip-013 → ft_transfer. Use scaffold_from_contract/abi instead when targeting one contract. See the secondlayer://traits resource for valid trait ids.", {
|
|
603
|
+
trait: z6.enum(TRAIT_STANDARDS2).describe("SIP standard to index (sip-009 | sip-010 | sip-013)"),
|
|
604
|
+
subgraphName: z6.string().optional().describe("Override the subgraph name (defaults to <trait>-transfers)")
|
|
605
|
+
}, async ({ trait, subgraphName }) => {
|
|
606
|
+
const code = generateTraitSubgraph({ trait, name: subgraphName });
|
|
607
|
+
return { content: [{ type: "text", text: code }] };
|
|
608
|
+
});
|
|
553
609
|
defineTool(server, "scaffold_from_contract", "Generate a subgraph scaffold from a deployed Stacks contract. Fetches the ABI automatically.", {
|
|
554
610
|
contractId: z6.string().describe("Fully qualified contract ID (e.g. SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-pool-v2-01)"),
|
|
555
611
|
subgraphName: z6.string().optional().describe("Override the subgraph name (defaults to contract name)")
|
|
@@ -671,7 +727,7 @@ import {
|
|
|
671
727
|
} from "@secondlayer/subgraphs";
|
|
672
728
|
import { z as z8 } from "zod/v4";
|
|
673
729
|
function registerSubgraphTools(server, clientProvider = getClient) {
|
|
674
|
-
defineTool(server, "subgraphs_list", "List all deployed subgraphs. Returns summary fields only
|
|
730
|
+
defineTool(server, "subgraphs_list", "List all deployed subgraphs. Returns summary fields only, including visibility — public subgraphs are anon-readable at /v1/subgraphs/<name>.", {}, async () => {
|
|
675
731
|
const { data } = await clientProvider().subgraphs.list();
|
|
676
732
|
return {
|
|
677
733
|
content: [
|
|
@@ -704,7 +760,7 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
704
760
|
]
|
|
705
761
|
};
|
|
706
762
|
});
|
|
707
|
-
defineTool(server, "subgraphs_query", 'Query rows from a subgraph table (max 200 rows). Filters support operators: "amount.gte": "1000", "sender.neq": "SP...", "name.like": "%token%". Available operators: eq, neq, gt, gte, lt, lte, like. To TAIL new rows (no streaming over MCP): sort=_id, order=desc for the latest, then poll forward with the filter {"_id.gt": "<last _id seen>"}, order=asc. Fetch one row by id with {"_id": "<id>"}.', {
|
|
763
|
+
defineTool(server, "subgraphs_query", 'Query rows from a subgraph table (max 200 rows). Filters support operators: "amount.gte": "1000", "sender.neq": "SP...", "name.like": "%token%". Available operators: eq, neq, gt, gte, lt, lte, like. To TAIL new rows (no streaming over MCP): sort=_id, order=desc for the latest, then poll forward with the filter {"_id.gt": "<last _id seen>"}, order=asc. Fetch one row by id with {"_id": "<id>"}. Public subgraphs are also keyless over HTTP at GET /v1/subgraphs/<name>/<table> — { rows, next_cursor, tip } envelope, resume with ?cursor=<next_cursor> + _order=asc|desc (no _offset/_sort on /v1); hand that URL to third parties.', {
|
|
708
764
|
name: z8.string().describe("Subgraph name"),
|
|
709
765
|
table: z8.string().describe("Table name"),
|
|
710
766
|
filters: z8.record(z8.string(), z8.string()).optional().describe('Column filters — plain values or with operators (e.g. {"amount.gte": "1000", "sender": "SP..."})'),
|
|
@@ -820,12 +876,13 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
820
876
|
const result = await clientProvider().subgraphs.delete(name);
|
|
821
877
|
return { content: [{ type: "text", text: result.message }] };
|
|
822
878
|
});
|
|
823
|
-
defineTool(server, "subgraphs_deploy", "Deploy a subgraph from TypeScript code. Pass the full defineSubgraph() source — it will be bundled, validated, and deployed. Optional startBlock overrides the source definition for this deploy. Set dryRun to validate and preview the schema/DDL without writing anything. Set databaseUrl to deploy to your own Postgres (BYO data plane) — the server verifies the connection first; with dryRun it returns the DDL + grant script. A breaking BYO schema change is refused and returns a migration plan (drop + rebuild DDL) instead of deploying. Call `subgraphs_reindex` separately if you need a forced reindex.", {
|
|
879
|
+
defineTool(server, "subgraphs_deploy", "Deploy a subgraph from TypeScript code. Pass the full defineSubgraph() source — it will be bundled, validated, and deployed. Optional startBlock overrides the source definition for this deploy. Set dryRun to validate and preview the schema/DDL without writing anything. Set databaseUrl to deploy to your own Postgres (BYO data plane) — the server verifies the connection first; with dryRun it returns the DDL + grant script. A breaking BYO schema change is refused and returns a migration plan (drop + rebuild DDL) instead of deploying. Visibility defaults: managed deploys are public (anon-readable at /v1/subgraphs/<name>, name claimed in the global public namespace), BYO deploys are private. Call `subgraphs_reindex` separately if you need a forced reindex.", {
|
|
824
880
|
code: z8.string().describe("TypeScript source code containing a defineSubgraph() call"),
|
|
825
881
|
startBlock: z8.number().int().nonnegative().optional().describe("Override the definition startBlock for this deploy"),
|
|
826
882
|
databaseUrl: z8.string().optional().describe("BYO data plane: Postgres connection string to host the subgraph's schema and rows in your own database"),
|
|
827
|
-
dryRun: z8.boolean().optional().describe("Validate and preview the deploy (schema/DDL, BYO connection) without writing changes")
|
|
828
|
-
|
|
883
|
+
dryRun: z8.boolean().optional().describe("Validate and preview the deploy (schema/DDL, BYO connection) without writing changes"),
|
|
884
|
+
visibility: z8.enum(["public", "private"]).optional().describe("Read visibility: public = anon /v1 reads + global name claim; private = owning account's key only. Defaults: managed → public, BYO → private.")
|
|
885
|
+
}, async ({ code, startBlock, databaseUrl, dryRun, visibility }) => {
|
|
829
886
|
const bundled = await bundleSubgraphCode(code);
|
|
830
887
|
try {
|
|
831
888
|
const result = await clientProvider().subgraphs.deploy({
|
|
@@ -838,7 +895,8 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
838
895
|
sourceCode: code,
|
|
839
896
|
...startBlock !== undefined ? { startBlock } : {},
|
|
840
897
|
...databaseUrl !== undefined ? { databaseUrl } : {},
|
|
841
|
-
...dryRun !== undefined ? { dryRun } : {}
|
|
898
|
+
...dryRun !== undefined ? { dryRun } : {},
|
|
899
|
+
...visibility !== undefined ? { visibility } : {}
|
|
842
900
|
});
|
|
843
901
|
return {
|
|
844
902
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
@@ -857,6 +915,18 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
857
915
|
throw err;
|
|
858
916
|
}
|
|
859
917
|
});
|
|
918
|
+
defineTool(server, "subgraphs_publish", "Make a subgraph publicly readable at /v1/subgraphs/<name> — anyone (or any agent) can read it without a key. Claims the name in the global public namespace; fails with PUBLIC_NAME_TAKEN if another account holds it.", { name: z8.string().describe("Subgraph name") }, async ({ name }) => {
|
|
919
|
+
const result = await clientProvider().subgraphs.publish(name);
|
|
920
|
+
return {
|
|
921
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
922
|
+
};
|
|
923
|
+
});
|
|
924
|
+
defineTool(server, "subgraphs_unpublish", "Make a subgraph private again — /v1 reads then require the owning account's bearer key, and the global public name claim is released.", { name: z8.string().describe("Subgraph name") }, async ({ name }) => {
|
|
925
|
+
const result = await clientProvider().subgraphs.unpublish(name);
|
|
926
|
+
return {
|
|
927
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
928
|
+
};
|
|
929
|
+
});
|
|
860
930
|
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: z8.string().describe("Subgraph name") }, async ({ name }) => {
|
|
861
931
|
const source = await clientProvider().subgraphs.getSource(name);
|
|
862
932
|
return {
|
|
@@ -1066,5 +1136,5 @@ var server = createServer();
|
|
|
1066
1136
|
var transport = new StdioServerTransport;
|
|
1067
1137
|
await server.connect(transport);
|
|
1068
1138
|
|
|
1069
|
-
//# debugId=
|
|
1139
|
+
//# debugId=9CFDE0E3EC20CFB264756E2164756E21
|
|
1070
1140
|
//# sourceMappingURL=bin.js.map
|