@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/index.js
CHANGED
|
@@ -53,11 +53,14 @@ async function apiRequest(method, path, body) {
|
|
|
53
53
|
|
|
54
54
|
// src/lib/format.ts
|
|
55
55
|
function formatSubgraphSummary(s) {
|
|
56
|
+
const apiUrl = process.env.SECONDLAYER_API_URL || "https://api.secondlayer.tools";
|
|
56
57
|
return {
|
|
57
58
|
name: s.name,
|
|
58
59
|
status: s.status,
|
|
59
60
|
tables: Array.isArray(s.tables) ? s.tables : Object.keys(s.tables),
|
|
60
|
-
lastProcessedBlock: s.lastProcessedBlock
|
|
61
|
+
lastProcessedBlock: s.lastProcessedBlock,
|
|
62
|
+
...s.visibility ? { visibility: s.visibility } : {},
|
|
63
|
+
...s.visibility === "public" ? { publicUrl: `${apiUrl}/v1/subgraphs/${s.name}` } : {}
|
|
61
64
|
};
|
|
62
65
|
}
|
|
63
66
|
function withCap(items, cap) {
|
|
@@ -209,7 +212,7 @@ var READ_AUTH_TIERS = {
|
|
|
209
212
|
datasets: "open — no API key required",
|
|
210
213
|
index: "anonymous reads allowed; free-tier API keys are rejected (Build+ required)",
|
|
211
214
|
streams: "API key required (SL_API_KEY) — keyless calls return 401",
|
|
212
|
-
subgraphs: "
|
|
215
|
+
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"
|
|
213
216
|
};
|
|
214
217
|
async function buildContext(deps = { clientProvider: getClient }) {
|
|
215
218
|
const unavailable = "unavailable: set SL_API_KEY";
|
|
@@ -363,6 +366,7 @@ function registerAccountTools(server) {
|
|
|
363
366
|
}
|
|
364
367
|
|
|
365
368
|
// src/tools/contracts.ts
|
|
369
|
+
import { generateContractInterface } from "@secondlayer/scaffold";
|
|
366
370
|
import { z as z2 } from "zod/v4";
|
|
367
371
|
function registerContractTools(server, clientProvider = getClient) {
|
|
368
372
|
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.', {
|
|
@@ -372,6 +376,47 @@ function registerContractTools(server, clientProvider = getClient) {
|
|
|
372
376
|
limit: z2.number().optional().describe("Page size, 1–500 (default 100)"),
|
|
373
377
|
cursor: z2.string().optional().describe("Opaque cursor from a prior response's next_cursor")
|
|
374
378
|
}, async (params) => jsonResponse(await clientProvider().contracts.list(params)));
|
|
379
|
+
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.", {
|
|
380
|
+
contractId: z2.string().describe("Fully qualified contract id (e.g. SP….amm-pool-v2-01)")
|
|
381
|
+
}, async ({ contractId }) => {
|
|
382
|
+
const contract = await clientProvider().contracts.get(contractId, {
|
|
383
|
+
includeAbi: true
|
|
384
|
+
});
|
|
385
|
+
return contract ? jsonResponse(contract) : jsonResponse({
|
|
386
|
+
error: {
|
|
387
|
+
type: "not_found",
|
|
388
|
+
status: 404,
|
|
389
|
+
message: `Contract not in registry: ${contractId}`
|
|
390
|
+
}
|
|
391
|
+
}, true);
|
|
392
|
+
});
|
|
393
|
+
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.", {
|
|
394
|
+
contractId: z2.string().describe("Fully qualified contract id (e.g. SP….amm-pool-v2-01)")
|
|
395
|
+
}, async ({ contractId }) => {
|
|
396
|
+
const c = await clientProvider().contracts.get(contractId, {
|
|
397
|
+
includeAbi: true
|
|
398
|
+
});
|
|
399
|
+
if (!c || !c.abi) {
|
|
400
|
+
return jsonResponse({
|
|
401
|
+
error: {
|
|
402
|
+
type: "not_found",
|
|
403
|
+
status: 404,
|
|
404
|
+
message: `Contract not in registry: ${contractId}`
|
|
405
|
+
}
|
|
406
|
+
}, true);
|
|
407
|
+
}
|
|
408
|
+
const [address, contractName] = contractId.split(".");
|
|
409
|
+
const name = (contractName ?? contractId).replace(/[^a-zA-Z0-9]/g, "_");
|
|
410
|
+
const code = generateContractInterface([
|
|
411
|
+
{
|
|
412
|
+
name,
|
|
413
|
+
address,
|
|
414
|
+
contractName: contractName ?? "",
|
|
415
|
+
abi: c.abi
|
|
416
|
+
}
|
|
417
|
+
]);
|
|
418
|
+
return { content: [{ type: "text", text: code }] };
|
|
419
|
+
});
|
|
375
420
|
}
|
|
376
421
|
|
|
377
422
|
// src/tools/datasets.ts
|
|
@@ -462,6 +507,10 @@ function registerIndexTools(server, clientProvider = getClient) {
|
|
|
462
507
|
const tx = await clientProvider().index.transactions.get(txId);
|
|
463
508
|
return tx ? jsonResponse(tx) : notFound(`No transaction for ${txId}`);
|
|
464
509
|
});
|
|
510
|
+
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 }) => {
|
|
511
|
+
const proof = await clientProvider().index.transactions.getProof(txId);
|
|
512
|
+
return proof ? jsonResponse(proof) : notFound(`No proof available for ${txId}`);
|
|
513
|
+
});
|
|
465
514
|
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).", {
|
|
466
515
|
...heightFilters,
|
|
467
516
|
functionName: z4.string().optional().describe("Filter by PoX function name"),
|
|
@@ -526,25 +575,32 @@ function registerProjectTools(server, clientProvider = getClient) {
|
|
|
526
575
|
}
|
|
527
576
|
|
|
528
577
|
// src/tools/scaffold.ts
|
|
529
|
-
import {
|
|
578
|
+
import {
|
|
579
|
+
generateSubgraphCode,
|
|
580
|
+
generateTraitSubgraph
|
|
581
|
+
} from "@secondlayer/scaffold";
|
|
582
|
+
import { TRAIT_STANDARDS as TRAIT_STANDARDS2 } from "@secondlayer/stacks/clarity";
|
|
530
583
|
import { z as z6 } from "zod/v4";
|
|
531
|
-
var API_BASE = process.env.SECONDLAYER_API_URL || "https://api.secondlayer.tools";
|
|
532
584
|
async function fetchAbi(contractId) {
|
|
533
|
-
const
|
|
534
|
-
|
|
585
|
+
const contract = await getClient().contracts.get(contractId, {
|
|
586
|
+
includeAbi: true
|
|
535
587
|
});
|
|
536
|
-
if (!
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
588
|
+
if (!contract)
|
|
589
|
+
throw new Error(`Contract not found: ${contractId}`);
|
|
590
|
+
const abi = contract.abi;
|
|
591
|
+
if (!abi) {
|
|
592
|
+
throw new Error(`No ABI available for ${contractId} (abi_status: ${contract.abi_status})`);
|
|
540
593
|
}
|
|
541
|
-
|
|
542
|
-
return {
|
|
543
|
-
functions: abi.functions ?? [],
|
|
544
|
-
maps: abi.maps ?? []
|
|
545
|
-
};
|
|
594
|
+
return { functions: abi.functions ?? [], maps: abi.maps ?? [] };
|
|
546
595
|
}
|
|
547
596
|
function registerScaffoldTools(server) {
|
|
597
|
+
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.", {
|
|
598
|
+
trait: z6.enum(TRAIT_STANDARDS2).describe("SIP standard to index (sip-009 | sip-010 | sip-013)"),
|
|
599
|
+
subgraphName: z6.string().optional().describe("Override the subgraph name (defaults to <trait>-transfers)")
|
|
600
|
+
}, async ({ trait, subgraphName }) => {
|
|
601
|
+
const code = generateTraitSubgraph({ trait, name: subgraphName });
|
|
602
|
+
return { content: [{ type: "text", text: code }] };
|
|
603
|
+
});
|
|
548
604
|
defineTool(server, "scaffold_from_contract", "Generate a subgraph scaffold from a deployed Stacks contract. Fetches the ABI automatically.", {
|
|
549
605
|
contractId: z6.string().describe("Fully qualified contract ID (e.g. SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-pool-v2-01)"),
|
|
550
606
|
subgraphName: z6.string().optional().describe("Override the subgraph name (defaults to contract name)")
|
|
@@ -666,7 +722,7 @@ import {
|
|
|
666
722
|
} from "@secondlayer/subgraphs";
|
|
667
723
|
import { z as z8 } from "zod/v4";
|
|
668
724
|
function registerSubgraphTools(server, clientProvider = getClient) {
|
|
669
|
-
defineTool(server, "subgraphs_list", "List all deployed subgraphs. Returns summary fields only
|
|
725
|
+
defineTool(server, "subgraphs_list", "List all deployed subgraphs. Returns summary fields only, including visibility — public subgraphs are anon-readable at /v1/subgraphs/<name>.", {}, async () => {
|
|
670
726
|
const { data } = await clientProvider().subgraphs.list();
|
|
671
727
|
return {
|
|
672
728
|
content: [
|
|
@@ -699,7 +755,7 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
699
755
|
]
|
|
700
756
|
};
|
|
701
757
|
});
|
|
702
|
-
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>"}.', {
|
|
758
|
+
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.', {
|
|
703
759
|
name: z8.string().describe("Subgraph name"),
|
|
704
760
|
table: z8.string().describe("Table name"),
|
|
705
761
|
filters: z8.record(z8.string(), z8.string()).optional().describe('Column filters — plain values or with operators (e.g. {"amount.gte": "1000", "sender": "SP..."})'),
|
|
@@ -815,12 +871,13 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
815
871
|
const result = await clientProvider().subgraphs.delete(name);
|
|
816
872
|
return { content: [{ type: "text", text: result.message }] };
|
|
817
873
|
});
|
|
818
|
-
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.", {
|
|
874
|
+
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.", {
|
|
819
875
|
code: z8.string().describe("TypeScript source code containing a defineSubgraph() call"),
|
|
820
876
|
startBlock: z8.number().int().nonnegative().optional().describe("Override the definition startBlock for this deploy"),
|
|
821
877
|
databaseUrl: z8.string().optional().describe("BYO data plane: Postgres connection string to host the subgraph's schema and rows in your own database"),
|
|
822
|
-
dryRun: z8.boolean().optional().describe("Validate and preview the deploy (schema/DDL, BYO connection) without writing changes")
|
|
823
|
-
|
|
878
|
+
dryRun: z8.boolean().optional().describe("Validate and preview the deploy (schema/DDL, BYO connection) without writing changes"),
|
|
879
|
+
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.")
|
|
880
|
+
}, async ({ code, startBlock, databaseUrl, dryRun, visibility }) => {
|
|
824
881
|
const bundled = await bundleSubgraphCode(code);
|
|
825
882
|
try {
|
|
826
883
|
const result = await clientProvider().subgraphs.deploy({
|
|
@@ -833,7 +890,8 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
833
890
|
sourceCode: code,
|
|
834
891
|
...startBlock !== undefined ? { startBlock } : {},
|
|
835
892
|
...databaseUrl !== undefined ? { databaseUrl } : {},
|
|
836
|
-
...dryRun !== undefined ? { dryRun } : {}
|
|
893
|
+
...dryRun !== undefined ? { dryRun } : {},
|
|
894
|
+
...visibility !== undefined ? { visibility } : {}
|
|
837
895
|
});
|
|
838
896
|
return {
|
|
839
897
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
@@ -852,6 +910,18 @@ function registerSubgraphTools(server, clientProvider = getClient) {
|
|
|
852
910
|
throw err;
|
|
853
911
|
}
|
|
854
912
|
});
|
|
913
|
+
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 }) => {
|
|
914
|
+
const result = await clientProvider().subgraphs.publish(name);
|
|
915
|
+
return {
|
|
916
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
917
|
+
};
|
|
918
|
+
});
|
|
919
|
+
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 }) => {
|
|
920
|
+
const result = await clientProvider().subgraphs.unpublish(name);
|
|
921
|
+
return {
|
|
922
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
923
|
+
};
|
|
924
|
+
});
|
|
855
925
|
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 }) => {
|
|
856
926
|
const source = await clientProvider().subgraphs.getSource(name);
|
|
857
927
|
return {
|
|
@@ -1059,5 +1129,5 @@ export {
|
|
|
1059
1129
|
createServer
|
|
1060
1130
|
};
|
|
1061
1131
|
|
|
1062
|
-
//# debugId=
|
|
1132
|
+
//# debugId=00B1F28CFDA24A4764756E2164756E21
|
|
1063
1133
|
//# sourceMappingURL=index.js.map
|