Skip to main content
Glama
hyunjae-labs

xlwings Excel MCP Server

by hyunjae-labs

delete_sheet_columns

Remove specified columns from an Excel worksheet to clean data or adjust spreadsheet structure. Specify sheet name, starting column, and number of columns to delete.

Instructions

Delete one or more columns starting at the specified column.

Args:
    sheet_name: Name of worksheet
    start_col: Column number to start deleting from
    session_id: Session ID from open_workbook (preferred)
    filepath: Path to Excel file (legacy, deprecated)
    count: Number of columns to delete
    
Note: Use session_id for better performance. filepath parameter is deprecated.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sheet_nameYes
start_colYes
session_idNo
filepathNo
countNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Registration of the delete_sheet_columns tool via @mcp.tool() decorator. Defines input schema through parameters and docstring. Dispatches to appropriate implementation based on session_id (preferred) or legacy filepath.
    @mcp.tool()
    def delete_sheet_columns(
        sheet_name: str,
        start_col: int,
        session_id: Optional[str] = None,
        filepath: Optional[str] = None,
        count: int = 1
    ) -> str:
        """
        Delete one or more columns starting at the specified column.
        
        Args:
            sheet_name: Name of worksheet
            start_col: Column number to start deleting from
            session_id: Session ID from open_workbook (preferred)
            filepath: Path to Excel file (legacy, deprecated)
            count: Number of columns to delete
            
        Note: Use session_id for better performance. filepath parameter is deprecated.
        """
        try:
            # Support both new (session_id) and old (filepath) API
            if session_id:
                # New API: use session
                session = SESSION_MANAGER.get_session(session_id)
                if not session:
                    return ERROR_TEMPLATES['SESSION_NOT_FOUND'].format(
                        session_id=session_id, 
                        ttl=10  # Default TTL is 10 minutes (600 seconds)
                    )
                
                with session.lock:
                    from xlwings_mcp.xlwings_impl.rows_cols_xlw import delete_sheet_columns_xlw_with_wb
                    result = delete_sheet_columns_xlw_with_wb(session.workbook, sheet_name, start_col, count)
            elif filepath:
                # Legacy API: backwards compatibility
                logger.warning("Using deprecated filepath parameter. Please use session_id instead.")
                full_path = get_excel_path(filepath)
                from xlwings_mcp.xlwings_impl.rows_cols_xlw import delete_sheet_columns_xlw
                result = delete_sheet_columns_xlw(full_path, sheet_name, start_col, count)
            else:
                return ERROR_TEMPLATES['PARAMETER_MISSING'].format(
                    param1='session_id',
                    param2='filepath'
                )
            
            if "error" in result:
                return f"Error: {result['error']}"
            return result["message"]
            
        except (ValidationError, SheetError) as e:
            return f"Error: {str(e)}"
        except Exception as e:
            logger.error(f"Error deleting columns: {e}")
            raise
  • Core handler implementation for filepath-based deletion of sheet columns using xlwings COM API. Handles file opening, sheet access, column letter conversion, deletion loop, saving, and cleanup.
    def delete_sheet_columns_xlw(
        filepath: str,
        sheet_name: str,
        start_col: int,
        count: int = 1
    ) -> Dict[str, Any]:
        """
        Delete one or more columns in Excel using xlwings.
        
        Args:
            filepath: Path to Excel file
            sheet_name: Name of worksheet
            start_col: Column number to start deletion (1-based)
            count: Number of columns to delete
            
        Returns:
            Dict with success message or error
        """
        app = None
        wb = None
    
        # Initialize COM for thread safety (Windows)
        _com_initialize()
    
        try:
            logger.info(f"Deleting {count} columns starting from column {start_col} in {sheet_name}")
            
            # Check if file exists
            if not os.path.exists(filepath):
                return {"error": f"File not found: {filepath}"}
            
            # Open Excel app and workbook
            app = xw.App(visible=False, add_book=False)
            wb = app.books.open(filepath)
            
            # Check if sheet exists
            sheet_names = [s.name for s in wb.sheets]
            if sheet_name not in sheet_names:
                return {"error": f"Sheet '{sheet_name}' not found"}
            
            sheet = wb.sheets[sheet_name]
            
            # Convert column number to letter
            def col_num_to_letter(n):
                string = ""
                while n > 0:
                    n, remainder = divmod(n - 1, 26)
                    string = chr(65 + remainder) + string
                return string
            
            col_letter = col_num_to_letter(start_col)
            
            # Delete columns using xlwings
            # Delete multiple times since we delete one at a time
            for i in range(count):
                col_to_delete = sheet.range(f"{col_letter}:{col_letter}")
                col_to_delete.api.Delete()
            
            # Save the workbook
            wb.save()
            
            logger.info(f"✅ Successfully deleted {count} columns starting from column {col_letter}")
            return {
                "message": f"Successfully deleted {count} columns starting from column {col_letter}",
                "sheet": sheet_name,
                "start_col": start_col,
                "count": count
            }
            
        except Exception as e:
            logger.error(f"Error deleting columns: {e}")
            return {"error": str(e)}
            
        finally:
            if wb:
                wb.close()
            if app:
                app.quit()
  • Session-based core handler for deleting sheet columns using existing workbook object. Used by the main tool when session_id is provided. Includes column letter conversion and deletion via xlwings API.
    def delete_sheet_columns_xlw_with_wb(
        wb,
        sheet_name: str,
        start_col: int,
        count: int = 1
    ) -> Dict[str, Any]:
        """Session-based version using existing workbook object.
        
        Args:
            wb: Workbook object from session
            sheet_name: Name of worksheet
            start_col: Column number to start deletion (1-based)
            count: Number of columns to delete
            
        Returns:
            Dict with success message or error
        """
        try:
            logger.info(f"🗑️ Deleting {count} columns starting from column {start_col} in {sheet_name}")
            
            # Check if sheet exists
            sheet_names = [s.name for s in wb.sheets]
            if sheet_name not in sheet_names:
                return {"error": f"Sheet '{sheet_name}' not found"}
            
            sheet = wb.sheets[sheet_name]
            
            # Convert column number to letter
            def col_num_to_letter(n):
                string = ""
                while n > 0:
                    n, remainder = divmod(n - 1, 26)
                    string = chr(65 + remainder) + string
                return string
            
            col_letter = col_num_to_letter(start_col)
            
            # Delete columns using xlwings
            # Delete multiple times since we delete one at a time
            for i in range(count):
                col_to_delete = sheet.range(f"{col_letter}:{col_letter}")
                col_to_delete.api.Delete()
            
            # Save the workbook
            wb.save()
            
            logger.info(f"✅ Successfully deleted {count} columns starting from column {col_letter}")
            return {
                "message": f"Successfully deleted {count} columns starting from column {col_letter}",
                "sheet": sheet_name,
                "start_col": start_col,
                "count": count
            }
            
        except Exception as e:
            logger.error(f"Error deleting columns: {e}")
            return {"error": str(e)}
  • Helper function to convert column number (1-based) to Excel column letter (A, B, ..., Z, AA, etc.). Used in both handler implementations.
    def col_num_to_letter(n):
        string = ""
        while n > 0:
            n, remainder = divmod(n - 1, 26)
            string = chr(65 + remainder) + string
        return string

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changed
    • addedInput schema / properties / filepath / anyOf
      Added value: +[
      +  {
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedInput schema / properties / filepath / default
      Added value: +null
    • removedInput schema / properties / filepath / type
      Removed value: -"string"
    • addedInput schema / properties / session_id
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Session Id"
      +}
    • changedInput schema / required
      Previous value: -[
      -  "filepath",
      -  "sheet_name",
      -  "start_col"
      -]New value: +[
      +  "sheet_name",
      +  "start_col"
      +]
  2. First observed

TDQS

B3.1/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must fully disclose behavioral traits. The description mentions deletion and deprecation of filepath, but does not specify the precise effect on the spreadsheet (e.g., columns shift left), whether the action is irreversible, performance implications, or required permissions. This leaves significant gaps in understanding the tool's behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, using a single paragraph with a bullet-like list to enumerates parameters. The purpose is front-loaded in the first sentence. Minor improvement could be to separate purpose and parameter details more clearly, but overall it is efficient and to the point.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having an output schema, the description does not mention return values or error conditions (e.g., invalid sheet name, out-of-range column). Given the tool is destructive and has 5 parameters with no annotations, the description should cover potential issues and expected outputs to be complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description adds meaningful context by listing parameters with brief explanations and noting that session_id is preferred over filepath. However, it does not clarify key details like whether start_col is 0-indexed or 1-indexed, or the exact effect of the count parameter on which columns are deleted.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Delete one or more columns') and the resource ('columns starting at the specified column'), making the purpose unambiguous. It effectively distinguishes this from sibling tools like delete_sheet_rows, which operate on rows instead.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description lacks guidance on when to use this tool versus other deletion tools (e.g., delete_range, delete_sheet_rows). It only hints at preferring session_id over filepath, but does not specify prerequisites, such as requiring an open workbook, or when alternatives would be more appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.