search_markets
Find markets by keyword or category with enriched on-chain data including volume and trade counts.
Instructions
Search markets by keyword or category. Returns market metadata enriched with on-chain volume and trade counts from subgraphs.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Keyword to search in title/description | |
| categories | No | Filter by categories (e.g. ['Crypto', 'Politics']) | |
| first | No | Number of results to return |
Implementation Reference
- mcp-server/src/index.ts:165-199 (handler)The handler for the search_markets tool, which invokes the apiClient's searchMarkets function and then enriches the results with subgraph data.
async ({ query, categories, first }) => { try { const apiResults = await searchMarkets(query, categories, first); // Enrich each result with on-chain stats from subgraphs const enriched = await Promise.all( apiResults.map(async (m) => { const mq = (entity: string) => `{ ${entity}(id: "${m.conditionId}") { tradesCount volumeUSD feesUSD } }`; const [s, n] = await Promise.all([ querySimple(mq("market")).catch(() => ({ market: null })), queryNegRisk(mq("negRiskMarket")).catch(() => ({ negRiskMarket: null })), ]); const onChain = s.market || n.negRiskMarket; return { title: m.title, conditionId: m.conditionId, categories: m.categories, currentPrices: m.prices, expirationDate: m.expirationDate, marketType: m.marketType, tradeType: m.tradeType, status: m.status, onChainVolume: onChain?.volumeUSD || "0", onChainTrades: onChain?.tradesCount || "0", onChainFees: onChain?.feesUSD || "0", }; }) ); return textResult({ count: enriched.length, markets: enriched }); } catch (e) { return errorResult(e); } } - mcp-server/src/apiClient.ts:130-176 (handler)The implementation of searchMarkets in apiClient.ts, which fetches from the API and filters cached markets.
export async function searchMarkets( query?: string, categories?: string[], first = 20 ): Promise<MarketMeta[]> { // If there's a query, also try the API search endpoint for broader results if (query) { const headers = getHeaders(); try { const res = await fetch( `${LIMITLESS_API_BASE}/markets/search?query=${encodeURIComponent(query)}`, { headers } ); if (res.ok) { const json = (await res.json()) as { markets: any[] }; for (const m of json.markets || []) { const meta = toMarketMeta(m); if (meta) marketCache.set(meta.conditionId.toLowerCase(), meta); } } } catch { // Fall back to cache-only search } } await refreshMarketCache(); let results = Array.from(marketCache.values()); if (query) { const q = query.toLowerCase(); results = results.filter( (m) => m.title.toLowerCase().includes(q) || m.description.toLowerCase().includes(q) || m.slug.toLowerCase().includes(q) ); } if (categories && categories.length > 0) { const cats = categories.map((c) => c.toLowerCase()); results = results.filter((m) => m.categories.some((c) => cats.includes(c.toLowerCase())) ); } return results.slice(0, first); } - mcp-server/src/index.ts:151-164 (registration)Registration of the search_markets tool in the MCP server.
server.registerTool( "search_markets", { description: "Search markets by keyword or category. Returns market metadata enriched with on-chain volume and trade counts from subgraphs.", inputSchema: { query: z.string().optional().describe("Keyword to search in title/description"), categories: z .array(z.string()) .optional() .describe("Filter by categories (e.g. ['Crypto', 'Politics'])"), first: z.number().default(20).describe("Number of results to return"), }, },