Skip to main content
Glama
0xGval
by 0xGval

getTokenPriceHistory

Retrieve historical price data for Ethereum tokens to analyze market trends and track performance over time.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
addressYes
networkIdNoNetwork ID (1 for Ethereum, 101 for Solana)
daysNoNumber of days of history
resolutionNoTime resolution (e.g. 1D, 1H, 60)1D

Implementation Reference

  • The core handler function that executes the tool: calculates unix timestamps for the requested period, fetches OHLCV chart data via fetchChartData helper from Codex GraphQL API, formats it using formatChartDataResponse, and returns formatted text response or error.
    async ({ address, networkId, days, resolution }) => {
      try {
        // Calculate time range
        const to = Math.floor(Date.now() / 1000);
        const from = to - (60 * 60 * 24 * days);
        
        // Get chart data from Codex API
        const chartData = await fetchChartData(address, networkId, resolution, from, to);
        
        if (!chartData || chartData.length === 0) {
          return {
            content: [{ type: "text", text: `No price history found for ${address} on network ${networkId}` }]
          };
        }
        
        // Format the chart data for display
        const response = formatChartDataResponse(chartData);
        
        return {
          content: [{ type: "text", text: response }]
        };
      } catch (error) {
        return {
          content: [{ type: "text", text: `Error fetching token price history: ${error.message}` }]
        };
      }
    }
  • Zod input validation schema defining required token address, optional networkId (default 1), days (default 7), and resolution (default '1D').
    { 
      address: z.string().min(1, "Token address is required"),
      networkId: z.number().int().positive().default(1).describe("Network ID (1 for Ethereum, 101 for Solana)"),
      days: z.number().int().positive().default(7).describe("Number of days of history"),
      resolution: z.string().default("1D").describe("Time resolution (e.g. 1D, 1H, 60)")
    },
  • MCP tool registration via server.tool() call within registerTokenAnalysisTools function, specifying name, input schema, and inline handler implementation.
    server.tool("getTokenPriceHistory",
      { 
        address: z.string().min(1, "Token address is required"),
        networkId: z.number().int().positive().default(1).describe("Network ID (1 for Ethereum, 101 for Solana)"),
        days: z.number().int().positive().default(7).describe("Number of days of history"),
        resolution: z.string().default("1D").describe("Time resolution (e.g. 1D, 1H, 60)")
      },
      async ({ address, networkId, days, resolution }) => {
        try {
          // Calculate time range
          const to = Math.floor(Date.now() / 1000);
          const from = to - (60 * 60 * 24 * days);
          
          // Get chart data from Codex API
          const chartData = await fetchChartData(address, networkId, resolution, from, to);
          
          if (!chartData || chartData.length === 0) {
            return {
              content: [{ type: "text", text: `No price history found for ${address} on network ${networkId}` }]
            };
          }
          
          // Format the chart data for display
          const response = formatChartDataResponse(chartData);
          
          return {
            content: [{ type: "text", text: response }]
          };
        } catch (error) {
          return {
            content: [{ type: "text", text: `Error fetching token price history: ${error.message}` }]
          };
        }
      }
    );
  • Key helper that performs GraphQL query to Codex API (graph.codex.io) for historical price bars (OHLCV + volume, transactions, etc.), processes multi-field response into structured bar array.
    async function fetchChartData(address, networkId, resolution = '1D', from, to) {
      try {
        // Use API key from environment variable
        const apiKey = process.env.CODEX_API_KEY;
        if (!apiKey) {
          throw new Error("CODEX_API_KEY environment variable is not set");
        }
        
        const response = await axios({
          url: API_URL,
          method: 'post',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': apiKey
          },
          data: {
            query: `{
              getBars(
                symbol: "${address}:${networkId}"
                from: ${from}
                to: ${to}
                resolution: "${resolution}"
                removeEmptyBars: true
              ) {
                t
                o
                h
                l
                c
                v
                volume
                transactions
                buyers
                sellers
                traders
                liquidity
                buyVolume
                sellVolume
                buys
                sells
                volumeNativeToken
              }
            }`
          }
        });
        
        if (response.data && response.data.data && response.data.data.getBars) {
          const bars = response.data.data.getBars;
          
          // Process bars data
          if (Array.isArray(bars.t)) {
            // Multiple bars - restructure into an array of bar objects
            const result = [];
            for (let i = 0; i < bars.t.length; i++) {
              result.push({
                t: bars.t[i],
                o: bars.o[i],
                h: bars.h[i],
                l: bars.l[i],
                c: bars.c[i],
                v: bars.v ? bars.v[i] : null,
                volume: bars.volume ? bars.volume[i] : null,
                transactions: bars.transactions ? bars.transactions[i] : null,
                buyers: bars.buyers ? bars.buyers[i] : null,
                sellers: bars.sellers ? bars.sellers[i] : null,
                traders: bars.traders ? bars.traders[i] : null,
                liquidity: bars.liquidity ? bars.liquidity[i] : null,
                buyVolume: bars.buyVolume ? bars.buyVolume[i] : null,
                sellVolume: bars.sellVolume ? bars.sellVolume[i] : null,
                buys: bars.buys ? bars.buys[i] : null,
                sells: bars.sells ? bars.sells[i] : null,
                volumeNativeToken: bars.volumeNativeToken ? bars.volumeNativeToken[i] : null
              });
            }
            return result;
          } else if (typeof bars.t === 'number') {
            // Single bar
            return [{
              t: bars.t,
              o: bars.o,
              h: bars.h,
              l: bars.l,
              c: bars.c,
              v: bars.v,
              volume: bars.volume,
              transactions: bars.transactions,
              buyers: bars.buyers,
              sellers: bars.sellers,
              traders: bars.traders,
              liquidity: bars.liquidity,
              buyVolume: bars.buyVolume,
              sellVolume: bars.sellVolume,
              buys: bars.buys,
              sells: bars.sells,
              volumeNativeToken: bars.volumeNativeToken
            }];
          }
        }
        
        return [];
      } catch (error) {
        console.error('Error fetching chart data:', error.response?.data || error.message);
        throw new Error(`API error: ${error.response?.data?.errors?.[0]?.message || error.message}`);
      }
    }
  • Helper to format raw chart data into human-readable markdown table with OHLCV prices, volume, overall price change percentage, and aggregate trading stats.
    function formatChartDataResponse(data) {
      let response = `=== Price History ===\n`;
      response += `Date       | Open     | High     | Low      | Close    | Volume\n`;
      response += `-----------|----------|----------|----------|----------|------------\n`;
      
      data.forEach(bar => {
        // Make sure all fields are present to avoid errors
        if (bar.t && bar.o !== undefined && bar.h !== undefined && 
            bar.l !== undefined && bar.c !== undefined) {
          response += `${formatDate(bar.t)} | $${bar.o.toFixed(4).padEnd(8)} | $${bar.h.toFixed(4).padEnd(8)} | $${bar.l.toFixed(4).padEnd(8)} | $${bar.c.toFixed(4).padEnd(8)} | $${formatNumber(bar.volume || bar.v)}\n`;
        }
      });
      
      // Display price change
      if (data.length > 1) {
        const firstPrice = data[0].o;
        const lastPrice = data[data.length - 1].c;
        const priceChange = ((lastPrice - firstPrice) / firstPrice) * 100;
        
        response += `\nPrice change over period: ${priceChange.toFixed(2)}%\n`;
        
        // Show basic trading activity
        response += '\n=== Recent Trading Activity ===\n';
        const totalTransactions = data.reduce((sum, bar) => sum + (bar.transactions || 0), 0);
        const totalTraders = data.reduce((sum, bar) => sum + (bar.traders || 0), 0);
        
        response += `Total Transactions: ${totalTransactions}\n`;
        response += `Total Unique Traders: ${totalTraders}\n`;
      }
      
      return response;
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/0xGval/evm-mcp-tools'

If you have feedback or need assistance with the MCP directory API, please join our Discord server