@secondlayer/mcp 3.8.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 CHANGED
@@ -10,7 +10,7 @@ bun add @secondlayer/mcp
10
10
 
11
11
  ## Auth
12
12
 
13
- Most reads are public — subgraph reads, `datasets_*`, `index_*`, and `contracts_find` work with no key. **`streams_*` requires an `SL_API_KEY`** (and the Index tools reject free-tier keys — Build+ for keyed access). Writes (deploy, reindex, delete, subscriptions) and account tools need a key: create one (prefixed `sk-sl_`) in the platform console at https://secondlayer.tools/platform/api-keys and set it as `SL_API_KEY`. Read `secondlayer://context` first — it reports auth state and read-auth tiers.
13
+ Most reads are public — `datasets_*`, `index_*`, and `contracts_find` work with no key. Subgraph tools need an `SL_API_KEY`; separately, **public** subgraphs are anon-readable over HTTP at `GET /v1/subgraphs/<name>/<table>` (`{ rows, next_cursor, tip }` cursor envelope), while private ones need the owning account's key (anon → 404). **`streams_*` requires an `SL_API_KEY`** (and the Index tools reject free-tier keys — Build+ for keyed access). Writes (deploy, publish/unpublish, reindex, delete, subscriptions) and account tools need a key: create one (prefixed `sk-sl_`) in the platform console at https://secondlayer.tools/platform/api-keys and set it as `SL_API_KEY`. Read `secondlayer://context` first — it reports auth state and read-auth tiers.
14
14
 
15
15
  ## Quick Start — Stdio (IDE)
16
16
 
@@ -52,7 +52,7 @@ bunx -p @secondlayer/mcp secondlayer-mcp-http
52
52
 
53
53
  | Domain | Tools |
54
54
  | --- | --- |
55
- | **Subgraphs** (11) | `subgraphs_list`, `subgraphs_get`, `subgraphs_spec`, `subgraphs_query`, `subgraphs_aggregate`, `subgraphs_reindex`, `subgraphs_operation`, `subgraphs_delete`, `subgraphs_deploy`, `subgraphs_read_source`, `subgraphs_codegen` |
55
+ | **Subgraphs** (16) | `subgraphs_list`, `subgraphs_get`, `subgraphs_spec`, `subgraphs_query`, `subgraphs_aggregate`, `subgraphs_reindex`, `subgraphs_operation`, `subgraphs_backfill`, `subgraphs_stop`, `subgraphs_gaps`, `subgraphs_delete`, `subgraphs_deploy`, `subgraphs_publish`, `subgraphs_unpublish`, `subgraphs_read_source`, `subgraphs_codegen` |
56
56
  | **Subscriptions** (12) | `subscriptions_list`, `subscriptions_get`, `subscriptions_create`, `subscriptions_update`, `subscriptions_pause`, `subscriptions_resume`, `subscriptions_delete`, `subscriptions_rotate_secret`, `subscriptions_replay`, `subscriptions_recent_deliveries`, `subscriptions_dead`, `subscriptions_requeue_dead` |
57
57
  | **Datasets** (2) | `datasets_list`, `datasets_query` |
58
58
  | **Index** (4) | `index_ft_transfers`, `index_nft_transfers`, `index_events`, `index_contract_calls` |
@@ -75,6 +75,10 @@ a webhook on raw chain events (contract / event / function / trait) with no
75
75
  subgraph (e.g. `[{ "type": "contract_call", "contractId": "SP....amm",
76
76
  "functionName": "swap-*" }]`).
77
77
 
78
+ ### Subgraph visibility
79
+
80
+ `subgraphs_deploy` takes a `visibility` param (`public` | `private`; defaults: managed → public, BYO `databaseUrl` → private). Flip later with `subgraphs_publish` / `subgraphs_unpublish` — publishing claims the name in the single global public namespace (409 `PUBLIC_NAME_TAKEN` if claimed). Public subgraphs are anon-readable at `GET /v1/subgraphs/<name>/<table>`.
81
+
78
82
  ### `subgraphs_query` enhancements
79
83
 
80
84
  - `fields` — comma-separated column projection (e.g. `"sender,amount_x"`)
