UNPKG

@chainlink/mcp-server

Version:
169 lines 7.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.searchDataFeedsDataSources = void 0; const logger_1 = require("../../../utils/logger"); const strings_1 = require("../shared/strings"); const matching_1 = require("../shared/matching"); const load_1 = require("./load"); function calculateFeedsRelevance(feed, query, _chainId, networkType, networkName, networkQueryString, preferredEnv, parsedPair) { let score = 0; const queryLower = query.toLowerCase(); if (preferredEnv && networkType === preferredEnv) score += 50; if (parsedPair && feed?.name) { const nameNormalized = feed.name .toUpperCase() .replace(/\s+/g, ""); const pairSlash = `${parsedPair.base}/${parsedPair.quote}`.toUpperCase(); const pairCompact = `${parsedPair.base}${parsedPair.quote}`.toUpperCase(); if (nameNormalized.includes(pairSlash.replace(/\s+/g, "")) || nameNormalized.includes(pairCompact)) { score += 200; } } if (feed.name && feed.name.toLowerCase().includes(queryLower)) score += 100; if (feed.assetName && feed.assetName.toLowerCase().includes(queryLower)) score += 80; if (feed.feedType && feed.feedType.toLowerCase().includes(queryLower)) score += 60; const feedNameWords = (feed.name || "").toLowerCase().split(/[\s\/]+/); const assetNameWords = (feed.assetName || "").toLowerCase().split(/[\s\/]+/); const queryWords = queryLower.split(/\s+/); for (const queryWord of queryWords) { if (queryWord.length > 2) { if (feedNameWords.some((word) => word.includes(queryWord))) score += 40; if (assetNameWords.some((word) => word.includes(queryWord))) score += 30; } } if (!preferredEnv && networkType === "mainnet") score += 5; // Boost if chain id or query string tokens appear in query const qNormChain = (0, strings_1.removeSeparatorsForMatching)(queryLower); const idNorm = (0, strings_1.removeSeparatorsForMatching)((_chainId || "").toLowerCase()); if (idNorm && (qNormChain.includes(idNorm) || idNorm.includes(qNormChain))) { score += 60; } if (networkQueryString) { const qs = networkQueryString.toLowerCase(); const qsNorm = (0, strings_1.removeSeparatorsForMatching)(qs); if (qNormChain.includes(qsNorm) || qsNorm.includes(qNormChain)) { score += 120; } for (const part of qs.split(/[-_\s]+/)) { if (part.length > 2 && queryLower.includes(part)) score += 100; } } // Boost when network name matches query (e.g., "Fuji" testnet) if (networkName) { const nn = networkName.toLowerCase(); const nnNorm = (0, strings_1.removeSeparatorsForMatching)(nn); const qNorm = (0, strings_1.removeSeparatorsForMatching)(queryLower); if (qNorm.includes(nnNorm) || nnNorm.includes(qNorm)) { score += 200; } // Specific boost for common testnet aliases within network names const aliases = [ "fuji", "sepolia", "holesky", "amoy", "mumbai", "devnet", "testnet", ]; if (aliases.some((a) => nn.includes(a) && queryLower.includes(a))) { score += 150; } } if ((queryLower.includes("address") || queryLower.includes("contract") || queryLower.includes("proxy")) && feed.proxyAddress) { score += 40; } if (queryLower.includes("price") && feed.feedType === "Crypto") score += 20; return score; } const searchDataFeedsDataSources = async (query) => { const results = []; try { const preferredEnv = (0, strings_1.extractEnvironmentFromQuery)(query); const parsedPair = (0, strings_1.parseAssetPairFromQuery)(query); const feedsIndex = await (0, load_1.loadDataFeedsIndex)(); if (!feedsIndex) { logger_1.Logger.debug("Data Feeds index not available"); return results; } // Centralized detection from shared keyword index const chainNames = await (0, matching_1.detectChainsFromQuery)(query, "dataFeeds"); let chainsToSearch = []; if (chainNames.length > 0) { chainsToSearch = (0, matching_1.matchChainsFromQuery)(chainNames, feedsIndex.chains, "dataFeeds"); logger_1.Logger.debug(`Found chains to search for feeds: ${chainsToSearch.join(", ")}`); } else { const chainsWithCounts = (feedsIndex.chains || []) .map((chain) => ({ chainId: chain.chainId, count: (typeof chain.feedCount === "number" && chain.feedCount) || (typeof chain.totalFeeds === "number" && chain.totalFeeds) || 0, })) .sort((a, b) => b.count - a.count); if (chainsWithCounts.length > 0 && chainsWithCounts[0].count > 0) { chainsToSearch = chainsWithCounts .slice(0, 6) .map((c) => c.chainId); logger_1.Logger.debug(`No specific chains detected, searching top chains by feed count: ${chainsToSearch.join(", ")}`); } else { const popularChains = [ "ethereum", "arbitrum", "polygon", "avalanche", "base", "optimism", ]; chainsToSearch = popularChains.filter((chainId) => feedsIndex.chains.some((chain) => chain.chainId === chainId)); logger_1.Logger.debug(`No specific chains detected, searching popular chains: ${chainsToSearch.join(", ")}`); } } for (const chainId of chainsToSearch) { const chainFeedsData = await (0, load_1.loadDataFeedsData)(chainId); if (!chainFeedsData) continue; for (const network of chainFeedsData.networks || []) { for (const feed of network.feeds || []) { const relevance = calculateFeedsRelevance(feed, query, chainId, network.networkType, network.networkName, network.queryString, preferredEnv || undefined, parsedPair); if (relevance > 0) { results.push({ chainId: chainId, chainLabel: chainFeedsData.chainLabel, networkName: network.networkName, networkType: network.networkType, queryString: network.queryString, feed: feed, relevance: relevance, dataType: "feeds", }); } } } } logger_1.Logger.debug(`Found ${results.length} relevant Data Feeds results`); } catch (error) { logger_1.Logger.log("warn", `Failed to search Data Feeds configuration: ${error}`); } return results .sort((a, b) => (b.relevance || 0) - (a.relevance || 0)) .slice(0, 30); }; exports.searchDataFeedsDataSources = searchDataFeedsDataSources; //# sourceMappingURL=search.js.map