get_price_history
Retrieve historical price data for tokens on Base by querying DEX pool swap events. Specify token address, time intervals, and data points to analyze price trends.
Instructions
Get recent price data points by querying swap events from DEX pools
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| token_address | Yes | Token contract address on Base | |
| periods | No | Number of data points to return | |
| interval | No | Time interval between points (e.g. 1h, 15m, 1d) | 1h |
Implementation Reference
- src/index.ts:474-568 (handler)The tool `get_price_history` is defined and implemented here as an MCP tool, which queries DEX pools for recent swap events to generate price history.
server.tool( "get_price_history", "Get recent price data points by querying swap events from DEX pools", { token_address: z.string().describe("Token contract address on Base"), periods: z.number().default(24).describe("Number of data points to return"), interval: z.string().default("1h").describe("Time interval between points (e.g. 1h, 15m, 1d)"), }, async ({ token_address, periods, interval }) => { try { const quoteAddress = WETH; const [tokenDecimals, quoteDecimals, tokenSymbol] = await Promise.all([ getTokenDecimals(token_address), getTokenDecimals(quoteAddress), getTokenSymbol(token_address), ]); const pools = await findAllPools(token_address, quoteAddress); if (pools.length === 0) { return { content: [{ type: "text" as const, text: `No DEX pools found for ${token_address} on Base.` }] }; } // Use the pool with most liquidity (V2: highest reserves, V3: highest liquidity) const bestPool = pools[0]; const blocksPerInterval = intervalToBlocks(interval); const totalBlocks = blocksPerInterval * periods; // Cap at ~50000 blocks to avoid RPC limits const lookback = Math.min(totalBlocks, 50000); const swaps = await getSwapHistory(bestPool, tokenDecimals, quoteDecimals, lookback); if (swaps.length === 0) { // Fall back to current price only const currentPrice = calculatePrice(bestPool, tokenDecimals, quoteDecimals); return { content: [{ type: "text" as const, text: JSON.stringify({ token: token_address, symbol: tokenSymbol, message: "No recent swap events found. Current spot price from reserves:", currentPrice: formatEth(currentPrice), dex: bestPool.dex, }, null, 2), }], }; } // Bucket swaps into intervals const now = swaps[swaps.length - 1].timestamp; const intervalSeconds = blocksPerInterval * 2; // 2s per block const buckets: PricePoint[][] = []; for (let i = 0; i < periods; i++) { const bucketEnd = now - i * intervalSeconds; const bucketStart = bucketEnd - intervalSeconds; const bucketSwaps = swaps.filter( (s) => s.timestamp > bucketStart && s.timestamp <= bucketEnd ); buckets.unshift(bucketSwaps); } const dataPoints = buckets.map((bucket, i) => { const time = now - (periods - 1 - i) * intervalSeconds; if (bucket.length === 0) { return { timestamp: time, price: null, swapCount: 0 }; } const avgPrice = bucket.reduce((s, p) => s + p.price, 0) / bucket.length; return { timestamp: time, price: formatEth(avgPrice), swapCount: bucket.length, }; }); return { content: [{ type: "text" as const, text: JSON.stringify({ token: token_address, symbol: tokenSymbol, dex: bestPool.dex, interval, periods: dataPoints.length, totalSwaps: swaps.length, data: dataPoints, }, null, 2), }], }; } catch (err: unknown) { const msg = err instanceof Error ? err.message : String(err); return { content: [{ type: "text" as const, text: `Error: ${msg}` }] }; } } );