Skip to main content
Glama
K02D

MCP Tabular Data Analysis Server

by K02D

generate_chart

Create visualizations from tabular data by specifying chart type, data columns, and grouping options to analyze patterns and relationships in CSV or SQLite files.

Instructions

Generate a chart/visualization from tabular data. Returns chart as base64-encoded PNG for display. Args: file_path: Path to CSV or SQLite file chart_type: Type of chart - 'bar', 'line', 'scatter', 'histogram', 'pie', 'box' x_column: Column for X-axis (not needed for histogram/pie) y_column: Column for Y-axis values group_by: Optional column for grouping/coloring title: Chart title (auto-generated if not provided) output_format: 'base64' (default) or 'file' (saves to data/charts/) Returns: Dictionary containing chart data as base64 or file path

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
file_pathYes
chart_typeYes
x_columnNo
y_columnNo
group_byNo
titleNo
output_formatNobase64

Implementation Reference

  • The primary handler function for the 'generate_chart' MCP tool. It is decorated with @mcp.tool() which registers it with the FastMCP server. The function loads data, validates inputs, generates matplotlib charts of various types (bar, line, scatter, histogram, pie, box), and returns either a base64-encoded PNG image or saves it to a file.
    @mcp.tool() def generate_chart( file_path: str, chart_type: str, x_column: str | None = None, y_column: str | None = None, group_by: str | None = None, title: str | None = None, output_format: str = "base64", ) -> dict[str, Any]: """ Generate a chart/visualization from tabular data. Returns chart as base64-encoded PNG for display. Args: file_path: Path to CSV or SQLite file chart_type: Type of chart - 'bar', 'line', 'scatter', 'histogram', 'pie', 'box' x_column: Column for X-axis (not needed for histogram/pie) y_column: Column for Y-axis values group_by: Optional column for grouping/coloring title: Chart title (auto-generated if not provided) output_format: 'base64' (default) or 'file' (saves to data/charts/) Returns: Dictionary containing chart data as base64 or file path """ df = _load_data(file_path) valid_types = ['bar', 'line', 'scatter', 'histogram', 'pie', 'box'] if chart_type not in valid_types: raise ValueError(f"Unknown chart_type: {chart_type}. Use: {valid_types}") # Set up the figure with a clean style plt.style.use('seaborn-v0_8-whitegrid') fig, ax = plt.subplots(figsize=(10, 6)) # Generate chart based on type if chart_type == 'histogram': if y_column is None: numeric_cols = _get_numeric_columns(df) if not numeric_cols: raise ValueError("No numeric columns found for histogram") y_column = numeric_cols[0] ax.hist(df[y_column].dropna(), bins=30, edgecolor='black', alpha=0.7, color='#4C72B0') ax.set_xlabel(y_column) ax.set_ylabel('Frequency') auto_title = f'Distribution of {y_column}' elif chart_type == 'pie': if x_column is None: cat_cols = df.select_dtypes(include=['object', 'category']).columns.tolist() if not cat_cols: raise ValueError("No categorical columns found for pie chart") x_column = cat_cols[0] value_counts = df[x_column].value_counts().head(10) colors = plt.cm.Set3(np.linspace(0, 1, len(value_counts))) ax.pie(value_counts.values, labels=value_counts.index, autopct='%1.1f%%', colors=colors) auto_title = f'Distribution of {x_column}' elif chart_type == 'box': if y_column is None: numeric_cols = _get_numeric_columns(df) if not numeric_cols: raise ValueError("No numeric columns found for box plot") y_column = numeric_cols[0] if group_by and group_by in df.columns: groups = df[group_by].unique()[:10] # Limit to 10 groups data = [df[df[group_by] == g][y_column].dropna() for g in groups] ax.boxplot(data, labels=groups) ax.set_xlabel(group_by) else: ax.boxplot(df[y_column].dropna()) ax.set_ylabel(y_column) auto_title = f'Box Plot of {y_column}' elif chart_type in ['bar', 'line', 'scatter']: if x_column is None or y_column is None: raise ValueError(f"Both x_column and y_column are required for {chart_type} chart") if x_column not in df.columns: raise ValueError(f"x_column '{x_column}' not found") if y_column not in df.columns: raise ValueError(f"y_column '{y_column}' not found") if group_by and group_by in df.columns: for name, group in df.groupby(group_by): if chart_type == 'bar': ax.bar(group[x_column].astype(str), group[y_column], label=str(name), alpha=0.7) elif chart_type == 'line': ax.plot(group[x_column], group[y_column], label=str(name), marker='o', markersize=4) else: # scatter ax.scatter(group[x_column], group[y_column], label=str(name), alpha=0.7) ax.legend(title=group_by, loc='best') else: if chart_type == 'bar': # For bar charts, aggregate if needed if df[x_column].dtype == 'object': agg = df.groupby(x_column)[y_column].mean() ax.bar(agg.index.astype(str), agg.values, color='#4C72B0', alpha=0.7) else: ax.bar(df[x_column].astype(str).head(50), df[y_column].head(50), color='#4C72B0', alpha=0.7) elif chart_type == 'line': ax.plot(df[x_column], df[y_column], marker='o', markersize=4, color='#4C72B0') else: # scatter ax.scatter(df[x_column], df[y_column], alpha=0.6, color='#4C72B0') ax.set_xlabel(x_column) ax.set_ylabel(y_column) auto_title = f'{y_column} by {x_column}' # Rotate x labels if needed if df[x_column].dtype == 'object' or chart_type == 'bar': plt.xticks(rotation=45, ha='right') # Set title ax.set_title(title or auto_title, fontsize=14, fontweight='bold') plt.tight_layout() # Save chart if output_format == 'file': charts_dir = _PROJECT_ROOT / 'data' / 'charts' charts_dir.mkdir(parents=True, exist_ok=True) timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') filename = f'{chart_type}_{timestamp}.png' filepath = charts_dir / filename plt.savefig(filepath, dpi=150, bbox_inches='tight') plt.close() return { "chart_type": chart_type, "file_path": str(filepath.relative_to(_PROJECT_ROOT)), "absolute_path": str(filepath), } else: # Return as base64 buffer = io.BytesIO() plt.savefig(buffer, format='png', dpi=150, bbox_inches='tight') plt.close() buffer.seek(0) image_base64 = base64.b64encode(buffer.getvalue()).decode('utf-8') return { "chart_type": chart_type, "format": "png", "encoding": "base64", "image_data": image_base64, "display_note": "Use this base64 string to display the image", }

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/K02D/mcp-tabular'

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