From 4d5b53379aa159aba31e8c51ab28221423fe7147 Mon Sep 17 00:00:00 2001 From: Haris Musa Date: Tue, 10 Jun 2025 22:40:59 +0500 Subject: [PATCH] Feat: Add create_excel_table function for native Excel table support. Closes #34 --- TOOLS.md | 23 ++++++++++++++ src/excel_mcp/server.py | 26 ++++++++++++++++ src/excel_mcp/tables.py | 69 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 src/excel_mcp/tables.py diff --git a/TOOLS.md b/TOOLS.md index 8927807..f3c8be4 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -233,6 +233,29 @@ create_pivot_table( - `agg_func`: Aggregation function (sum, count, average, max, min) - Returns: Success message +## Table Operations + +### create_table + +Creates a native Excel table from a specified range of data. + +```python +create_table( + filepath: str, + sheet_name: str, + data_range: str, + table_name: str = None, + table_style: str = "TableStyleMedium9" +) -> str +``` + +- `filepath`: Path to the Excel file. +- `sheet_name`: Name of the worksheet. +- `data_range`: The cell range for the table (e.g., "A1:D5"). +- `table_name`: Optional unique name for the table. +- `table_style`: Optional visual style for the table. +- Returns: Success message. + ## Worksheet Operations ### copy_worksheet diff --git a/src/excel_mcp/server.py b/src/excel_mcp/server.py index 7af345e..65207c9 100644 --- a/src/excel_mcp/server.py +++ b/src/excel_mcp/server.py @@ -25,6 +25,7 @@ from excel_mcp.chart import create_chart_in_sheet as create_chart_impl from excel_mcp.workbook import get_workbook_info from excel_mcp.data import write_data from excel_mcp.pivot import create_pivot_table as create_pivot_table_impl +from excel_mcp.tables import create_excel_table as create_table_impl from excel_mcp.sheet import ( copy_sheet, delete_sheet, @@ -350,6 +351,31 @@ def create_pivot_table( logger.error(f"Error creating pivot table: {e}") raise +@mcp.tool() +def create_table( + filepath: str, + sheet_name: str, + data_range: str, + table_name: str = None, + table_style: str = "TableStyleMedium9" +) -> str: + """Creates a native Excel table from a specified range of data.""" + try: + full_path = get_excel_path(filepath) + result = create_table_impl( + filepath=full_path, + sheet_name=sheet_name, + data_range=data_range, + table_name=table_name, + table_style=table_style + ) + return result["message"] + except DataError as e: + return f"Error: {str(e)}" + except Exception as e: + logger.error(f"Error creating table: {e}") + raise + @mcp.tool() def copy_worksheet( filepath: str, diff --git a/src/excel_mcp/tables.py b/src/excel_mcp/tables.py new file mode 100644 index 0000000..ed5168d --- /dev/null +++ b/src/excel_mcp/tables.py @@ -0,0 +1,69 @@ +import uuid +import logging + +from openpyxl import load_workbook +from openpyxl.worksheet.table import Table, TableStyleInfo +from .exceptions import DataError + +logger = logging.getLogger(__name__) + +def create_excel_table( + filepath: str, + sheet_name: str, + data_range: str, + table_name: str | None = None, + table_style: str = "TableStyleMedium9" +) -> dict: + """Creates a native Excel table for the given data range. + + Args: + filepath: Path to the Excel file. + sheet_name: Name of the worksheet. + data_range: The cell range for the table (e.g., "A1:D5"). + table_name: A unique name for the table. If not provided, a unique name is generated. + table_style: The visual style to apply to the table. + + Returns: + A dictionary with a success message and table details. + """ + try: + wb = load_workbook(filepath) + if sheet_name not in wb.sheetnames: + raise DataError(f"Sheet '{sheet_name}' not found.") + + ws = wb[sheet_name] + + # If no table name is provided, generate a unique one + if not table_name: + table_name = f"Table_{uuid.uuid4().hex[:8]}" + + # Check if table name already exists + if table_name in ws.parent.defined_names: + raise DataError(f"Table name '{table_name}' already exists.") + + # Create the table + table = Table(displayName=table_name, ref=data_range) + + # Apply style + style = TableStyleInfo( + name=table_style, + showFirstColumn=False, + showLastColumn=False, + showRowStripes=True, + showColumnStripes=False + ) + table.tableStyleInfo = style + + ws.add_table(table) + + wb.save(filepath) + + return { + "message": f"Successfully created table '{table_name}' in sheet '{sheet_name}'.", + "table_name": table_name, + "range": data_range + } + + except Exception as e: + logger.error(f"Failed to create table: {e}") + raise DataError(str(e)) \ No newline at end of file