recommend_subgraph
Find the best subgraphs for your blockchain data needs by describing your goal in natural language. Get matching subgraphs with reliability scores and query URLs for live data access.
Instructions
Given a natural-language goal like 'find DEX trades on Arbitrum' or 'get lending liquidation data', returns the best matching subgraphs with reliability scores and query URLs. Automatically infers domain and protocol type from the goal. Each result includes a query_url — replace [api-key] with your Graph API key to query live data.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| goal | Yes | What you want to do, e.g. 'query Uniswap pool data on Base' | |
| chain | No | Optional chain filter: mainnet, arbitrum-one, base, matic, etc. |
Implementation Reference
- src/index.js:172-267 (handler)JavaScript handler function that implements recommend_subgraph tool. Takes a natural language goal and optional chain parameter, infers domain/protocol type from keywords, queries the SQLite database for matching subgraphs, and returns recommendations with reliability scores and query URLs.
function recommendSubgraph({ goal, chain = "" }) { const goalLower = goal.toLowerCase(); const domainMap = { defi: ["defi", "swap", "trade", "lend", "borrow", "yield", "stake", "liquidity", "pool", "token"], nfts: ["nft", "collectible", "art", "marketplace"], dao: ["governance", "vote", "proposal", "dao"], identity: ["ens", "domain", "name", "identity"], infrastructure: ["indexer", "graph", "oracle"], social: ["social", "profile", "post", "lens"], gaming: ["game", "player", "quest"], }; const typeMap = { dex: ["dex", "swap", "trade", "exchange", "amm", "uniswap", "sushi"], lending: ["lend", "borrow", "loan", "collateral", "aave", "compound"], bridge: ["bridge", "cross-chain"], staking: ["stake", "validator", "delegation"], options: ["option", "call", "put", "strike"], perpetuals: ["perp", "perpetual", "leverage", "margin"], governance: ["governance", "vote", "proposal"], "name-service": ["ens", "name service", "domain name"], "nft-marketplace": ["nft market", "opensea", "blur"], }; const domains = Object.entries(domainMap) .filter(([, kws]) => kws.some((k) => goalLower.includes(k))) .map(([d]) => d); const ptypes = Object.entries(typeMap) .filter(([, kws]) => kws.some((k) => goalLower.includes(k))) .map(([t]) => t); const conditions = []; const params = []; if (chain) { conditions.push("network = ?"); params.push(chain); } if (domains.length) { conditions.push(`domain IN (${domains.map(() => "?").join(",")})`); params.push(...domains); } if (ptypes.length) { conditions.push(`protocol_type IN (${ptypes.map(() => "?").join(",")})`); params.push(...ptypes); } if (!domains.length && !ptypes.length) { const words = goalLower.split(/\s+/).filter((w) => w.length > 2).slice(0, 5); if (words.length) { const textConds = words.map(() => "(display_name LIKE ? OR description LIKE ?)"); words.forEach((w) => params.push(`%${w}%`, `%${w}%`)); conditions.push(`(${textConds.join(" OR ")})`); } } const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : ""; const sql = ` SELECT id, display_name, description, auto_description, domain, protocol_type, network, reliability_score, ipfs_hash, canonical_entities FROM subgraphs ${where} ORDER BY reliability_score DESC LIMIT 15 `; const rows = getDb().prepare(sql).all(...params); const seenIpfs = new Set(); const recommendations = []; for (const r of rows) { if (r.ipfs_hash && seenIpfs.has(r.ipfs_hash)) continue; if (r.ipfs_hash) seenIpfs.add(r.ipfs_hash); recommendations.push({ id: r.id, display_name: r.display_name, description: (r.description || r.auto_description || "").slice(0, 300), domain: r.domain, protocol_type: r.protocol_type, network: r.network, reliability_score: r.reliability_score, ipfs_hash: r.ipfs_hash, canonical_entities: JSON.parse(r.canonical_entities), query_url: `https://gateway.thegraph.com/api/[api-key]/subgraphs/id/${r.id}`, }); if (recommendations.length >= 5) break; } return { goal, chain_filter: chain || null, inferred_domain: domains.length ? domains : null, inferred_protocol_type: ptypes.length ? ptypes : null, total_matches: recommendations.length, recommendations, }; } - python/mcp_server.py:152-249 (handler)Python handler function that implements recommend_subgraph tool. Mirrors the JavaScript implementation - parses natural language goals, infers domain/protocol type from keyword mappings, queries SQLite database, and returns JSON with matching subgraphs.
def recommend_subgraph(goal: str, chain: str = "") -> str: """Given a natural-language goal, find the best matching subgraphs.""" goal_lower = goal.lower() # Infer domain domain_map = { "defi": ["defi", "swap", "trade", "lend", "borrow", "yield", "stake", "liquidity", "pool", "token"], "nfts": ["nft", "collectible", "art", "marketplace"], "dao": ["governance", "vote", "proposal", "dao"], "identity": ["ens", "domain", "name", "identity"], "infrastructure": ["indexer", "graph", "oracle"], "social": ["social", "profile", "post", "lens"], "gaming": ["game", "player", "quest"], } type_map = { "dex": ["dex", "swap", "trade", "exchange", "amm", "uniswap", "sushi"], "lending": ["lend", "borrow", "loan", "collateral", "aave", "compound"], "bridge": ["bridge", "cross-chain"], "staking": ["stake", "validator", "delegation"], "options": ["option", "call", "put", "strike"], "perpetuals": ["perp", "perpetual", "leverage", "margin"], "governance": ["governance", "vote", "proposal"], "name-service": ["ens", "name service", "domain name"], "nft-marketplace": ["nft market", "opensea", "blur"], } domains = [d for d, kws in domain_map.items() if any(k in goal_lower for k in kws)] ptypes = [t for t, kws in type_map.items() if any(k in goal_lower for k in kws)] conn = get_db() conditions = [] params = [] if chain: conditions.append("network = ?") params.append(chain) if domains: conditions.append(f"domain IN ({','.join('?' * len(domains))})") params.extend(domains) if ptypes: conditions.append(f"protocol_type IN ({','.join('?' * len(ptypes))})") params.extend(ptypes) # Fallback to text search if no hints matched if not domains and not ptypes: words = [w for w in goal_lower.split() if len(w) > 2] if words: text_conds = [] for w in words[:5]: text_conds.append("(display_name LIKE ? OR description LIKE ?)") params.extend([f"%{w}%", f"%{w}%"]) conditions.append(f"({' OR '.join(text_conds)})") where = f"WHERE {' AND '.join(conditions)}" if conditions else "" sql = f""" SELECT id, display_name, description, auto_description, domain, protocol_type, network, reliability_score, ipfs_hash, canonical_entities FROM subgraphs {where} ORDER BY reliability_score DESC LIMIT 15 """ rows = conn.execute(sql, params).fetchall() conn.close() # Dedup by IPFS hash recommendations = [] seen_ipfs = set() for r in rows: ipfs = r["ipfs_hash"] if ipfs and ipfs in seen_ipfs: continue if ipfs: seen_ipfs.add(ipfs) recommendations.append({ "id": r["id"], "display_name": r["display_name"], "description": (r["description"] or r["auto_description"] or "")[:300], "domain": r["domain"], "protocol_type": r["protocol_type"], "network": r["network"], "reliability_score": r["reliability_score"], "ipfs_hash": r["ipfs_hash"], "canonical_entities": json.loads(r["canonical_entities"]), "query_url": f"https://gateway.thegraph.com/api/[api-key]/subgraphs/id/{r['id']}", }) if len(recommendations) >= 5: break return json.dumps({ "goal": goal, "chain_filter": chain or None, "inferred_domain": domains or None, "inferred_protocol_type": ptypes or None, "total_matches": len(recommendations), "recommendations": recommendations, }, indent=2) - src/index.js:334-346 (schema)MCP tool schema definition for recommend_subgraph. Defines the tool name, description, and inputSchema with 'goal' (required string) and 'chain' (optional string) parameters.
{ name: "recommend_subgraph", description: "Given a natural-language goal like 'find DEX trades on Arbitrum' or 'get lending liquidation data', returns the best matching subgraphs with reliability scores and query URLs. Automatically infers domain and protocol type from the goal. Each result includes a query_url — replace [api-key] with your Graph API key to query live data.", inputSchema: { type: "object", properties: { goal: { type: "string", description: "What you want to do, e.g. 'query Uniswap pool data on Base'" }, chain: { type: "string", description: "Optional chain filter: mainnet, arbitrum-one, base, matic, etc." }, }, required: ["goal"], }, }, - python/mcp_server.py:314-325 (schema)Python MCP tool schema definition for recommend_subgraph. Defines the tool metadata including name, description, and inputSchema with goal/chain properties.
{ "name": "recommend_subgraph", "description": "Given a natural-language goal like 'find DEX trades on Arbitrum' or 'get lending liquidation data', returns the best matching subgraphs with reliability scores and query instructions. Automatically infers domain and protocol type from the goal.", "inputSchema": { "type": "object", "properties": { "goal": {"type": "string", "description": "What you want to do, e.g. 'query Uniswap pool data on Base'"}, "chain": {"type": "string", "description": "Optional chain filter: mainnet, arbitrum-one, base, matic, etc."}, }, "required": ["goal"], }, }, - src/index.js:370-375 (registration)HANDLERS object that maps tool names to their handler functions. recommend_subgraph maps to the recommendSubgraph function.
const HANDLERS = { search_subgraphs: searchSubgraphs, recommend_subgraph: recommendSubgraph, get_subgraph_detail: getSubgraphDetail, list_registry_stats: listRegistryStats, };