Skip to main content
Glama

copy_range

Transfer a specified cell range within an Excel sheet or between sheets using source and target coordinates. Ideal for reorganizing or duplicating data efficiently.

Instructions

Copy a range of cells to another location.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filepathYes
sheet_nameYes
source_endYes
source_startYes
target_sheetNo
target_startYes

Implementation Reference

  • MCP tool handler for 'copy_range': handles input parameters, resolves file path, imports and calls the core copy_range_operation function from sheet.py, and returns the result message or error.
    @mcp.tool()
    def copy_range(
        filepath: str,
        sheet_name: str,
        source_start: str,
        source_end: str,
        target_start: str,
        target_sheet: Optional[str] = None
    ) -> str:
        """Copy a range of cells to another location."""
        try:
            full_path = get_excel_path(filepath)
            from excel_mcp.sheet import copy_range_operation
            result = copy_range_operation(
                full_path,
                sheet_name,
                source_start,
                source_end,
                target_start,
                target_sheet or sheet_name  # Use source sheet if target_sheet is None
            )
            return result["message"]
        except (ValidationError, SheetError) as e:
            return f"Error: {str(e)}"
        except Exception as e:
            logger.error(f"Error copying range: {e}")
            raise
  • Core helper function implementing the range copy logic: loads workbook, validates sheets and ranges, calculates offsets, copies cell values and styles cell-by-cell, and saves the workbook.
    def copy_range_operation(
        filepath: str,
        sheet_name: str,
        source_start: str,
        source_end: str,
        target_start: str,
        target_sheet: Optional[str] = None
    ) -> Dict:
        """Copy a range of cells to another location."""
        try:
            wb = load_workbook(filepath)
            if sheet_name not in wb.sheetnames:
                logger.error(f"Sheet '{sheet_name}' not found")
                raise ValidationError(f"Sheet '{sheet_name}' not found")
    
            source_ws = wb[sheet_name]
            target_ws = wb[target_sheet] if target_sheet else source_ws
    
            # Parse source range
            try:
                start_row, start_col, end_row, end_col = parse_cell_range(source_start, source_end)
            except ValueError as e:
                logger.error(f"Invalid source range: {e}")
                raise ValidationError(f"Invalid source range: {str(e)}")
    
            # Parse target starting point
            try:
                target_row = int(''.join(filter(str.isdigit, target_start)))
                target_col = column_index_from_string(''.join(filter(str.isalpha, target_start)))
            except ValueError as e:
                logger.error(f"Invalid target cell: {e}")
                raise ValidationError(f"Invalid target cell: {str(e)}")
    
            # Copy the range
            row_offset = target_row - start_row
            col_offset = target_col - start_col
    
            for i in range(start_row, end_row + 1):
                for j in range(start_col, end_col + 1):
                    source_cell = source_ws.cell(row=i, column=j)
                    target_cell = target_ws.cell(row=i + row_offset, column=j + col_offset)
                    target_cell.value = source_cell.value
                    if source_cell.has_style:
                        target_cell._style = copy(source_cell._style)
    
            wb.save(filepath)
            return {"message": f"Range copied successfully"}
    
        except (ValidationError, SheetError):
            raise
        except Exception as e:
            logger.error(f"Failed to copy range: {e}")
            raise SheetError(f"Failed to copy range: {str(e)}")
  • Supporting helper function for copying ranges between worksheets, including detailed style copying (font, border, fill, format, alignment). Not directly called by the tool but provides similar copy logic.
    def copy_range(
        source_ws: Worksheet,
        target_ws: Worksheet,
        source_range: str,
        target_start: Optional[str] = None,
    ) -> None:
        """Copy range from source worksheet to target worksheet."""
        # Parse source range
        if ':' in source_range:
            source_start, source_end = source_range.split(':')
        else:
            source_start = source_range
            source_end = None
            
        src_start_row, src_start_col, src_end_row, src_end_col = parse_cell_range(
            source_start, source_end
        )
    
        if src_end_row is None:
            src_end_row = src_start_row
            src_end_col = src_start_col
    
        if target_start is None:
            target_start = source_start
    
        tgt_start_row, tgt_start_col, _, _ = parse_cell_range(target_start)
    
        for i, row in enumerate(range(src_start_row, src_end_row + 1)):
            for j, col in enumerate(range(src_start_col, src_end_col + 1)):
                source_cell = source_ws.cell(row=row, column=col)
                target_cell = target_ws.cell(row=tgt_start_row + i, column=tgt_start_col + j)
    
                target_cell.value = source_cell.value
    
                try:
                    # Copy font
                    font_kwargs = {}
                    if hasattr(source_cell.font, 'name'):
                        font_kwargs['name'] = source_cell.font.name
                    if hasattr(source_cell.font, 'size'):
                        font_kwargs['size'] = source_cell.font.size
                    if hasattr(source_cell.font, 'bold'):
                        font_kwargs['bold'] = source_cell.font.bold
                    if hasattr(source_cell.font, 'italic'):
                        font_kwargs['italic'] = source_cell.font.italic
                    if hasattr(source_cell.font, 'color'):
                        font_color = None
                        if source_cell.font.color:
                            font_color = source_cell.font.color.rgb
                        font_kwargs['color'] = font_color
                    target_cell.font = Font(**font_kwargs)
    
                    # Copy border
                    new_border = Border()
                    for side in ['left', 'right', 'top', 'bottom']:
                        source_side = getattr(source_cell.border, side)
                        if source_side and source_side.style:
                            side_color = source_side.color.rgb if source_side.color else None
                            setattr(new_border, side, Side(
                                style=source_side.style,
                                color=side_color
                            ))
                    target_cell.border = new_border
    
                    # Copy fill
                    if hasattr(source_cell, 'fill'):
                        fill_kwargs = {'patternType': source_cell.fill.patternType}
                        if hasattr(source_cell.fill, 'fgColor') and source_cell.fill.fgColor:
                            fg_color = None
                            if hasattr(source_cell.fill.fgColor, 'rgb'):
                                fg_color = source_cell.fill.fgColor.rgb
                            fill_kwargs['fgColor'] = fg_color
                        if hasattr(source_cell.fill, 'bgColor') and source_cell.fill.bgColor:
                            bg_color = None
                            if hasattr(source_cell.fill.bgColor, 'rgb'):
                                bg_color = source_cell.fill.bgColor.rgb
                            fill_kwargs['bgColor'] = bg_color
                        target_cell.fill = PatternFill(**fill_kwargs)
    
                    # Copy number format and alignment
                    if source_cell.number_format:
                        target_cell.number_format = source_cell.number_format
                    if source_cell.alignment:
                        target_cell.alignment = source_cell.alignment
    
                except Exception:
                    continue
    
    def delete_range(worksheet: Worksheet, start_cell: str, end_cell: Optional[str] = None) -> None:

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/haris-musa/excel-mcp-server'

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