Skip to main content
Glama
hyunjae-labs

xlwings Excel MCP Server

insert_rows

Add rows to Excel worksheets at specified positions to organize data and create space for new entries in workbooks managed by the xlwings Excel MCP Server.

Instructions

Insert one or more rows starting at the specified row.

Args:
    sheet_name: Name of worksheet
    start_row: Row number to start inserting at
    session_id: Session ID from open_workbook (preferred)
    filepath: Path to Excel file (legacy, deprecated)
    count: Number of rows to insert
    
Note: Use session_id for better performance. filepath parameter is deprecated.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sheet_nameYes
start_rowYes
session_idNo
filepathNo
countNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Registration of the 'insert_rows' tool using @mcp.tool(). This wrapper handles session-based and legacy filepath modes by calling the appropriate implementation functions.
    def insert_rows(
        sheet_name: str,
        start_row: int,
        session_id: Optional[str] = None,
        filepath: Optional[str] = None,
        count: int = 1
    ) -> str:
        """
        Insert one or more rows starting at the specified row.
        
        Args:
            sheet_name: Name of worksheet
            start_row: Row number to start inserting at
            session_id: Session ID from open_workbook (preferred)
            filepath: Path to Excel file (legacy, deprecated)
            count: Number of rows 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_rows_xlw_with_wb
                    result = insert_rows_xlw_with_wb(session.workbook, sheet_name, start_row, 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_rows_xlw
                result = insert_rows_xlw(full_path, sheet_name, start_row, 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 rows: {e}")
            raise
  • Core handler function that executes the row insertion logic using xlwings for filepath-based operations. Opens workbook, inserts rows via COM API, saves, and cleans up.
    def insert_rows_xlw(
        filepath: str,
        sheet_name: str,
        start_row: int,
        count: int = 1
    ) -> Dict[str, Any]:
        """
        Insert one or more rows in Excel using xlwings.
        
        Args:
            filepath: Path to Excel file
            sheet_name: Name of worksheet
            start_row: Row number to start insertion (1-based)
            count: Number of rows 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} rows at row {start_row} 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]
            
            # Insert rows using xlwings
            # Get the range for the row to insert at
            target_row = sheet.range(f"{start_row}:{start_row}")
            
            # Insert rows - use COM API for better control
            for _ in range(count):
                target_row.api.Insert()
            
            # Save the workbook
            wb.save()
            
            logger.info(f"✅ Successfully inserted {count} rows at row {start_row}")
            return {
                "message": f"Successfully inserted {count} rows at row {start_row}",
                "sheet": sheet_name,
                "start_row": start_row,
                "count": count
            }
            
        except Exception as e:
            logger.error(f"Error inserting rows: {e}")
            return {"error": str(e)}
            
        finally:
            if wb:
                wb.close()
            if app:
                app.quit()
  • Helper function for session-based row insertion using pre-opened workbook object. Used by the main tool wrapper when session_id is provided.
    def insert_rows_xlw_with_wb(
        wb,
        sheet_name: str,
        start_row: 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_row: Row number to start insertion (1-based)
            count: Number of rows to insert
            
        Returns:
            Dict with success message or error
        """
        try:
            logger.info(f"📊 Inserting {count} rows at row {start_row} 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]
            
            # Insert rows using xlwings
            # Get the range for the row to insert at
            target_row = sheet.range(f"{start_row}:{start_row}")
            
            # Insert rows - use COM API for better control
            for _ in range(count):
                target_row.api.Insert()
            
            # Save the workbook
            wb.save()
            
            logger.info(f"✅ Successfully inserted {count} rows at row {start_row}")
            return {
                "message": f"Successfully inserted {count} rows at row {start_row}",
                "sheet": sheet_name,
                "start_row": start_row,
                "count": count
            }
            
        except Exception as e:
            logger.error(f"Error inserting rows: {e}")
            return {"error": str(e)}
Behavior2/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions performance implications and deprecation warnings, which is helpful. However, it doesn't describe what happens to existing data (e.g., whether rows shift down), whether this operation requires specific permissions, what the output looks like, or potential side effects. For a mutation tool with zero annotation coverage, 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 well-structured with a clear purpose statement followed by parameter documentation. Every sentence earns its place, with no redundant information. It could be slightly more front-loaded by moving the performance/deprecation notes earlier, but overall it's efficiently organized and appropriately sized for a 5-parameter tool.

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

Completeness3/5

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

Given that this is a mutation tool with no annotations but with an output schema (which handles return values), the description covers the core functionality and parameters adequately. However, it lacks important behavioral context about what the insertion actually does to the worksheet structure and existing data. The presence of an output schema means the description doesn't need to explain return values, but it should still address the mutation's effects more explicitly.

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 description adds substantial value beyond the input schema, which has 0% description coverage. It provides clear semantics for all 5 parameters: 'sheet_name: Name of worksheet', 'start_row: Row number to start inserting at', 'session_id: Session ID from open_workbook (preferred)', 'filepath: Path to Excel file (legacy, deprecated)', and 'count: Number of rows to insert'. The performance guidance and deprecation warning for filepath are particularly valuable additions not present in the schema.

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 rows') and resource ('starting at the specified row'), making the purpose unambiguous. It distinguishes from siblings like 'insert_columns' by specifying row insertion rather than column insertion. However, it doesn't explicitly differentiate from all possible row-related operations like 'delete_sheet_rows' beyond the obvious verb difference.

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 context about parameter usage with 'Use session_id for better performance' and 'filepath parameter is deprecated', which helps guide parameter selection. However, it doesn't explicitly state when to use this tool versus alternatives like 'write_data_to_excel' or 'copy_range' for similar data manipulation tasks, nor does it mention prerequisites like needing an open workbook session.

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