subgraph-registry-mcp 0.6.5 → 0.7.2
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 +30 -6
- package/data/registry.db +0 -0
- package/package.json +1 -1
- package/src/index.js +112 -3
package/README.md
CHANGED
|
@@ -16,11 +16,13 @@ Agents querying The Graph need to discover and select the right subgraph before
|
|
|
16
16
|
|
|
17
17
|
1. **Crawls** all active subgraphs from the Graph Network meta-subgraph
|
|
18
18
|
2. **Fetches** the GraphQL schema for every deployment
|
|
19
|
-
3. **
|
|
20
|
-
4. **
|
|
21
|
-
5. **
|
|
22
|
-
6. **
|
|
23
|
-
7. **
|
|
19
|
+
3. **Extracts contract addresses** from each manifest's `dataSources` and `templates` — agents can answer "which subgraph indexes contract 0x… on chain X?"
|
|
20
|
+
4. **Generates a per-subgraph starter GraphQL query** from the parsed schema (real top entity, real fields, sensible orderBy) — no more generic boilerplate that doesn't compile against most subgraphs
|
|
21
|
+
5. **Classifies** each subgraph by domain, protocol type, canonical entities, and schema family
|
|
22
|
+
6. **Scores** reliability using on-chain signals (query fees, volume, curation, stake)
|
|
23
|
+
7. **Returns x402 + legacy query URLs** — agents can pay $0.01 USDC on Base per query (no API key) or use a Studio key
|
|
24
|
+
8. **Publishes** as SQLite database + REST API + MCP server + **per-subgraph JSON-LD at `/.well-known/subgraph/{id}.jsonld`** for ecosystem crawlers
|
|
25
|
+
9. **Generates** visual dashboards and bot-readable category files (auto-updated with each sync)
|
|
24
26
|
|
|
25
27
|
---
|
|
26
28
|
|
|
@@ -191,6 +193,28 @@ The server auto-downloads the pre-built registry (8MB SQLite) from GitHub on fir
|
|
|
191
193
|
|
|
192
194
|
---
|
|
193
195
|
|
|
196
|
+
## Well-Known JSON-LD Manifest
|
|
197
|
+
|
|
198
|
+
Stable, machine-readable per-subgraph manifest that other crawlers and agent frameworks can index without going through MCP. Served by the Node MCP HTTP transport:
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
GET /.well-known/subgraph/{id}.jsonld Full per-subgraph manifest (JSON-LD)
|
|
202
|
+
GET /subgraphs/{id}.jsonld Alias (same payload)
|
|
203
|
+
GET /.well-known/subgraph-index.jsonld Discovery list — top 100 by reliability with @id links
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Each manifest includes classification, parsed entities, contract addresses (from the indexed `dataSources`), endpoints (x402 + API-key), a per-subgraph starter query generated from the actual schema, pricing, and metadata. The `@context` + `@type` make the shape auto-discoverable.
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Start the HTTP transport
|
|
210
|
+
npx subgraph-registry-mcp --http-only
|
|
211
|
+
|
|
212
|
+
# Fetch the manifest for Uniswap V3 Mainnet
|
|
213
|
+
curl http://localhost:3848/.well-known/subgraph/5zvR82QoaXYFyDEKLZ9t6v9adgnptxYpKpSbxtgVENFV.jsonld
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
194
218
|
## REST API
|
|
195
219
|
|
|
196
220
|
```
|
|
@@ -199,7 +223,7 @@ GET /domains Domain breakdown
|
|
|
199
223
|
GET /networks Network breakdown
|
|
200
224
|
GET /families Schema family groups (fork/clone detection)
|
|
201
225
|
GET /subgraphs Filter subgraphs
|
|
202
|
-
GET /subgraphs/{id} Full detail for one subgraph
|
|
226
|
+
GET /subgraphs/{id} Full detail for one subgraph (now includes contract_addresses and example_query)
|
|
203
227
|
GET /search?q=uniswap Free-text search
|
|
204
228
|
GET /recommend?goal=...&chain= Agent-optimized recommendation
|
|
205
229
|
```
|
package/data/registry.db
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subgraph-registry-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"mcpName": "io.github.PaulieB14/subgraph-registry-mcp",
|
|
5
5
|
"description": "MCP server for agent-friendly subgraph discovery on The Graph Network. 14,733 classified subgraphs with x402 query URLs ($0.01 USDC on Base, no API key required), reliability scoring, and protocol classification.",
|
|
6
6
|
"type": "module",
|
package/src/index.js
CHANGED
|
@@ -45,7 +45,7 @@ const GITHUB_DB_URL =
|
|
|
45
45
|
// 3. Paste the new hash here and bump package.json version
|
|
46
46
|
// 4. Update SKILL.md "Verifying the registry" section
|
|
47
47
|
const EXPECTED_DB_SHA256 =
|
|
48
|
-
"
|
|
48
|
+
"76943c2037bc63546408ca8d8531ce8b76415fccfb455e13cc4c805d5f440f68";
|
|
49
49
|
// Skip-verification escape hatch (set to "1" only if you're rebuilding the DB
|
|
50
50
|
// locally and know what you're doing — never set in agent-runtime defaults).
|
|
51
51
|
const SKIP_VERIFY = process.env.SUBGRAPH_REGISTRY_SKIP_VERIFY === "1";
|
|
@@ -365,6 +365,13 @@ function getSubgraphDetail({ subgraph_id }) {
|
|
|
365
365
|
result.canonical_entities = JSON.parse(result.canonical_entities);
|
|
366
366
|
result.categories = JSON.parse(result.categories);
|
|
367
367
|
if (result.all_entities) result.all_entities = JSON.parse(result.all_entities);
|
|
368
|
+
// Contract addresses extracted from the manifest — list of
|
|
369
|
+
// {kind, name, address, network, startBlock}. Null on subgraphs we
|
|
370
|
+
// haven't crawled with manifest support yet, or substreams-powered ones.
|
|
371
|
+
if (result.contract_addresses) {
|
|
372
|
+
try { result.contract_addresses = JSON.parse(result.contract_addresses); }
|
|
373
|
+
catch { /* leave as string if not valid JSON */ }
|
|
374
|
+
}
|
|
368
375
|
if (!result.description && result.auto_description) {
|
|
369
376
|
result.description = result.auto_description;
|
|
370
377
|
}
|
|
@@ -372,6 +379,14 @@ function getSubgraphDetail({ subgraph_id }) {
|
|
|
372
379
|
result.query_url = endpoints.query_url;
|
|
373
380
|
result.query_url_x402 = endpoints.query_url_x402;
|
|
374
381
|
result.pricing = endpoints.pricing;
|
|
382
|
+
|
|
383
|
+
// Per-subgraph starter query generated by the crawler from this subgraph's
|
|
384
|
+
// parsed schema. Falls back to the legacy generic example when the column
|
|
385
|
+
// is empty (pre-feature DBs).
|
|
386
|
+
const FALLBACK_EXAMPLE =
|
|
387
|
+
"{ pools(first: 5, orderBy: totalValueLockedUSD, orderDirection: desc) { id token0 { symbol } token1 { symbol } totalValueLockedUSD } }";
|
|
388
|
+
const exampleQuery = result.example_query || FALLBACK_EXAMPLE;
|
|
389
|
+
|
|
375
390
|
result.query_instructions = {
|
|
376
391
|
recommended: "x402",
|
|
377
392
|
x402: {
|
|
@@ -379,17 +394,60 @@ function getSubgraphDetail({ subgraph_id }) {
|
|
|
379
394
|
payment: endpoints.pricing,
|
|
380
395
|
flow: "POST GraphQL to url. Gateway returns HTTP 402 with a base64 payment-required header containing the payment manifest. Sign $0.01 USDC on Base with an x402 client and retry. No API key, no signup.",
|
|
381
396
|
client_libraries: ["@graphprotocol/client-x402", "x402-fetch"],
|
|
382
|
-
example_query:
|
|
397
|
+
example_query: exampleQuery,
|
|
383
398
|
},
|
|
384
399
|
api_key_legacy: {
|
|
385
400
|
url: endpoints.query_url,
|
|
386
401
|
flow: "Get an API key from https://thegraph.com/studio/apikeys/, replace [api-key] in the url, then POST GraphQL.",
|
|
387
402
|
},
|
|
388
|
-
schema_hint:
|
|
403
|
+
schema_hint: result.example_query
|
|
404
|
+
? "example_query above was generated from this subgraph's actual schema. Adapt the entity name + field selection as needed."
|
|
405
|
+
: "Use the all_entities field above to see what entities and fields are available to query.",
|
|
389
406
|
};
|
|
390
407
|
return result;
|
|
391
408
|
}
|
|
392
409
|
|
|
410
|
+
|
|
411
|
+
// ── JSON-LD per-subgraph well-known shape ─────────────────────────────────
|
|
412
|
+
// Stable, machine-readable manifest other crawlers and agents can index
|
|
413
|
+
// without going through MCP. Served at /.well-known/subgraph/{id}.jsonld and
|
|
414
|
+
// /subgraphs/{id}.jsonld (alias, same payload).
|
|
415
|
+
const JSONLD_CONTEXT = "https://subgraph-registry.paulieb14.dev/context.jsonld";
|
|
416
|
+
|
|
417
|
+
function buildJsonLdManifest(row) {
|
|
418
|
+
if (!row) return null;
|
|
419
|
+
const detail = getSubgraphDetail({ subgraph_id: row.id });
|
|
420
|
+
if (detail?.error) return null;
|
|
421
|
+
return {
|
|
422
|
+
"@context": JSONLD_CONTEXT,
|
|
423
|
+
"@type": "SubgraphDeployment",
|
|
424
|
+
"@id": `https://subgraph-registry.paulieb14.dev/subgraphs/${row.id}`,
|
|
425
|
+
id: row.id,
|
|
426
|
+
ipfsHash: row.ipfs_hash,
|
|
427
|
+
name: row.display_name,
|
|
428
|
+
description: row.description || row.auto_description,
|
|
429
|
+
network: row.network,
|
|
430
|
+
classification: {
|
|
431
|
+
domain: row.domain,
|
|
432
|
+
protocolType: row.protocol_type,
|
|
433
|
+
confidence: row.classification_confidence,
|
|
434
|
+
},
|
|
435
|
+
entities: detail.all_entities || [],
|
|
436
|
+
canonicalEntities: detail.canonical_entities || [],
|
|
437
|
+
contracts: detail.contract_addresses || null,
|
|
438
|
+
reliabilityScore: row.reliability_score,
|
|
439
|
+
activeIndexers: row.active_allocation_count,
|
|
440
|
+
queryVolume30d: row.query_volume_30d,
|
|
441
|
+
endpoints: {
|
|
442
|
+
x402: detail.query_url_x402,
|
|
443
|
+
apiKey: detail.query_url,
|
|
444
|
+
},
|
|
445
|
+
exampleQuery: detail.query_instructions?.x402?.example_query || null,
|
|
446
|
+
poweredBySubstreams: !!row.powered_by_substreams,
|
|
447
|
+
pricing: detail.pricing,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
393
451
|
function listRegistryStats() {
|
|
394
452
|
const d = getDb();
|
|
395
453
|
const domains = d
|
|
@@ -542,8 +600,59 @@ function startHttpTransport(port) {
|
|
|
542
600
|
res.json({ status: "ok", subgraphs: getDb().prepare("SELECT COUNT(*) as c FROM subgraphs").get().c });
|
|
543
601
|
});
|
|
544
602
|
|
|
603
|
+
// ── Stable per-subgraph manifest for ecosystem crawlers ───────────────
|
|
604
|
+
// Other tools (E&N tooling, indexer dashboards, agent frameworks) can
|
|
605
|
+
// hit this without needing MCP. JSON-LD so the shape is auto-discoverable.
|
|
606
|
+
const serveManifest = (req, res) => {
|
|
607
|
+
const id = req.params.id;
|
|
608
|
+
const row = getDb()
|
|
609
|
+
.prepare("SELECT * FROM subgraphs WHERE id = ? OR ipfs_hash = ?")
|
|
610
|
+
.get(id, id);
|
|
611
|
+
if (!row) {
|
|
612
|
+
res.status(404).json({ error: `Subgraph '${id}' not found` });
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
const manifest = buildJsonLdManifest(row);
|
|
616
|
+
if (!manifest) {
|
|
617
|
+
res.status(500).json({ error: "Manifest build failed" });
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
res.type("application/ld+json").json(manifest);
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
// Canonical .well-known location + a friendlier alias under /subgraphs/
|
|
624
|
+
app.get("/.well-known/subgraph/:id.jsonld", serveManifest);
|
|
625
|
+
app.get("/subgraphs/:id.jsonld", serveManifest);
|
|
626
|
+
|
|
627
|
+
// Discovery index so a crawler that doesn't know the ID can find one:
|
|
628
|
+
// returns the top 100 by reliability with their .jsonld URLs.
|
|
629
|
+
app.get("/.well-known/subgraph-index.jsonld", (_req, res) => {
|
|
630
|
+
const rows = getDb()
|
|
631
|
+
.prepare(
|
|
632
|
+
"SELECT id, display_name, network, domain, reliability_score " +
|
|
633
|
+
"FROM subgraphs WHERE active_allocation_count > 0 " +
|
|
634
|
+
"ORDER BY reliability_score DESC LIMIT 100"
|
|
635
|
+
).all();
|
|
636
|
+
res.type("application/ld+json").json({
|
|
637
|
+
"@context": JSONLD_CONTEXT,
|
|
638
|
+
"@type": "SubgraphIndex",
|
|
639
|
+
generatedAt: new Date().toISOString(),
|
|
640
|
+
count: rows.length,
|
|
641
|
+
subgraphs: rows.map((r) => ({
|
|
642
|
+
"@id": `https://subgraph-registry.paulieb14.dev/subgraphs/${r.id}`,
|
|
643
|
+
id: r.id,
|
|
644
|
+
name: r.display_name,
|
|
645
|
+
network: r.network,
|
|
646
|
+
domain: r.domain,
|
|
647
|
+
reliabilityScore: r.reliability_score,
|
|
648
|
+
manifest: `/.well-known/subgraph/${r.id}.jsonld`,
|
|
649
|
+
})),
|
|
650
|
+
});
|
|
651
|
+
});
|
|
652
|
+
|
|
545
653
|
app.listen(port, () => {
|
|
546
654
|
console.error(`SSE transport listening on http://localhost:${port}/sse`);
|
|
655
|
+
console.error(`Well-known manifest at http://localhost:${port}/.well-known/subgraph/{id}.jsonld`);
|
|
547
656
|
});
|
|
548
657
|
}
|
|
549
658
|
|