Skip to main content
Glama
hyunjae-labs

xlwings Excel MCP Server

by hyunjae-labs

validate_excel_range

Check if an Excel range exists and has correct formatting by specifying worksheet name and cell coordinates. Use session_id for optimal performance when validating workbook data ranges.

Instructions

Validate if a range exists and is properly formatted.

Args:
    sheet_name: Name of worksheet
    start_cell: Starting cell
    session_id: Session ID from open_workbook (preferred)
    filepath: Path to Excel file (legacy, deprecated)
    end_cell: Ending cell (optional)
    
Note: Use session_id for better performance. filepath parameter is deprecated.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sheet_nameYes
start_cellYes
session_idNo
filepathNo
end_cellNo

Implementation Reference

  • MCP tool registration for 'validate_excel_range', defines input schema via arguments and docstring, handles session and legacy filepath modes by delegating to xlwings handlers.
    @mcp.tool()
    def validate_excel_range(
        sheet_name: str,
        start_cell: str,
        session_id: Optional[str] = None,
        filepath: Optional[str] = None,
        end_cell: Optional[str] = None
    ) -> str:
        """
        Validate if a range exists and is properly formatted.
        
        Args:
            sheet_name: Name of worksheet
            start_cell: Starting cell
            session_id: Session ID from open_workbook (preferred)
            filepath: Path to Excel file (legacy, deprecated)
            end_cell: Ending cell (optional)
            
        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.validation_xlw import validate_excel_range_xlw_with_wb
                    result = validate_excel_range_xlw_with_wb(session.workbook, sheet_name, start_cell, end_cell)
            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.validation_xlw import validate_excel_range_xlw
                result = validate_excel_range_xlw(full_path, sheet_name, start_cell, end_cell)
            else:
                return ERROR_TEMPLATES['PARAMETER_MISSING'].format(
                    param1='session_id',
                    param2='filepath'
                )
            
            return result.get("message", "Range validation completed") if "error" not in result else f"Error: {result['error']}"
                
        except (ValidationError, DataError) as e:
            return f"Error: {str(e)}"
        except Exception as e:
            logger.error(f"Error validating range: {e}")
            raise
  • Primary handler for session-based range validation: checks sheet existence, validates range syntax and accessibility via xlwings, returns detailed range info including dimensions and data presence.
    def validate_excel_range_xlw_with_wb(
        wb,
        sheet_name: str,
        start_cell: str,
        end_cell: str = None
    ) -> Dict[str, Any]:
        """
        Validate if a range exists and is properly formatted using xlwings with workbook object.
        
        Args:
            wb: xlwings Workbook object
            sheet_name: Name of worksheet
            start_cell: Starting cell address
            end_cell: Ending cell address (optional)
            
        Returns:
            Dict containing validation result and range information
        """
        try:
            logger.info(f"๐Ÿ” Validating range {start_cell}:{end_cell or start_cell} 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", "valid": False}
            
            sheet = wb.sheets[sheet_name]
            
            # Validate the range
            try:
                if end_cell:
                    range_obj = sheet.range(f"{start_cell}:{end_cell}")
                else:
                    range_obj = sheet.range(start_cell)
                
                # Get range information
                range_info = {
                    "message": f"Range validation successful: {range_obj.address}",
                    "valid": True,
                    "range": range_obj.address,
                    "start_cell": start_cell,
                    "end_cell": end_cell,
                    "rows": range_obj.rows.count,
                    "columns": range_obj.columns.count,
                    "size": range_obj.rows.count * range_obj.columns.count,
                    "sheet": sheet_name,
                    "has_data": bool(range_obj.value is not None)
                }
                
                # Check if range has any data
                if range_obj.value:
                    if isinstance(range_obj.value, (list, tuple)):
                        non_empty_count = sum(1 for row in range_obj.value 
                                            if row and any(cell for cell in (row if isinstance(row, (list, tuple)) else [row]) if cell is not None))
                    else:
                        non_empty_count = 1 if range_obj.value is not None else 0
                    range_info["non_empty_cells"] = non_empty_count
                else:
                    range_info["non_empty_cells"] = 0
                
                logger.info(f"โœ… Range validation successful: {range_obj.address}")
                return range_info
                
            except Exception as range_error:
                return {
                    "error": f"Invalid range: {range_error}",
                    "valid": False,
                    "start_cell": start_cell,
                    "end_cell": end_cell,
                    "sheet": sheet_name
                }
            
        except Exception as e:
            logger.error(f"Error validating range: {e}")
            return {"error": str(e), "valid": False}
  • Legacy handler for filepath-based range validation: opens workbook, performs same validation logic, ensures cleanup.
    def validate_excel_range_xlw(
        filepath: str,
        sheet_name: str,
        start_cell: str,
        end_cell: str = None
    ) -> Dict[str, Any]:
        """
        Validate if a range exists and is properly formatted using xlwings.
        
        Args:
            filepath: Path to Excel file
            sheet_name: Name of worksheet
            start_cell: Starting cell address
            end_cell: Ending cell address (optional)
            
        Returns:
            Dict containing validation result and range information
        """
        app = None
        wb = None
    
        # Initialize COM for thread safety (Windows)
        _com_initialize()
    
        try:
            logger.info(f"Validating range {start_cell}:{end_cell or start_cell} in {sheet_name}")
            
            # Check if file exists
            if not os.path.exists(filepath):
                return {"error": f"File not found: {filepath}", "valid": False}
            
            # 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", "valid": False}
            
            sheet = wb.sheets[sheet_name]
            
            # Validate the range
            try:
                if end_cell:
                    range_obj = sheet.range(f"{start_cell}:{end_cell}")
                else:
                    range_obj = sheet.range(start_cell)
                
                # Get range information
                range_info = {
                    "message": f"Range validation successful: {range_obj.address}",
                    "valid": True,
                    "range": range_obj.address,
                    "start_cell": start_cell,
                    "end_cell": end_cell,
                    "rows": range_obj.rows.count,
                    "columns": range_obj.columns.count,
                    "size": range_obj.rows.count * range_obj.columns.count,
                    "sheet": sheet_name,
                    "has_data": bool(range_obj.value is not None)
                }
                
                # Check if range has any data
                if range_obj.value:
                    if isinstance(range_obj.value, (list, tuple)):
                        non_empty_count = sum(1 for row in range_obj.value 
                                            if row and any(cell for cell in (row if isinstance(row, (list, tuple)) else [row]) if cell is not None))
                    else:
                        non_empty_count = 1 if range_obj.value is not None else 0
                    range_info["non_empty_cells"] = non_empty_count
                else:
                    range_info["non_empty_cells"] = 0
                
                logger.info(f"โœ… Range validation successful: {range_obj.address}")
                return range_info
                
            except Exception as range_error:
                return {
                    "error": f"Invalid range: {range_error}",
                    "valid": False,
                    "start_cell": start_cell,
                    "end_cell": end_cell,
                    "sheet": sheet_name
                }
            
        except Exception as e:
            logger.error(f"Error validating range: {e}")
            return {"error": str(e), "valid": False}
            
        finally:
            if wb:
                wb.close()
            if app:
                app.quit()

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