package/dist/bin-http.js CHANGED
@@ -61,11 +61,14 @@ async function apiRequest(method, path, body) {
61
61
 
62
62
  // src/lib/format.ts
63
63
  function formatSubgraphSummary(s) {
64
+ const apiUrl = process.env.SECONDLAYER_API_URL || "https://api.secondlayer.tools";
64
65
  return {
65
66
  name: s.name,
66
67
  status: s.status,
67
68
  tables: Array.isArray(s.tables) ? s.tables : Object.keys(s.tables),
68
- lastProcessedBlock: s.lastProcessedBlock
69
+ lastProcessedBlock: s.lastProcessedBlock,
70
+ ...s.visibility ? { visibility: s.visibility } : {},
71
+ ...s.visibility === "public" ? { publicUrl: `${apiUrl}/v1/subgraphs/${s.name}` } : {}
69
72
  };
70
73
  }
71
74
  function withCap(items, cap) {
@@ -217,7 +220,7 @@ var READ_AUTH_TIERS = {
217
220
  datasets: "open — no API key required",
218
221
  index: "anonymous reads allowed; free-tier API keys are rejected (Build+ required)",
219
222
  streams: "API key required (SL_API_KEY) — keyless calls return 401",
220
- subgraphs: "reads public during open beta; writes require an API key"
223
+ 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"
221
224
  };
222
225
  async function buildContext(deps = { clientProvider: getClient }) {
223
226
  const unavailable = "unavailable: set SL_API_KEY";
@@ -727,7 +730,7 @@ import {
727
730
  } from "@secondlayer/subgraphs";
728
731
  import { z as z8 } from "zod/v4";
729
732
  function registerSubgraphTools(server, clientProvider = getClient) {
730
- defineTool(server, "subgraphs_list", "List all deployed subgraphs. Returns summary fields only.", {}, async () => {
733
+ defineTool(server, "subgraphs_list", "List all deployed subgraphs. Returns summary fields only, including visibility — public subgraphs are anon-readable at /v1/subgraphs/<name>.", {}, async () => {
731
734
  const { data } = await clientProvider().subgraphs.list();
732
735
  return {
733
736
  content: [
@@ -760,7 +763,7 @@ function registerSubgraphTools(server, clientProvider = getClient) {
760
763
  ]
761
764
  };
762
765
  });
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>"}.', {
766
+ 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.', {
764
767
  name: z8.string().describe("Subgraph name"),
765
768
  table: z8.string().describe("Table name"),
766
769
  filters: z8.record(z8.string(), z8.string()).optional().describe('Column filters — plain values or with operators (e.g. {"amount.gte": "1000", "sender": "SP..."})'),
@@ -876,12 +879,13 @@ function registerSubgraphTools(server, clientProvider = getClient) {
876
879
  const result = await clientProvider().subgraphs.delete(name);
877
880
  return { content: [{ type: "text", text: result.message }] };
878
881
  });
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. Call `subgraphs_reindex` separately if you need a forced reindex.", {
882
+ 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.", {
880
883
  code: z8.string().describe("TypeScript source code containing a defineSubgraph() call"),
881
884
  startBlock: z8.number().int().nonnegative().optional().describe("Override the definition startBlock for this deploy"),
882
885
  databaseUrl: z8.string().optional().describe("BYO data plane: Postgres connection string to host the subgraph's schema and rows in your own database"),
883
- dryRun: z8.boolean().optional().describe("Validate and preview the deploy (schema/DDL, BYO connection) without writing changes")
884
- }, async ({ code, startBlock, databaseUrl, dryRun }) => {
886
+ dryRun: z8.boolean().optional().describe("Validate and preview the deploy (schema/DDL, BYO connection) without writing changes"),
887
+ 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.")
888
+ }, async ({ code, startBlock, databaseUrl, dryRun, visibility }) => {
885
889
  const bundled = await bundleSubgraphCode(code);
886
890
  try {
887
891
  const result = await clientProvider().subgraphs.deploy({
@@ -894,7 +898,8 @@ function registerSubgraphTools(server, clientProvider = getClient) {
894
898
  sourceCode: code,
895
899
  ...startBlock !== undefined ? { startBlock } : {},
896
900
  ...databaseUrl !== undefined ? { databaseUrl } : {},
897
- ...dryRun !== undefined ? { dryRun } : {}
901
+ ...dryRun !== undefined ? { dryRun } : {},
902
+ ...visibility !== undefined ? { visibility } : {}
898
903
  });
899
904
  return {
900
905
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
@@ -913,6 +918,18 @@ function registerSubgraphTools(server, clientProvider = getClient) {
913
918
  throw err;
914
919
  }
915
920
  });
921
+ 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 }) => {
922
+ const result = await clientProvider().subgraphs.publish(name);
923
+ return {
924
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
925
+ };
926
+ });
927
+ 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 }) => {
928
+ const result = await clientProvider().subgraphs.unpublish(name);
929
+ return {
930
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
931
+ };
932
+ });
916
933
  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 }) => {
917
934
  const source = await clientProvider().subgraphs.getSource(name);
918
935
  return {
@@ -1203,5 +1220,5 @@ httpServer.listen(port, () => {
1203
1220
  console.error("Warning: SECONDLAYER_MCP_SECRET not set, authentication disabled");
1204
1221
  });
1205
1222
 
1206
- //# debugId=4D2E7E6934E70FD064756E2164756E21
1223
+ //# debugId=38C3E42509C42A3264756E2164756E21
1207
1224
  //# sourceMappingURL=bin-http.js.map