generate_cartesian_chart
Create Cartesian charts to visualize data trends, comparisons, and processes using line, area, bar, waterfall, ranking bar, or funnel chart types.
Instructions
Generates Cartesian charts: line (trends over time), area (cumulative totals), bar (category comparison), waterfall (incremental changes), ranking bar (ordered categories), and funnel (visualizes stages in a process or conversion rates).
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| output | No | Chart output type. Defaults to 'image'. | image |
| chartType | Yes | ||
| width | No | Chart width. Optional, defaults to 500. | |
| height | No | Chart height. Optional, defaults to 500. | |
| dataTable | Yes | Data array, e.g., [{ x: '2018', y: 99.9 }]. Cannot be empty. | |
| transpose | No | Set to true only when displaying a horizontal bar chart. | |
| xField | Yes | Dimension field. Must exist in the data. | |
| yField | Yes | Measure field. Must be numeric and exist in the data. | |
| colorField | No | Color grouping field. Should not duplicate the dimension field. | |
| timeField | No | Time field, such as year or month. The x field and time field must be different. this field is required in ranking_bar | |
| 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. | |
| xAxisType | No | X-axis type: categorical ('band') or continuous ('linear'). | |
| xAxisOrient | No | X-axis position in the chart. | |
| xAxisTitle | No | X-axis title. | |
| xAxisHasGrid | No | Show vertical grid lines for the X-axis. | |
| xAxisHasLabel | No | Show X-axis labels. | |
| xAxisHasTick | No | Show X-axis ticks. | |
| yAxisType | No | Y-axis type: categorical ('band') or continuous ('linear'). | |
| yAxisOrient | No | Y-axis position in the chart. | |
| yAxisTitle | No | Y-axis title. | |
| yAxisHasGrid | No | Show horizontal grid lines for the Y-axis. | |
| yAxisHasLabel | No | Show Y-axis labels. | |
| yAxisHasTick | No | Show Y-axis ticks. | |
| background | No | Chart background color (hex). Optional, defaults to white. | |
| colors | No | Color palette for chart elements. | |
| stackOrPercent | No | Stacking mode: 'stack' for stacked data, 'percent' for percentage stacking. Requires 'color' field. |
Implementation Reference
- src/server.ts:43-125 (handler)Central MCP tool call handler that dispatches to the appropriate chart generator by matching tool name to chart type ('cartesian' for generate_cartesian_chart), validates input with the tool's schema, calls generateChartByType, and formats the response.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/utils/generateChart.ts:42-202 (helper)Generates VChart specification and renders it to image, HTML, or spec JSON based on chartType ('cartesian') and input options, used by all chart tool handlers.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`, }); }
- src/charts/cartesian.ts:31-79 (schema)Zod schema defining input parameters for generate_cartesian_chart, including dataTable, fields (xField, yField, colorField), axes configurations, theme, title, and chartType for cartesian charts.const schema = z.object({ output: ChartOutputSchema, chartType: z.enum([ 'area', 'line', 'bar', 'waterfall', 'ranking_bar', 'funnel', ]), width: WidthSchema, height: HeightSchema, dataTable: z .array(z.record(z.string(), z.any())) .min(1, { message: 'Data is required.' }) .describe("Data array, e.g., [{ x: '2018', y: 99.9 }]. Cannot be empty."), transpose: z .boolean() .optional() .describe('Set to true only when displaying a horizontal bar chart.'), xField: XFieldSchema, yField: YFieldSchema, colorField: ColorFieldSchema, timeField: z .string() .optional() .describe( 'Time field, such as year or month. The x field and time field must be different. this field is required in ranking_bar' ), chartTheme: ThemeSchema, title: TitleTextSchema, subTitle: TitleSubTextSchema, titleOrient: TitleOrientSchema, xAxisType: XAxisTypeSchema, xAxisOrient: XAxisOrientSchema, xAxisTitle: XAxisTitleSchema, xAxisHasGrid: XAxisHasGridSchema, xAxisHasLabel: XAxisHasLabelSchema, xAxisHasTick: XAxisHasTickSchema, yAxisType: YAxisTypeSchema, yAxisOrient: YAxisOrientSchema, yAxisTitle: YAxisTitleSchema, yAxisHasGrid: YAxisHasGridSchema, yAxisHasLabel: YAxisHasLabelSchema, yAxisHasTick: YAxisHasTickSchema, background: BackgroundSchema, colors: ColorsSchema, stackOrPercent: StackSchema, });
- src/server.ts:34-38 (registration)Registers and lists all chart tools (including generate_cartesian_chart) by dynamically exporting tool objects from imported Charts modules.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: Object.values(Charts).map(chart => (chart as any).tool), }; });
- src/charts/cartesian.ts:81-91 (registration)Defines the tool metadata (name, description, inputSchema) and exports it alongside the schema for registration in the MCP server.const tool = { name: 'generate_cartesian_chart', description: 'Generates Cartesian charts: line (trends over time), area (cumulative totals), bar (category comparison), waterfall (incremental changes), ranking bar (ordered categories), and funnel (visualizes stages in a process or conversion rates).', inputSchema: convertZodToJsonSchema(schema), }; export const cartesian = { schema, tool, };