search_markets_enriched
Search Polymarket markets and automatically enrich results with live CLOB prices and on-chain resolution status in one call.
Instructions
Power tool: search Polymarket markets then auto-enrich each result with live CLOB prices and on-chain resolution status. Combines Gamma API + CLOB API + The Graph in one call — no need to chain tools manually.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search text (e.g. 'Trump', 'Bitcoin', 'World Cup') | |
| limit | No | Number of results (1-20, kept small for enrichment speed) | |
| active | No | Filter: only active markets | |
| closed | No | Filter: only closed/resolved markets |
Implementation Reference
- src/index.ts:1292-1370 (handler)Handler for search_markets_enriched: searches Polymarket markets via Gamma API, then enriches each result with live CLOB prices (via getClobMarket) and on-chain resolution status (via the resolution subgraph) in parallel.
server.registerTool( "search_markets_enriched", { description: "Power tool: search Polymarket markets then auto-enrich each result with live CLOB prices and on-chain resolution status. Combines Gamma API + CLOB API + The Graph in one call — no need to chain tools manually.", inputSchema: { query: z.string().describe("Search text (e.g. 'Trump', 'Bitcoin', 'World Cup')"), limit: z.number().min(1).max(20).default(5).describe("Number of results (1-20, kept small for enrichment speed)"), active: z.boolean().optional().describe("Filter: only active markets"), closed: z.boolean().optional().describe("Filter: only closed/resolved markets"), }, }, async ({ query, limit, active, closed }) => { try { const markets = await searchMarkets(query, { limit, active, closed, orderBy: "volume" }); // Enrich each market with CLOB prices and resolution status in parallel const enriched = await Promise.all( markets.map(async (m) => { const base = { question: m.question, slug: m.slug, conditionId: m.conditionId, active: m.active, closed: m.closed, volume: m.volume, liquidity: m.liquidity, endDate: m.endDate, outcomes: m.outcomes, outcomePrices: m.outcomePrices, clobTokenIds: m.clobTokenIds, }; // Fetch CLOB market data + resolution status in parallel const [clobData, resolutionData] = await Promise.all([ m.conditionId ? getClobMarket(m.conditionId).catch(() => null) : Promise.resolve(null), m.conditionId ? querySubgraph( SUBGRAPHS.resolution.ipfsHash, `{ marketResolutions(where: { id: "${m.conditionId.toLowerCase()}" }, first: 1) { status flagged wasDisputed proposedPrice price lastUpdateTimestamp } }` ).catch(() => null) : Promise.resolve(null), ]); const cd = clobData as { tokens?: Array<{ token_id: string; outcome: string; price: number; winner: boolean }>; minimum_tick_size?: string; accepting_orders?: boolean; } | null; const rd = resolutionData as { marketResolutions?: Array<{ status: string; flagged: boolean; wasDisputed: boolean; proposedPrice: string; price: string; lastUpdateTimestamp: string; }>; } | null; return { ...base, liveTokens: cd?.tokens ?? null, acceptingOrders: cd?.accepting_orders ?? null, tickSize: cd?.minimum_tick_size ?? null, resolution: rd?.marketResolutions?.[0] ?? null, }; }) ); return textResult({ count: enriched.length, markets: enriched }); } catch (error) { return errorResult(error); } } ); - src/index.ts:1292-1370 (registration)Registration of the 'search_markets_enriched' tool via server.registerTool on the MCP server instance.
server.registerTool( "search_markets_enriched", { description: "Power tool: search Polymarket markets then auto-enrich each result with live CLOB prices and on-chain resolution status. Combines Gamma API + CLOB API + The Graph in one call — no need to chain tools manually.", inputSchema: { query: z.string().describe("Search text (e.g. 'Trump', 'Bitcoin', 'World Cup')"), limit: z.number().min(1).max(20).default(5).describe("Number of results (1-20, kept small for enrichment speed)"), active: z.boolean().optional().describe("Filter: only active markets"), closed: z.boolean().optional().describe("Filter: only closed/resolved markets"), }, }, async ({ query, limit, active, closed }) => { try { const markets = await searchMarkets(query, { limit, active, closed, orderBy: "volume" }); // Enrich each market with CLOB prices and resolution status in parallel const enriched = await Promise.all( markets.map(async (m) => { const base = { question: m.question, slug: m.slug, conditionId: m.conditionId, active: m.active, closed: m.closed, volume: m.volume, liquidity: m.liquidity, endDate: m.endDate, outcomes: m.outcomes, outcomePrices: m.outcomePrices, clobTokenIds: m.clobTokenIds, }; // Fetch CLOB market data + resolution status in parallel const [clobData, resolutionData] = await Promise.all([ m.conditionId ? getClobMarket(m.conditionId).catch(() => null) : Promise.resolve(null), m.conditionId ? querySubgraph( SUBGRAPHS.resolution.ipfsHash, `{ marketResolutions(where: { id: "${m.conditionId.toLowerCase()}" }, first: 1) { status flagged wasDisputed proposedPrice price lastUpdateTimestamp } }` ).catch(() => null) : Promise.resolve(null), ]); const cd = clobData as { tokens?: Array<{ token_id: string; outcome: string; price: number; winner: boolean }>; minimum_tick_size?: string; accepting_orders?: boolean; } | null; const rd = resolutionData as { marketResolutions?: Array<{ status: string; flagged: boolean; wasDisputed: boolean; proposedPrice: string; price: string; lastUpdateTimestamp: string; }>; } | null; return { ...base, liveTokens: cd?.tokens ?? null, acceptingOrders: cd?.accepting_orders ?? null, tickSize: cd?.minimum_tick_size ?? null, resolution: rd?.marketResolutions?.[0] ?? null, }; }) ); return textResult({ count: enriched.length, markets: enriched }); } catch (error) { return errorResult(error); } } ); - src/index.ts:1297-1302 (schema)Input schema definition for search_markets_enriched: accepts query string, limit (1-20, default 5), optional active/closed booleans.
inputSchema: { query: z.string().describe("Search text (e.g. 'Trump', 'Bitcoin', 'World Cup')"), limit: z.number().min(1).max(20).default(5).describe("Number of results (1-20, kept small for enrichment speed)"), active: z.boolean().optional().describe("Filter: only active markets"), closed: z.boolean().optional().describe("Filter: only closed/resolved markets"), }, - src/polymarketApi.ts:71-85 (helper)The searchMarkets helper function called by search_markets_enriched to query the Gamma API for market search results.
export async function searchMarkets( query: string, opts: { limit?: number; active?: boolean; closed?: boolean; orderBy?: string; ascending?: boolean } = {} ): Promise<GammaMarket[]> { const params = new URLSearchParams(); params.set("_limit", String(opts.limit ?? 10)); if (query) params.set("_q", query); if (opts.active !== undefined) params.set("active", String(opts.active)); if (opts.closed !== undefined) params.set("closed", String(opts.closed)); if (opts.orderBy) { params.set("_sort", opts.orderBy); params.set("_order", opts.ascending ? "asc" : "desc"); } return fetchJson<GammaMarket[]>(`${GAMMA_BASE}/markets?${params}`); } - src/polymarketApi.ts:211-215 (helper)The getClobMarket helper function called by search_markets_enriched to fetch live CLOB data for each market.
export async function getClobMarket(conditionId: string): Promise<ClobMarket> { return fetchJson<ClobMarket>( `${CLOB_BASE}/markets/${encodeURIComponent(conditionId)}` ); }