generate_progress_chart
Create progress charts to visualize completion rates, proportional metrics, and normalized quantitative values between 0 and 1 using gauge, liquid, linear, or circular formats.
Instructions
Generates a progress chart for visualizing quantitative values normalized between 0 and 1. Ideal for representing progress, completion rates, or proportional metrics. The gauge chart and liquid chart currently only supports displaying data for a single dimension.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| output | No | Chart output type. Defaults to 'image'. | image |
| width | No | Chart width. Optional, defaults to 500. | |
| height | No | Chart height. Optional, defaults to 500. | |
| dataTable | Yes | Data for the progress chart, e.g., [{ category: 'category 01', value: 0.5 }]. | |
| chartType | Yes | ||
| colorField | No | Dimension field, Must exist in the data, required in linear_progress, circular_progress and gauge | |
| valueField | Yes | Measure field with values in [0, 1]. Must exist in the data. | |
| chartTheme | No | Chart theme. Optional, defaults to 'light'. | |
| title | No | Chart title text. | |
| subTitle | No | Chart subtitle text. | |
| titleOrient | No | Title position in the chart. | |
| background | No | Chart background color (hex). Optional, defaults to white. | |
| colors | No | Color palette for chart elements. |
Implementation Reference
- src/server.ts:43-125 (handler)The MCP CallToolRequest handler that executes 'generate_progress_chart' by identifying the 'progress' chart type from the tool name, validating arguments with the progress schema, invoking generateChartByType('progress', args), and formatting the response as text content (spec, image URL, or HTML URL).server.setRequestHandler(CallToolRequestSchema, async request => { const toolName = request.params.name; const chartType = Object.keys(Charts).find( key => (Charts as any)[key].tool.name === toolName ); if (!chartType) { throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}.` ); } try { // Validate input using Zod before generating chart const args = request.params.arguments || {}; // Select the appropriate schema based on the chart type const schema = Charts[chartType as keyof typeof Charts].schema; if (schema) { const result = schema.safeParse(args); if (!result.success) { throw new McpError( ErrorCode.InvalidParams, `Invalid parameters: ${result.error.message}` ); } } const res = await generateChartByType(chartType, args); if (res && (res as any).spec) { return { content: [ { type: 'text', text: JSON.stringify((res as any).spec, null, 2), }, ], }; } if (res && (res as any).image) { return { content: [ { type: 'text', text: (res as any).image, }, ], }; } if (res && (res as any).html) { return { content: [ { type: 'text', text: (res as any).html, }, ], }; } return { content: [ { type: 'text', text: 'Failed to generate chart', }, ], }; } catch (error: any) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Failed to generate chart: ${error?.message || 'Unknown error.'}` ); } });
- src/charts/progress.ts:16-50 (schema)Zod schema defining the input parameters for generate_progress_chart, including output format, dimensions, dataTable, chartType (linear_progress, circular_progress, gauge, liquid), valueField, styling options like theme, title, background, and colors.const schema = z.object({ output: ChartOutputSchema, width: WidthSchema, height: HeightSchema, dataTable: z .array(z.any()) .describe( "Data for the progress chart, e.g., [{ category: 'category 01', value: 0.5 }]." ) .nonempty({ message: "Data for the progress chart must not be empty.", }), chartType: z.enum([ "linear_progress", "circular_progress", "gauge", "liquid", ]), colorField: z .string() .optional() .describe( "Dimension field, Must exist in the data, required in linear_progress, circular_progress and gauge" ), valueField: ProgressFieldSchema, chartTheme: ThemeSchema, title: TitleTextSchema, subTitle: TitleSubTextSchema, titleOrient: TitleOrientSchema, background: BackgroundSchema, colors: ColorsSchema, });
- src/charts/progress.ts:52-62 (registration)Defines and exports the tool metadata for 'generate_progress_chart', including name, description, and JSON schema derived from Zod for MCP tool registration.const tool = { name: "generate_progress_chart", description: "Generates a progress chart for visualizing quantitative values normalized between 0 and 1. Ideal for representing progress, completion rates, or proportional metrics. The gauge chart and liquid chart currently only supports displaying data for a single dimension.", inputSchema: convertZodToJsonSchema(schema), }; export const progress = { schema, tool, };
- src/server.ts:34-38 (registration)MCP ListToolsRequest handler that dynamically registers all chart tools, including generate_progress_chart, by collecting .tool objects from imported charts modules.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: Object.values(Charts).map(chart => (chart as any).tool), }; });
- src/utils/generateChart.ts:42-202 (helper)Primary helper function invoked by the handler for 'progress' chartType; normalizes options, extracts fields/axes/title, generates VChart spec using generateChart from @visactor/generate-vchart (with sub chartType), and renders to image URL, HTML URL, or spec via external service.export async function generateChartByType(chartType: string, options: any) { const { title, subTitle, titleOrient, xAxisType, xAxisOrient, xAxisTitle, xAxisHasGrid, xAxisHasLabel, xAxisHasTick, yAxisType, yAxisOrient, yAxisTitle, yAxisHasGrid, yAxisHasLabel, yAxisHasTick, leftYAxisTitle, leftYAxisHasGrid, leftYAxisHasLabel, leftYAxisHasTick, rightYAxisTitle, rightYAxisHasGrid, rightYAxisHasLabel, rightYAxisHasTick, angleAxisTitle, angleAxisHasGrid, angleAxisHasLabel, angleAxisHasTick, angleAxisType, radiusAxisHasGrid, radiusAxisHasLabel, radiusAxisHasTick, radiusAxisType, radiusAxisTitle, output, width, height, ...res } = options; const opts = { ...res }; const titleObj = filterValidAttributes({ text: title, subText: subTitle, orient: titleOrient, }); const xAxisObj = filterValidAttributes({ type: xAxisType, orient: xAxisOrient, title: xAxisTitle, hasGrid: xAxisHasGrid, hasLabel: xAxisHasLabel, hasTick: xAxisHasTick, }); const yAxisObj = filterValidAttributes({ type: yAxisType, orient: yAxisOrient, title: yAxisTitle, hasGrid: yAxisHasGrid, hasLabel: yAxisHasLabel, hasTick: yAxisHasTick, }); const leftYAxisObj = filterValidAttributes({ title: leftYAxisTitle, hasGrid: leftYAxisHasGrid, hasLabel: leftYAxisHasLabel, hasTick: leftYAxisHasTick, }); const rightYAxisObj = filterValidAttributes({ title: rightYAxisTitle, hasGrid: rightYAxisHasGrid, hasLabel: rightYAxisHasLabel, hasTick: rightYAxisHasTick, }); const angleAxisObj = filterValidAttributes({ title: angleAxisTitle, hasGrid: angleAxisHasGrid, hasLabel: angleAxisHasLabel, hasTick: angleAxisHasTick, type: angleAxisType, }); const radiusAxisObj = filterValidAttributes({ hasGrid: radiusAxisHasGrid, hasLabel: radiusAxisHasLabel, hasTick: radiusAxisHasTick, type: radiusAxisType, title: radiusAxisTitle, }); const cell: Record<string, string> = {}; [ "xField", "yField", "colorField", "categoryField", "valueField", "wordField", "sizeField", "timeField", "sourceField", "targetField", "setsField", "radiusField", ].forEach((fieldName) => { if (isValid(options[fieldName])) { cell[fieldName.replace("Field", "")] = options[fieldName]; delete opts[fieldName]; } }); opts.cell = cell; if (!isEmpty(titleObj)) { opts.title = titleObj; } const axes = [ xAxisObj, yAxisObj, leftYAxisObj, rightYAxisObj, angleAxisObj, radiusAxisObj, ]; if (axes.some((axis) => !isEmpty(axis))) { opts.axes = axes.filter((axis) => !isEmpty(axis)); } const { spec } = generateChart(options.chartType ?? chartType, opts); if (!spec) { return null; } if (output === "spec") { if (isValid(width)) { spec.width = width; } if (isValid(height)) { spec.height = height; } return { spec: spec, }; } return gentrateChartImageOrHtml(output, spec, { width: `${width ?? 500}px`, height: `${height ?? 500}px`, }); }