Skip to main content
Glama
hyunjae-labs

xlwings Excel MCP Server

by hyunjae-labs

copy_range

Copy Excel cell ranges between locations or worksheets to reorganize data, duplicate content, or prepare reports. Specify source and target ranges with optional sheet names for flexible data management.

Instructions

Copy a range of cells to another location. Args: sheet_name: Name of source worksheet source_start: Starting cell of source range source_end: Ending cell of source range target_start: Starting cell of target range session_id: Session ID from open_workbook (preferred) filepath: Path to Excel file (legacy, deprecated) target_sheet: Target worksheet (optional, uses source sheet if not provided) Note: Use session_id for better performance. filepath parameter is deprecated.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sheet_nameYes
source_startYes
source_endYes
target_startYes
session_idNo
filepathNo
target_sheetNo

Implementation Reference

  • Handler and registration for the 'copy_range' MCP tool. Dispatches to session-based or legacy filepath implementations in range_xlw.py.
    @mcp.tool() def copy_range( sheet_name: str, source_start: str, source_end: str, target_start: str, session_id: Optional[str] = None, filepath: Optional[str] = None, target_sheet: Optional[str] = None ) -> str: """ Copy a range of cells to another location. Args: sheet_name: Name of source worksheet source_start: Starting cell of source range source_end: Ending cell of source range target_start: Starting cell of target range session_id: Session ID from open_workbook (preferred) filepath: Path to Excel file (legacy, deprecated) target_sheet: Target worksheet (optional, uses source sheet if not provided) 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.range_xlw import copy_range_xlw_with_wb result = copy_range_xlw_with_wb( session.workbook, sheet_name, source_start, source_end, target_start, target_sheet or sheet_name # Use source sheet if target_sheet is None ) 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.range_xlw import copy_range_xlw result = copy_range_xlw( full_path, sheet_name, source_start, source_end, target_start, target_sheet or sheet_name # Use source sheet if target_sheet is None ) else: return ERROR_TEMPLATES['PARAMETER_MISSING'].format( param1='session_id', param2='filepath' ) return result.get("message", "Range copied successfully") if "error" not in result else f"Error: {result['error']}" except (ValidationError, SheetError) as e: return f"Error: {str(e)}" except Exception as e: logger.error(f"Error copying range: {e}") raise
  • Legacy (filepath-based) core implementation of range copying using xlwings. Opens workbook, copies range preserving formats/formulas, saves, and closes.
    def copy_range_xlw( filepath: str, sheet_name: str, source_start: str, source_end: str, target_start: str, target_sheet: Optional[str] = None ) -> Dict[str, Any]: """ Copy a range of cells to another location using xlwings. Args: filepath: Path to Excel file sheet_name: Name of source worksheet source_start: Top-left cell of source range source_end: Bottom-right cell of source range target_start: Top-left cell of target location target_sheet: Name of target worksheet (optional, defaults to source sheet) Returns: Dict with success message or error """ app = None wb = None # Initialize COM for thread safety (Windows) _com_initialize() try: # Use target_sheet if provided, otherwise use source sheet target_sheet = target_sheet or sheet_name logger.info(f"Copying range {source_start}:{source_end} to {target_start} in {target_sheet}") # 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 sheets exist sheet_names = [s.name for s in wb.sheets] if sheet_name not in sheet_names: return {"error": f"Source sheet '{sheet_name}' not found"} if target_sheet not in sheet_names: return {"error": f"Target sheet '{target_sheet}' not found"} source_sheet = wb.sheets[sheet_name] dest_sheet = wb.sheets[target_sheet] # Get source range source_range = source_sheet.range(f"{source_start}:{source_end}") # Copy to target location # xlwings copy method preserves formatting and formulas source_range.copy(destination=dest_sheet.range(target_start)) # Calculate target end cell rows = source_range.rows.count cols = source_range.columns.count target_end_row = dest_sheet.range(target_start).row + rows - 1 target_end_col = dest_sheet.range(target_start).column + cols - 1 target_end = dest_sheet.cells(target_end_row, target_end_col).address.replace("$", "") # Save the workbook wb.save() logger.info(f"βœ… Successfully copied range to {target_start}:{target_end}") return { "message": f"Successfully copied range {source_start}:{source_end} to {target_start}", "source_range": f"{source_start}:{source_end}", "target_range": f"{target_start}:{target_end}", "source_sheet": sheet_name, "target_sheet": target_sheet } except Exception as e: logger.error(f"❌ Error copying range: {str(e)}") return {"error": str(e)} finally: if wb: wb.close() if app: app.quit()
  • Session-based (with existing workbook) core implementation of range copying using xlwings. Copies range preserving formats/formulas and saves.
    def copy_range_xlw_with_wb( wb, sheet_name: str, source_start: str, source_end: str, target_start: str, target_sheet: Optional[str] = None ) -> Dict[str, Any]: """ Session-based range copying using existing workbook object. Args: wb: Workbook object from session sheet_name: Name of source worksheet source_start: Top-left cell of source range source_end: Bottom-right cell of source range target_start: Top-left cell of target location target_sheet: Name of target worksheet (optional, defaults to source sheet) Returns: Dict with success message or error """ try: # Use target_sheet if provided, otherwise use source sheet target_sheet = target_sheet or sheet_name logger.info(f"πŸ“‹ Copying range {source_start}:{source_end} to {target_start} in {target_sheet}") # Check if sheets exist sheet_names = [s.name for s in wb.sheets] if sheet_name not in sheet_names: return {"error": f"Source sheet '{sheet_name}' not found"} if target_sheet not in sheet_names: return {"error": f"Target sheet '{target_sheet}' not found"} source_sheet = wb.sheets[sheet_name] dest_sheet = wb.sheets[target_sheet] # Get source range source_range = source_sheet.range(f"{source_start}:{source_end}") # Copy to target location # xlwings copy method preserves formatting and formulas source_range.copy(destination=dest_sheet.range(target_start)) # Calculate target end cell rows = source_range.rows.count cols = source_range.columns.count target_end_row = dest_sheet.range(target_start).row + rows - 1 target_end_col = dest_sheet.range(target_start).column + cols - 1 target_end = dest_sheet.cells(target_end_row, target_end_col).address.replace("$", "") # Save the workbook wb.save() logger.info(f"βœ… Successfully copied range to {target_start}:{target_end}") return { "message": f"Successfully copied range {source_start}:{source_end} to {target_start}", "source_range": f"{source_start}:{source_end}", "target_range": f"{target_start}:{target_end}", "source_sheet": sheet_name, "target_sheet": target_sheet } except Exception as e: logger.error(f"❌ Error copying range: {str(e)}") return {"error": str(e)}

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