Skip to main content
Glama
gianlucamazza

MCP ASCII Charts

create_line_chart

Generate ASCII line charts to visualize temporal data trends in terminal environments using numeric arrays and optional labels.

Instructions

Generate ASCII line charts for temporal data visualization

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
dataYesArray of numeric values to plot
labelsNoOptional labels for x-axis (must match data length)
titleNoOptional chart title
widthNoChart width (10-200, default: 60)
heightNoChart height (5-50, default: 15)
colorNoANSI color name (red, green, blue, yellow, etc.)

Implementation Reference

  • Core handler function that implements the ASCII line chart generation. Handles data validation, grid setup, axis drawing, point plotting, line interpolation using a custom drawLine function, coloring, and formatting.
    export function createLineChart(data: ChartData): ChartResult {
      const { data: values, labels, title, width = 60, height = 15, color = 'white' } = data;
      
      if (values.length === 0) {
        throw new Error('Data array cannot be empty');
      }
    
      const chartWidth = width - 10; // Reserve space for y-axis labels
      const chartHeight = height - 2; // Reserve space for x-axis
      
      const minValue = Math.min(...values);
      const maxValue = Math.max(...values);
      const valueRange = maxValue - minValue;
      
      // Create the chart grid
      const grid = createGrid(width, height);
      
      // Draw y-axis labels and grid lines
      for (let y = 0; y < chartHeight; y++) {
        const value = maxValue - (y / (chartHeight - 1)) * valueRange;
        const label = value.toFixed(1);
        const labelStr = padLeft(label, 8);
        
        // Place y-axis label
        for (let i = 0; i < Math.min(labelStr.length, 8); i++) {
          if (8 - i < width) {
            grid[y][8 - i] = labelStr[i];
          }
        }
        
        // Draw y-axis line
        if (9 < width) {
          grid[y][9] = y === chartHeight - 1 ? ASCII_CHARS.bottomLeft : 
                       y === 0 ? ASCII_CHARS.topLeft : ASCII_CHARS.teeRight;
        }
        
        // Draw horizontal grid lines (optional light lines)
        for (let x = 10; x < width; x++) {
          if (y === chartHeight - 1) {
            grid[y][x] = ASCII_CHARS.horizontal;
          } else if (y % 2 === 0) {
            grid[y][x] = '·'; // Light grid dots
          }
        }
      }
      
      // Draw x-axis labels
      if (labels && labels.length === values.length) {
        // const labelSpacing = Math.max(1, Math.floor(chartWidth / Math.min(labels.length, 8)));
        for (let i = 0; i < labels.length && i < 8; i++) {
          const x = 10 + Math.floor((i / (labels.length - 1)) * (chartWidth - 1));
          const label = labels[i].substring(0, 6); // Truncate long labels
          
          if (x + label.length <= width && height - 1 >= 0) {
            for (let j = 0; j < label.length && x + j < width; j++) {
              grid[height - 1][x + j] = label[j];
            }
          }
        }
      }
      
      // Plot the line
      const plotPoints: { x: number; y: number }[] = [];
      
      for (let i = 0; i < values.length; i++) {
        const x = values.length === 1 ? 
          10 + Math.floor(chartWidth / 2) : 
          10 + Math.floor((i / (values.length - 1)) * (chartWidth - 1));
        const normalizedValue = valueRange === 0 ? 0.5 : normalize(values[i], minValue, maxValue);
        const y = Math.floor((1 - normalizedValue) * (chartHeight - 1));
        
        plotPoints.push({ x: clamp(x, 10, width - 1), y: clamp(y, 0, chartHeight - 1) });
      }
      
      // Draw line segments between points
      for (let i = 0; i < plotPoints.length; i++) {
        const point = plotPoints[i];
        
        // Draw the point
        if (point.x < width && point.y < chartHeight) {
          grid[point.y][point.x] = '●';
        }
        
        // Draw line to next point
        if (i < plotPoints.length - 1) {
          const nextPoint = plotPoints[i + 1];
          drawLine(grid, point.x, point.y, nextPoint.x, nextPoint.y, chartWidth, chartHeight);
        }
      }
      
      // Convert grid to string and apply coloring
      let chart = gridToString(grid);
      
      if (color !== 'white') {
        chart = colorize(chart, color);
      }
      
      // Add title if provided
      if (title) {
        const titleLine = center(title, width);
        chart = titleLine + '\n' + chart;
      }
      
      return {
        chart,
        title,
        dimensions: { width, height }
      };
    }
  • src/index.ts:339-346 (registration)
    Tool dispatch/registration in the generateChart switch statement, calling the createLineChart handler with validated chartData.
    case 'create_line_chart': {
      progress.nextStep('Generating line chart');
      result = await withRequestTracking(
        () => Promise.resolve(createLineChart(chartData)),
        'create_line_chart'
      )();
      break;
    }
  • MCP tool input schema definition for 'create_line_chart', specifying parameters, types, descriptions, constraints, and examples.
    type: 'object',
    properties: {
      data: {
        type: 'array',
        items: { type: 'number' },
        description: 'Array of numeric values to plot'
      },
      labels: {
        type: 'array',
        items: { type: 'string' },
        description: 'Optional labels for x-axis (must match data length)',
        optional: true
      },
      title: {
        type: 'string',
        description: 'Optional chart title',
        optional: true
      },
      width: {
        type: 'number',
        description: 'Chart width (10-200, default: 60)',
        minimum: 10,
        maximum: 200,
        optional: true
      },
      height: {
        type: 'number',
        description: 'Chart height (5-50, default: 15)',
        minimum: 5,
        maximum: 50,
        optional: true
      },
      color: {
        type: 'string',
        description: 'ANSI color name (red, green, blue, yellow, etc.)',
        optional: true
      }
    },
    required: ['data'],
    examples: getToolExamples('create_line_chart')
  • TypeScript interface defining the ChartData input structure used by the handler and validation.
    export interface ChartData {
      data: number[];
      labels?: string[];
      title?: string;
      width?: number;
      height?: number;
      color?: string;
    }
  • Helper function implementing line drawing algorithm for connecting data points in the chart.
    function drawLine(
      grid: string[][],
      x1: number,
      y1: number,
      x2: number,
      y2: number,
      maxWidth: number,
      maxHeight: number
    ): void {
      const dx = Math.abs(x2 - x1);
      const dy = Math.abs(y2 - y1);
      const sx = x1 < x2 ? 1 : -1;
      const sy = y1 < y2 ? 1 : -1;
      let err = dx - dy;
      
      let x = x1;
      let y = y1;
      
      // eslint-disable-next-line no-constant-condition
      while (true) {
        // Draw line character based on direction
        if (x >= 10 && x < maxWidth + 10 && y >= 0 && y < maxHeight) {
          if (grid[y][x] === ' ' || grid[y][x] === '·') {
            if (dx > dy) {
              grid[y][x] = ASCII_CHARS.horizontal;
            } else if (dy > dx) {
              grid[y][x] = ASCII_CHARS.vertical;
            } else {
              grid[y][x] = x < x2 ? ASCII_CHARS.curveUpRight : ASCII_CHARS.curveUpLeft;
            }
          }
        }
        
        if (x === x2 && y === y2) break;
        
        const e2 = 2 * err;
        if (e2 > -dy) {
          err -= dy;
          x += sx;
        }
        if (e2 < dx) {
          err += dx;
          y += sy;
        }
      }
    }

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/gianlucamazza/mcp-ascii-charts'

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