subgraph-registry-mcp 0.8.30 → 0.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 +37 -0
- package/data/openapi.json +1 -1
- package/data/registry.db +0 -0
- package/openapi.yaml +1 -1
- package/package.json +4 -3
- package/src/index.js +185 -9
package/README.md
CHANGED
|
@@ -159,6 +159,43 @@ All values are log-scaled and capped at 1.0. A 0.5 penalty is applied if the sub
|
|
|
159
159
|
|
|
160
160
|
**Score tiers:** High (0.7+) = strong signal, real usage | Medium (0.3-0.7) = functional, some activity | Low (<0.3) = minimal signal or test deployment
|
|
161
161
|
|
|
162
|
+
### The score measures traction, so it measures age
|
|
163
|
+
|
|
164
|
+
All four inputs are cumulative — fees and curation accrue, volume needs 30 days
|
|
165
|
+
to exist at all. A subgraph deployed last month therefore scores near zero no
|
|
166
|
+
matter how good it is. Measured on the current corpus (served, non-denied):
|
|
167
|
+
|
|
168
|
+
| Age | Count | Avg reliability |
|
|
169
|
+
|-----|-------|-----------------|
|
|
170
|
+
| < 30 days | 64 | 0.107 |
|
|
171
|
+
| 30–90 days | 227 | 0.143 |
|
|
172
|
+
| 90–365 days | 1,100 | 0.225 |
|
|
173
|
+
| > 1 year | 4,034 | 0.313 |
|
|
174
|
+
|
|
175
|
+
The newest subgraph anywhere in the registry's top 25 is **280 days old** — yet
|
|
176
|
+
59 of those 64 sub-30-day subgraphs are already serving real query volume.
|
|
177
|
+
|
|
178
|
+
Rather than reweight the score and trade a measurable signal for a guess,
|
|
179
|
+
`search_subgraphs` returns young matches in a **separate `emerging` list**
|
|
180
|
+
alongside an `emerging_caveat` explaining that a low score at that age is
|
|
181
|
+
expected rather than damning. Every result also carries `age_days` and
|
|
182
|
+
`maturity` (`new` < 30d, `emerging` < 90d, `established`). This matters most
|
|
183
|
+
for new chains and new protocols, where no mature deployment *can* exist —
|
|
184
|
+
searching "perpetual futures" surfaces years-old Ethereum and BSC deployments
|
|
185
|
+
in the main list and the 40-day-old Monad perps subgraph under `emerging`.
|
|
186
|
+
|
|
187
|
+
`semantic_search_subgraphs` ranks by cosine similarity rather than reliability,
|
|
188
|
+
so it is already age-neutral — it carries the `maturity` labels but no
|
|
189
|
+
`emerging` list, because a three-week-old subgraph can top it on merit.
|
|
190
|
+
|
|
191
|
+
### Denied deployments
|
|
192
|
+
|
|
193
|
+
Curation-denied deployments (`deniedAt > 0` — denied indexing rewards, usually
|
|
194
|
+
spam, duplicates or deprecations) are **excluded by default** from
|
|
195
|
+
`search_subgraphs`, `semantic_search_subgraphs` and `recommend_subgraph`. Pass
|
|
196
|
+
`include_denied: true` to the two search tools to see them; every result then
|
|
197
|
+
carries `denied: true|false` so the choice stays visible.
|
|
198
|
+
|
|
162
199
|
---
|
|
163
200
|
|
|
164
201
|
## MCP Server
|
package/data/openapi.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Subgraph Registry",
|
|
5
5
|
"description": "Agent-friendly subgraph discovery on The Graph Network. 14,700+ classified subgraphs with semantic search, reliability scoring, schema-evolution tracking, and x402 query URLs ($0.01 USDC on Base, no API key).",
|
|
6
|
-
"version": "0.8.
|
|
6
|
+
"version": "0.8.31",
|
|
7
7
|
"license": {
|
|
8
8
|
"name": "MIT"
|
|
9
9
|
},
|
package/data/registry.db
CHANGED
|
Binary file
|
package/openapi.yaml
CHANGED
|
@@ -5,7 +5,7 @@ openapi: "3.1.0"
|
|
|
5
5
|
info:
|
|
6
6
|
title: "Subgraph Registry"
|
|
7
7
|
description: "Agent-friendly subgraph discovery on The Graph Network. 14,700+ classified subgraphs with semantic search, reliability scoring, schema-evolution tracking, and x402 query URLs ($0.01 USDC on Base, no API key)."
|
|
8
|
-
version: "0.8.
|
|
8
|
+
version: "0.8.31"
|
|
9
9
|
license:
|
|
10
10
|
name: "MIT"
|
|
11
11
|
contact:
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subgraph-registry-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"mcpName": "io.github.PaulieB14/subgraph-registry-mcp",
|
|
5
|
-
"description": "MCP server for agent-friendly subgraph discovery on The Graph Network. 15,
|
|
5
|
+
"description": "MCP server for agent-friendly subgraph discovery on The Graph Network. 15,330 classified subgraphs with x402 query URLs ($0.01 USDC on Base, no API key required), reliability scoring, and protocol classification.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"subgraph-registry-mcp": "src/index.js"
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"start": "node src/index.js",
|
|
19
19
|
"start:http": "node src/index.js --http",
|
|
20
|
-
"start:http-only": "node src/index.js --http-only"
|
|
20
|
+
"start:http-only": "node src/index.js --http-only",
|
|
21
|
+
"test": "node --test test/"
|
|
21
22
|
},
|
|
22
23
|
"keywords": [
|
|
23
24
|
"mcp",
|
package/src/index.js
CHANGED
|
@@ -30,6 +30,21 @@ import { createHash } from "crypto";
|
|
|
30
30
|
|
|
31
31
|
const __filename = fileURLToPath(import.meta.url);
|
|
32
32
|
const __dirname = dirname(__filename);
|
|
33
|
+
|
|
34
|
+
// Read from package.json rather than a literal. The hardcoded string had
|
|
35
|
+
// drifted to "0.8.20" while the package shipped 0.8.31 — eleven releases of
|
|
36
|
+
// every MCP client being told the wrong server version, which is the kind of
|
|
37
|
+
// thing that only surfaces when someone is debugging something else.
|
|
38
|
+
const PKG_VERSION = (() => {
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(
|
|
41
|
+
readFileSync(join(__dirname, "..", "package.json"), "utf8"),
|
|
42
|
+
).version;
|
|
43
|
+
} catch {
|
|
44
|
+
return "0.0.0";
|
|
45
|
+
}
|
|
46
|
+
})();
|
|
47
|
+
|
|
33
48
|
const DATA_DIR = join(__dirname, "..", "data");
|
|
34
49
|
const DB_PATH = join(DATA_DIR, "registry.db");
|
|
35
50
|
const OPENAPI_JSON_PATH = join(DATA_DIR, "openapi.json");
|
|
@@ -50,7 +65,7 @@ const GITHUB_DB_URL =
|
|
|
50
65
|
// 3. Paste the new hash here and bump package.json version
|
|
51
66
|
// 4. Update SKILL.md "Verifying the registry" section
|
|
52
67
|
const EXPECTED_DB_SHA256 =
|
|
53
|
-
"
|
|
68
|
+
"ec7bb54f72379c0d4921b0c34c1c666c46e44c82f334efda440aeb2db09fa2d0";
|
|
54
69
|
// Skip-verification escape hatch (set to "1" only if you're rebuilding the DB
|
|
55
70
|
// locally and know what you're doing — never set in agent-runtime defaults).
|
|
56
71
|
const SKIP_VERIFY = process.env.SUBGRAPH_REGISTRY_SKIP_VERIFY === "1";
|
|
@@ -162,6 +177,84 @@ function getDb() {
|
|
|
162
177
|
return db;
|
|
163
178
|
}
|
|
164
179
|
|
|
180
|
+
// ── Maturity / cold-start handling ─────────────────────────
|
|
181
|
+
// reliability_score is built from four CUMULATIVE inputs (curation signal,
|
|
182
|
+
// indexer stake, lifetime query fees, 30d volume — see _reliability_score in
|
|
183
|
+
// python/classifier.py), so it measures accrued traction and therefore age.
|
|
184
|
+
// Measured on the 2026-08-25 corpus, served and non-denied:
|
|
185
|
+
//
|
|
186
|
+
// age n avg reliability
|
|
187
|
+
// <30d 64 0.107
|
|
188
|
+
// 30-90d 227 0.143
|
|
189
|
+
// 90-365d 1100 0.225
|
|
190
|
+
// >1y 4034 0.313
|
|
191
|
+
//
|
|
192
|
+
// The newest entry in the global top 25 is 280 days old. A good subgraph
|
|
193
|
+
// deployed last month cannot rank, no matter how good it is — 59 of those 64
|
|
194
|
+
// sub-30-day subgraphs are already serving real query volume.
|
|
195
|
+
//
|
|
196
|
+
// Rather than reweight the score (which would silently change every existing
|
|
197
|
+
// caller's results and trade a measurable signal for a guess), surface the
|
|
198
|
+
// young matches SEPARATELY and label them honestly, so the agent makes the
|
|
199
|
+
// call. A label alone would not be enough: at 0.107 average, young subgraphs
|
|
200
|
+
// are not in the ranked page to be labelled, so this needs its own lookup.
|
|
201
|
+
const EMERGING_MAX_AGE_DAYS = 90;
|
|
202
|
+
const NEW_MAX_AGE_DAYS = 30;
|
|
203
|
+
const EMERGING_LIMIT = 3;
|
|
204
|
+
|
|
205
|
+
// Shared so the main search and its emerging companion query select exactly
|
|
206
|
+
// the same columns — they feed the same row mapper.
|
|
207
|
+
const SEARCH_COLS = `id, display_name, description, auto_description, domain, protocol_type, network,
|
|
208
|
+
reliability_score, ipfs_hash, entity_count, canonical_entities,
|
|
209
|
+
powered_by_substreams, active_allocation_count, example_query, denied_at, created_at`;
|
|
210
|
+
|
|
211
|
+
function ageDays(created_at) {
|
|
212
|
+
if (!created_at) return null;
|
|
213
|
+
return Math.max(0, Math.floor(Date.now() / 1000 - created_at) / 86400) | 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function maturityOf(created_at) {
|
|
217
|
+
const d = ageDays(created_at);
|
|
218
|
+
if (d === null) return "unknown";
|
|
219
|
+
if (d < NEW_MAX_AGE_DAYS) return "new";
|
|
220
|
+
if (d < EMERGING_MAX_AGE_DAYS) return "emerging";
|
|
221
|
+
return "established";
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const EMERGING_CAVEAT =
|
|
225
|
+
"Recent deployments that matched your query but ranked below the main list " +
|
|
226
|
+
"because reliability_score is cumulative (curation signal, indexer stake, " +
|
|
227
|
+
"lifetime query fees, 30d volume) and so grows with age — the newest subgraph " +
|
|
228
|
+
"in the whole registry's top 25 is 280 days old. A low score here is expected " +
|
|
229
|
+
"at this age and is NOT evidence of a problem; these are unproven, not bad. " +
|
|
230
|
+
"Prefer `subgraphs` for production work. Consider these when the protocol is " +
|
|
231
|
+
"itself new (no mature deployment can exist), when you want the newest schema, " +
|
|
232
|
+
"or when the ranked list missed what you asked for.";
|
|
233
|
+
|
|
234
|
+
// Young matches for the same filter, fetched separately because they cannot
|
|
235
|
+
// compete on the main ORDER BY. Returns [] on any failure — this is an
|
|
236
|
+
// enrichment, and it must never take down the search that already succeeded.
|
|
237
|
+
function findEmerging(where, params, excludeIds, selectCols) {
|
|
238
|
+
try {
|
|
239
|
+
const cutoff = Math.floor(Date.now() / 1000) - EMERGING_MAX_AGE_DAYS * 86400;
|
|
240
|
+
const notIn = excludeIds.length
|
|
241
|
+
? ` AND id NOT IN (${excludeIds.map(() => "?").join(",")})`
|
|
242
|
+
: "";
|
|
243
|
+
const sql = `
|
|
244
|
+
SELECT ${selectCols}
|
|
245
|
+
FROM subgraphs
|
|
246
|
+
${where ? `${where} AND` : "WHERE"} created_at > ?${notIn}
|
|
247
|
+
ORDER BY reliability_score DESC
|
|
248
|
+
LIMIT ?
|
|
249
|
+
`;
|
|
250
|
+
return getDb()
|
|
251
|
+
.prepare(sql)
|
|
252
|
+
.all(...params, cutoff, ...excludeIds, EMERGING_LIMIT);
|
|
253
|
+
} catch {
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
165
258
|
// ── Tool Implementations ───────────────────────────────────
|
|
166
259
|
|
|
167
260
|
function searchSubgraphs({
|
|
@@ -172,6 +265,7 @@ function searchSubgraphs({
|
|
|
172
265
|
entity = "",
|
|
173
266
|
min_reliability = 0,
|
|
174
267
|
include_unserved = false,
|
|
268
|
+
include_denied = false,
|
|
175
269
|
limit = 20,
|
|
176
270
|
} = {}) {
|
|
177
271
|
const conditions = [];
|
|
@@ -183,6 +277,20 @@ function searchSubgraphs({
|
|
|
183
277
|
conditions.push("active_allocation_count > 0");
|
|
184
278
|
}
|
|
185
279
|
|
|
280
|
+
// Default: hide curation-denied deployments (deniedAt > 0 on the network
|
|
281
|
+
// subgraph — denied indexing rewards, typically spam, duplicates or
|
|
282
|
+
// deprecations). classifier.py has persisted this since the denied_at
|
|
283
|
+
// column landed, explicitly "so agents can filter denied subgraphs", but
|
|
284
|
+
// nothing in this file ever read it, so the filter the crawler was feeding
|
|
285
|
+
// did not exist. The 0.5 reliability penalty already keeps denied entries
|
|
286
|
+
// out of the top of a ranked page — measured: 0 of the global top 20, and
|
|
287
|
+
// none in any domain's top 10 — so this changes few results today. It
|
|
288
|
+
// matters for the narrow queries where a denied fork IS the best textual
|
|
289
|
+
// match, and it makes the signal visible either way via `denied` below.
|
|
290
|
+
if (!include_denied) {
|
|
291
|
+
conditions.push("denied_at = 0");
|
|
292
|
+
}
|
|
293
|
+
|
|
186
294
|
if (domain) {
|
|
187
295
|
conditions.push("domain = ?");
|
|
188
296
|
params.push(domain);
|
|
@@ -219,14 +327,15 @@ function searchSubgraphs({
|
|
|
219
327
|
// Over-fetch to allow dedup by IPFS hash (same deployment, different subgraph IDs)
|
|
220
328
|
const fetchLimit = limit * 3;
|
|
221
329
|
const sql = `
|
|
222
|
-
SELECT
|
|
223
|
-
reliability_score, ipfs_hash, entity_count, canonical_entities,
|
|
224
|
-
powered_by_substreams, active_allocation_count, example_query
|
|
330
|
+
SELECT ${SEARCH_COLS}
|
|
225
331
|
FROM subgraphs
|
|
226
332
|
${where}
|
|
227
333
|
ORDER BY reliability_score DESC
|
|
228
334
|
LIMIT ?
|
|
229
335
|
`;
|
|
336
|
+
// Snapshot the filter params BEFORE the LIMIT is appended — the emerging
|
|
337
|
+
// companion query reuses the same WHERE and must not inherit this LIMIT.
|
|
338
|
+
const filterParams = [...params];
|
|
230
339
|
params.push(fetchLimit);
|
|
231
340
|
|
|
232
341
|
const rows = getDb().prepare(sql).all(...params);
|
|
@@ -249,17 +358,54 @@ function searchSubgraphs({
|
|
|
249
358
|
canonical_entities: JSON.parse(r.canonical_entities),
|
|
250
359
|
powered_by_substreams: Boolean(r.powered_by_substreams),
|
|
251
360
|
active_allocation_count: r.active_allocation_count || 0,
|
|
361
|
+
// Curation-denied on the network subgraph. Only ever true when the
|
|
362
|
+
// caller passed include_denied — surfaced so that choice stays visible
|
|
363
|
+
// in the result rather than being silently carried.
|
|
364
|
+
denied: Boolean(r.denied_at),
|
|
252
365
|
// Ready-to-run GraphQL generated from this subgraph's actual schema — so an
|
|
253
366
|
// agent can POST it to query_url_x402 immediately, no get_subgraph_detail round-trip.
|
|
254
367
|
example_query: r.example_query || null,
|
|
368
|
+
age_days: ageDays(r.created_at),
|
|
369
|
+
maturity: maturityOf(r.created_at),
|
|
255
370
|
...buildQueryEndpoints(r.id),
|
|
256
371
|
});
|
|
257
372
|
if (results.length >= limit) break;
|
|
258
373
|
}
|
|
259
374
|
|
|
375
|
+
// Young matches that could not compete on the cumulative score. Same filter,
|
|
376
|
+
// separate lookup, clearly labelled — never blended into `subgraphs`, so a
|
|
377
|
+
// caller that ignores this field sees exactly what it saw before.
|
|
378
|
+
const emerging = findEmerging(
|
|
379
|
+
where,
|
|
380
|
+
filterParams,
|
|
381
|
+
results.map((x) => x.id),
|
|
382
|
+
SEARCH_COLS,
|
|
383
|
+
).map((r) => ({
|
|
384
|
+
id: r.id,
|
|
385
|
+
display_name: r.display_name,
|
|
386
|
+
description: (r.description || r.auto_description || "").slice(0, 300),
|
|
387
|
+
domain: r.domain,
|
|
388
|
+
protocol_type: r.protocol_type,
|
|
389
|
+
network: r.network,
|
|
390
|
+
reliability_score: r.reliability_score,
|
|
391
|
+
ipfs_hash: r.ipfs_hash,
|
|
392
|
+
entity_count: r.entity_count,
|
|
393
|
+
canonical_entities: JSON.parse(r.canonical_entities),
|
|
394
|
+
powered_by_substreams: Boolean(r.powered_by_substreams),
|
|
395
|
+
active_allocation_count: r.active_allocation_count || 0,
|
|
396
|
+
denied: Boolean(r.denied_at),
|
|
397
|
+
example_query: r.example_query || null,
|
|
398
|
+
age_days: ageDays(r.created_at),
|
|
399
|
+
maturity: maturityOf(r.created_at),
|
|
400
|
+
...buildQueryEndpoints(r.id),
|
|
401
|
+
}));
|
|
402
|
+
|
|
260
403
|
return {
|
|
261
404
|
total: results.length,
|
|
262
405
|
subgraphs: results,
|
|
406
|
+
...(emerging.length
|
|
407
|
+
? { emerging, emerging_caveat: EMERGING_CAVEAT }
|
|
408
|
+
: {}),
|
|
263
409
|
query_instructions: "Two ways to query: (a) RECOMMENDED — POST GraphQL to query_url_x402 and pay $0.01 USDC on Base per query via x402 (no API key required; gateway returns HTTP 402 with a payment manifest, use an x402 client like @graphprotocol/client-x402 to sign and retry). (b) LEGACY — replace [api-key] in query_url with a Graph API key from https://thegraph.com/studio/apikeys/. Each result includes a ready-to-run `example_query` generated from that subgraph's real schema — POST it to query_url_x402 as-is, or adapt the entity/fields. Use get_subgraph_detail for the full schema.",
|
|
264
410
|
};
|
|
265
411
|
}
|
|
@@ -295,7 +441,10 @@ function recommendSubgraph({ goal, chain = "" }) {
|
|
|
295
441
|
.filter(([, kws]) => kws.some((k) => goalLower.includes(k)))
|
|
296
442
|
.map(([t]) => t);
|
|
297
443
|
|
|
298
|
-
|
|
444
|
+
// recommend_subgraph exposes no include_* escape hatches — it answers "which
|
|
445
|
+
// one should I use", so a curation-denied deployment is never the right
|
|
446
|
+
// answer and the filter is unconditional here.
|
|
447
|
+
const conditions = ["active_allocation_count > 0", "denied_at = 0"];
|
|
299
448
|
const params = [];
|
|
300
449
|
|
|
301
450
|
if (chain) {
|
|
@@ -589,6 +738,7 @@ async function semanticSearchSubgraphs({
|
|
|
589
738
|
limit = 10,
|
|
590
739
|
min_score = 0.3,
|
|
591
740
|
include_unserved = false,
|
|
741
|
+
include_denied = false,
|
|
592
742
|
domain = "",
|
|
593
743
|
network = "",
|
|
594
744
|
protocol_type = "",
|
|
@@ -615,6 +765,9 @@ async function semanticSearchSubgraphs({
|
|
|
615
765
|
if (!include_unserved) {
|
|
616
766
|
conditions.push("active_allocation_count > 0");
|
|
617
767
|
}
|
|
768
|
+
if (!include_denied) {
|
|
769
|
+
conditions.push("denied_at = 0");
|
|
770
|
+
}
|
|
618
771
|
if (domain) {
|
|
619
772
|
conditions.push("domain = ?");
|
|
620
773
|
params.push(domain);
|
|
@@ -637,7 +790,7 @@ async function semanticSearchSubgraphs({
|
|
|
637
790
|
`SELECT id, display_name, description, auto_description, domain,
|
|
638
791
|
protocol_type, network, reliability_score, ipfs_hash,
|
|
639
792
|
entity_count, canonical_entities, powered_by_substreams,
|
|
640
|
-
active_allocation_count, example_query, embedding
|
|
793
|
+
active_allocation_count, example_query, denied_at, created_at, embedding
|
|
641
794
|
FROM subgraphs
|
|
642
795
|
${where}`,
|
|
643
796
|
)
|
|
@@ -672,7 +825,15 @@ async function semanticSearchSubgraphs({
|
|
|
672
825
|
canonical_entities: JSON.parse(r.canonical_entities),
|
|
673
826
|
powered_by_substreams: Boolean(r.powered_by_substreams),
|
|
674
827
|
active_allocation_count: r.active_allocation_count || 0,
|
|
828
|
+
denied: Boolean(r.denied_at),
|
|
675
829
|
example_query: r.example_query || null,
|
|
830
|
+
// No `emerging` companion list here: this tool ranks by cosine score,
|
|
831
|
+
// not reliability_score, so a three-week-old subgraph can and does take
|
|
832
|
+
// the top slot on merit. The cold-start bias is a property of the ranked
|
|
833
|
+
// search, not of semantic search — what this tool needs is the label, so
|
|
834
|
+
// a caller knows a strong match is also unproven.
|
|
835
|
+
age_days: ageDays(r.created_at),
|
|
836
|
+
maturity: maturityOf(r.created_at),
|
|
676
837
|
semantic_score: Number(score.toFixed(4)),
|
|
677
838
|
...buildQueryEndpoints(r.id),
|
|
678
839
|
});
|
|
@@ -828,7 +989,7 @@ const TOOLS = [
|
|
|
828
989
|
{
|
|
829
990
|
name: "search_subgraphs",
|
|
830
991
|
description:
|
|
831
|
-
"Search and filter the classified subgraph registry (15,500+ subgraphs). Filter by domain (defi, nfts, dao, gaming, identity, infrastructure, social, analytics), network (mainnet, arbitrum-one, base, matic, bsc, optimism, avalanche), protocol_type (dex, lending, bridge, staking, options, perpetuals, nft-marketplace, yield-aggregator, governance, name-service), canonical entity type (liquidity_pool, trade, token, position, vault, loan, collateral, liquidation, nft_collection, nft_item, nft_sale, proposal, delegate, domain_name, account, transaction, daily_snapshot, hourly_snapshot), or free-text keyword. Returns subgraphs ranked by reliability score. Each result includes query_url_x402 (POST GraphQL and pay $0.01 USDC on Base per query — no API key needed) and a legacy query_url (Studio API key required).",
|
|
992
|
+
"Search and filter the classified subgraph registry (15,500+ subgraphs). Filter by domain (defi, nfts, dao, gaming, identity, infrastructure, social, analytics), network (mainnet, arbitrum-one, base, matic, bsc, optimism, avalanche), protocol_type (dex, lending, bridge, staking, options, perpetuals, nft-marketplace, yield-aggregator, governance, name-service), canonical entity type (liquidity_pool, trade, token, position, vault, loan, collateral, liquidation, nft_collection, nft_item, nft_sale, proposal, delegate, domain_name, account, transaction, daily_snapshot, hourly_snapshot), or free-text keyword. Returns subgraphs ranked by reliability score. Each result includes query_url_x402 (POST GraphQL and pay $0.01 USDC on Base per query — no API key needed) and a legacy query_url (Studio API key required), plus age_days and maturity (new | emerging | established). Because reliability_score is cumulative it structurally favours older deployments, so a separate `emerging` list carries recent matches that ranked below the main cut for age rather than quality — read `emerging_caveat` before offering one to a user.",
|
|
832
993
|
inputSchema: {
|
|
833
994
|
type: "object",
|
|
834
995
|
additionalProperties: false,
|
|
@@ -838,8 +999,18 @@ const TOOLS = [
|
|
|
838
999
|
network: { type: "string", description: "Filter by chain: mainnet, arbitrum-one, base, matic, bsc, optimism, avalanche, etc." },
|
|
839
1000
|
protocol_type: { type: "string", description: "Filter by protocol type: dex, lending, bridge, staking, options, perpetuals, etc." },
|
|
840
1001
|
entity: { type: "string", description: "Filter by canonical entity: liquidity_pool, trade, token, position, vault, loan, etc." },
|
|
841
|
-
min_reliability: { type: "number", description: "Minimum reliability score (0-1). Higher = more query fees, volume, curation signal, and indexer allocation." },
|
|
1002
|
+
min_reliability: { type: "number", description: "Minimum reliability score (0-1). Higher = more query fees, volume, curation signal, and indexer allocation. NOTE: all four inputs are cumulative, so this score rises with age — setting a floor here filters out good recent subgraphs along with bad ones." },
|
|
842
1003
|
limit: { type: "integer", description: "Max results to return (default: 20)", default: 20 },
|
|
1004
|
+
include_unserved: {
|
|
1005
|
+
type: "boolean",
|
|
1006
|
+
description: "Include subgraphs with 0 active indexer allocations (returns 'no allocations' on query). Default false.",
|
|
1007
|
+
default: false,
|
|
1008
|
+
},
|
|
1009
|
+
include_denied: {
|
|
1010
|
+
type: "boolean",
|
|
1011
|
+
description: "Include curation-denied deployments (deniedAt > 0 — denied indexing rewards, typically spam, duplicates or deprecations). Default false. When true, each result carries denied: true so the choice stays visible.",
|
|
1012
|
+
default: false,
|
|
1013
|
+
},
|
|
843
1014
|
},
|
|
844
1015
|
},
|
|
845
1016
|
},
|
|
@@ -909,6 +1080,11 @@ const TOOLS = [
|
|
|
909
1080
|
description: "Include subgraphs with 0 active indexer allocations (returns 'no allocations' on query). Default false.",
|
|
910
1081
|
default: false,
|
|
911
1082
|
},
|
|
1083
|
+
include_denied: {
|
|
1084
|
+
type: "boolean",
|
|
1085
|
+
description: "Include curation-denied deployments (deniedAt > 0 — denied indexing rewards, typically spam, duplicates or deprecations). Default false. When true, each result carries denied: true so the choice stays visible.",
|
|
1086
|
+
default: false,
|
|
1087
|
+
},
|
|
912
1088
|
domain: {
|
|
913
1089
|
type: "string",
|
|
914
1090
|
description: "Pre-filter by domain (defi, nfts, dao, gaming, identity, infrastructure, social, analytics)",
|
|
@@ -963,7 +1139,7 @@ const HANDLERS = {
|
|
|
963
1139
|
|
|
964
1140
|
function createServer() {
|
|
965
1141
|
const server = new Server(
|
|
966
|
-
{ name: "subgraph-registry", version:
|
|
1142
|
+
{ name: "subgraph-registry", version: PKG_VERSION },
|
|
967
1143
|
{ capabilities: { tools: {} } }
|
|
968
1144
|
);
|
|
969
1145
|
|