generate_bar_chart
Create horizontal bar charts to visualize numerical comparisons across categories, supporting grouped or stacked data with customizable styles and themes.
Instructions
Generate a horizontal bar chart to show data for numerical comparisons among different categories, such as, comparing categorical data and for horizontal comparisons.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| data | Yes | Data for bar chart, such as, [{ category: '分类一', value: 10 }, { category: '分类二', value: 20 }], when grouping or stacking is needed for bar, the data should contain a `group` field, such as, when [{ category: '北京', value: 825, group: '油车' }, { category: '北京', value: 1000, group: '电车' }]. | |
| group | No | Whether grouping is enabled. When enabled, bar charts require a 'group' field in the data. When `group` is true, `stack` should be false. | |
| stack | No | Whether stacking is enabled. When enabled, bar charts require a 'group' field in the data. When `stack` is true, `group` should be false. | |
| style | No | Style configuration for the chart with a JSON object, optional. | |
| theme | No | Set the theme for the chart, optional, default is 'default'. | default |
| width | No | Set the width of chart, default is 600. | |
| height | No | Set the height of chart, default is 400. | |
| title | No | Set the title of chart. | |
| axisXTitle | No | Set the x-axis title of chart. | |
| axisYTitle | No | Set the y-axis title of chart. |
Implementation Reference
- src/utils/callTool.ts:44-111 (handler)Generic MCP tool handler that executes generate_bar_chart: maps to chartType='bar', validates args with Charts.bar.schema, generates chart URL via generateChartUrl, returns content with URL and spec metadata.export async function callTool(tool: string, args: object = {}) { logger.info(`Calling tool: ${tool}`); const chartType = CHART_TYPE_MAP[tool as keyof typeof CHART_TYPE_MAP]; if (!chartType) { logger.error(`Unknown tool: ${tool}`); throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${tool}.`); } try { // Validate input using Zod before sending to API. // Select the appropriate schema based on the chart type. const schema = Charts[chartType].schema; if (schema) { // Use safeParse instead of parse and try-catch. const result = z.object(schema).safeParse(args); if (!result.success) { logger.error(`Invalid parameters: ${result.error.message}`); throw new McpError( ErrorCode.InvalidParams, `Invalid parameters: ${result.error.message}`, ); } } const isMapChartTool = [ "generate_district_map", "generate_path_map", "generate_pin_map", ].includes(tool); if (isMapChartTool) { // For map charts, we use the generateMap function, and return the mcp result. const { metadata, ...result } = await generateMap(tool, args); return result; } const url = await generateChartUrl(chartType, args); logger.info(`Generated chart URL: ${url}`); return { content: [ { type: "text", text: url, }, ], _meta: { description: "This is the chart's spec and configuration, which can be renderred to corresponding chart by AntV GPT-Vis chart components.", spec: { type: chartType, ...args }, }, }; // biome-ignore lint/suspicious/noExplicitAny: <explanation> } catch (error: any) { logger.error( `Failed to generate chart: ${error.message || "Unknown error"}.`, ); if (error instanceof McpError) throw error; if (error instanceof ValidateError) throw new McpError(ErrorCode.InvalidParams, error.message); throw new McpError( ErrorCode.InternalError, `Failed to generate chart: ${error?.message || "Unknown error."}`, ); } }
- src/charts/bar.ts:23-72 (schema)Defines the input schema using Zod for generate_bar_chart (data array with category/value/group, options for group/stack/style/theme/size/titles) and the tool descriptor with name, description, inputSchema.const schema = { data: z .array(data) .describe( "Data for bar chart, such as, [{ category: '分类一', value: 10 }, { category: '分类二', value: 20 }], when grouping or stacking is needed for bar, the data should contain a `group` field, such as, when [{ category: '北京', value: 825, group: '油车' }, { category: '北京', value: 1000, group: '电车' }].", ) .nonempty({ message: "Bar chart data cannot be empty." }), group: z .boolean() .optional() .default(false) .describe( "Whether grouping is enabled. When enabled, bar charts require a 'group' field in the data. When `group` is true, `stack` should be false.", ), stack: z .boolean() .optional() .default(true) .describe( "Whether stacking is enabled. When enabled, bar charts require a 'group' field in the data. When `stack` is true, `group` should be false.", ), style: z .object({ backgroundColor: BackgroundColorSchema, palette: PaletteSchema, texture: TextureSchema, }) .optional() .describe( "Style configuration for the chart with a JSON object, optional.", ), theme: ThemeSchema, width: WidthSchema, height: HeightSchema, title: TitleSchema, axisXTitle: AxisXTitleSchema, axisYTitle: AxisYTitleSchema, }; // Bar chart tool descriptor const tool = { name: "generate_bar_chart", description: "Generate a horizontal bar chart to show data for numerical comparisons among different categories, such as, comparing categorical data and for horizontal comparisons.", inputSchema: zodToJsonSchema(schema), annotations: { title: "Generate Bar Chart", readOnlyHint: true, }, };
- src/server.ts:64-77 (registration)Dynamically registers all chart tools (including generate_bar_chart from Charts.bar.tool) for ListTools and CallTool requests on the MCP server, delegating execution to callTool.function setupToolHandlers(server: Server): void { logger.info("setting up tool handlers..."); server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: getEnabledTools().map((chart) => chart.tool), })); // biome-ignore lint/suspicious/noExplicitAny: <explanation> server.setRequestHandler(CallToolRequestSchema, async (request: any) => { logger.info("calling tool", request.params.name, request.params.arguments); return await callTool(request.params.name, request.params.arguments); }); logger.info("tool handlers set up"); }
- src/utils/generate.ts:12-39 (helper)Helper function called by callTool to generate the actual bar chart: POSTs {type: 'bar', ...args, source} to vis server API and returns the chart URL.export async function generateChartUrl( type: string, // biome-ignore lint/suspicious/noExplicitAny: <explanation> options: Record<string, any>, ): Promise<string> { const url = getVisRequestServer(); const response = await axios.post( url, { type, ...options, source: "mcp-server-chart", }, { headers: { "Content-Type": "application/json", }, }, ); const { success, errorMessage, resultObj } = response.data; if (!success) { throw new Error(errorMessage); } return resultObj; }