Skip to main content
Glama
hyunjae-labs

xlwings Excel MCP Server

insert_columns

Insert columns into Excel worksheets to reorganize data structure. Specify sheet name, starting column position, and number of columns to add for spreadsheet modification.

Instructions

Insert one or more columns starting at the specified column.

Args:
    sheet_name: Name of worksheet
    start_col: Column number to start inserting at
    session_id: Session ID from open_workbook (preferred)
    filepath: Path to Excel file (legacy, deprecated)
    count: Number of columns to insert
    
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 'insert_columns' tool using @mcp.tool() decorator. Dispatches to session-based or legacy filepath-based handlers.
    @mcp.tool()
    def insert_columns(
        sheet_name: str,
        start_col: int,
        session_id: Optional[str] = None,
        filepath: Optional[str] = None,
        count: int = 1
    ) -> str:
        """
        Insert one or more columns starting at the specified column.
        
        Args:
            sheet_name: Name of worksheet
            start_col: Column number to start inserting at
            session_id: Session ID from open_workbook (preferred)
            filepath: Path to Excel file (legacy, deprecated)
            count: Number of columns to insert
            
        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 insert_columns_xlw_with_wb
                    result = insert_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 insert_columns_xlw
                result = insert_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 inserting columns: {e}")
            raise
  • Stateless handler implementation for inserting columns using xlwings with filepath. Handles file opening, sheet access, column insertion via COM API, and cleanup.
    def insert_columns_xlw(
        filepath: str,
        sheet_name: str,
        start_col: int,
        count: int = 1
    ) -> Dict[str, Any]:
        """
        Insert 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 insertion (1-based)
            count: Number of columns to insert
            
        Returns:
            Dict with success message or error
        """
        app = None
        wb = None
    
        # Initialize COM for thread safety (Windows)
        _com_initialize()
    
        try:
            logger.info(f"Inserting {count} columns at 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)
            
            # Insert columns using xlwings
            target_col = sheet.range(f"{col_letter}:{col_letter}")
            
            # Insert columns - use COM API for better control
            for _ in range(count):
                target_col.api.Insert()
            
            # Save the workbook
            wb.save()
            
            logger.info(f"✅ Successfully inserted {count} columns at column {col_letter}")
            return {
                "message": f"Successfully inserted {count} columns at column {col_letter}",
                "sheet": sheet_name,
                "start_col": start_col,
                "count": count
            }
            
        except Exception as e:
            logger.error(f"Error inserting columns: {e}")
            return {"error": str(e)}
            
        finally:
            if wb:
                wb.close()
            if app:
                app.quit()
  • Stateful (session-based) handler implementation for inserting columns using an existing workbook object from session. Performs column insertion via COM API.
    def insert_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 insertion (1-based)
            count: Number of columns to insert
            
        Returns:
            Dict with success message or error
        """
        try:
            logger.info(f"📊 Inserting {count} columns at 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)
            
            # Insert columns using xlwings
            target_col = sheet.range(f"{col_letter}:{col_letter}")
            
            # Insert columns - use COM API for better control
            for _ in range(count):
                target_col.api.Insert()
            
            # Save the workbook
            wb.save()
            
            logger.info(f"✅ Successfully inserted {count} columns at column {col_letter}")
            return {
                "message": f"Successfully inserted {count} columns at column {col_letter}",
                "sheet": sheet_name,
                "start_col": start_col,
                "count": count
            }
            
        except Exception as e:
            logger.error(f"Error inserting columns: {e}")
            return {"error": str(e)}
Behavior3/5

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

With no annotations provided, the description carries the full burden. It mentions performance implications ('Use session_id for better performance') and deprecation warnings ('filepath parameter is deprecated'), which adds useful context. However, it doesn't disclose critical behavioral traits like whether this operation modifies existing data (e.g., shifting cells), requires specific permissions, or has side effects on formulas/charts.

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

Conciseness5/5

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

The description is perfectly structured: a clear purpose statement followed by an 'Args:' section with parameter explanations and a 'Note:' with important guidance. Every sentence earns its place, with no wasted words or redundancy.

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

Completeness4/5

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

Given the tool's complexity (mutation operation with 5 parameters), no annotations, but with an output schema (which handles return values), the description does well by documenting all parameters and providing usage guidance. However, it could be more complete by mentioning behavioral aspects like data shifting or effects on other worksheet elements.

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

Parameters5/5

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

The schema description coverage is 0%, so the description must compensate fully. It does this excellently by listing all 5 parameters with brief explanations ('sheet_name: Name of worksheet', 'start_col: Column number to start inserting at', etc.) and providing important usage notes about session_id vs filepath and the default count value.

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

Purpose4/5

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

The description clearly states the action ('Insert one or more columns') and specifies the resource ('starting at the specified column'), making the purpose immediately understandable. However, it doesn't explicitly differentiate from sibling tools like 'insert_rows' or 'delete_sheet_columns', which would require a 5.

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

Usage Guidelines4/5

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

The description provides clear guidance on parameter usage ('Use session_id for better performance. filepath parameter is deprecated'), which helps the agent choose between alternatives. However, it doesn't specify when to use this tool versus other column-related tools like 'delete_sheet_columns' or 'copy_range', missing explicit sibling differentiation.

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

Install Server

Other Tools

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/hyunjae-labs/xlwings-mcp-server'

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