Skip to main content
Glama

create_duplicate_sheet_tool

Create a copy of an existing sheet in Google Sheets to preserve original data, use as a template, or work with multiple versions.

Instructions

Create a duplicate of an existing sheet.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
spreadsheet_nameYesThe name of the Google Spreadsheet
source_sheet_nameYesName of the sheet to duplicate
new_sheet_nameNoName for the duplicated sheet (optional, will auto-generate if not provided)
insert_positionNoPosition to insert the duplicated sheet (1-based index, optional - will insert at end if not specified)

Implementation Reference

  • Main handler implementing the tool logic: input validation, spreadsheet/sheet ID resolution using helpers, duplicate name check, API duplication call, and JSON response formatting.
    def create_duplicate_sheet_handler(
        drive_service,
        sheets_service,
        spreadsheet_name: str,
        source_sheet_name: str,
        new_sheet_name: str = None,
        insert_position: int = None
    ) -> str:
        """
        Handler to create a duplicate of an existing sheet.
        
        Args:
            drive_service: Google Drive service
            sheets_service: Google Sheets service
            spreadsheet_name: Name of the spreadsheet
            source_sheet_name: Name of the sheet to duplicate
            new_sheet_name: Name for the duplicated sheet (optional)
            insert_position: Position to insert the duplicated sheet (optional)
        
        Returns:
            JSON string with success status and duplicate sheet info
        """
        try:
            # Validate inputs
            if not source_sheet_name or not isinstance(source_sheet_name, str):
                return compact_json_response({
                    "success": False,
                    "message": "Source sheet name is required and must be a string."
                })
            
            # Validate new sheet name if provided
            if new_sheet_name:
                validation = validate_sheet_name(new_sheet_name)
                if not validation["valid"]:
                    return compact_json_response({
                        "success": False,
                        "message": f"Invalid new sheet name: {validation['error']}"
                    })
                new_sheet_name = validation["cleaned_name"]
            
            # Validate insert position if provided
            if insert_position is not None:
                if not isinstance(insert_position, int) or insert_position < 0:
                    return compact_json_response({
                        "success": False,
                        "message": "Insert position must be a non-negative integer."
                    })
            
            # Get spreadsheet ID
            spreadsheet_id = get_spreadsheet_id_by_name(drive_service, spreadsheet_name)
            if not spreadsheet_id:
                return compact_json_response({
                    "success": False,
                    "message": f"Spreadsheet '{spreadsheet_name}' not found."
                })
            
            # Get source sheet ID
            sheet_ids = get_sheet_ids_by_names(sheets_service, spreadsheet_id, [source_sheet_name])
            source_sheet_id = sheet_ids.get(source_sheet_name)
            if source_sheet_id is None:
                return compact_json_response({
                    "success": False,
                    "message": f"Source sheet '{source_sheet_name}' not found in spreadsheet '{spreadsheet_name}'."
                })
            
            # Check for duplicate name if new name is provided
            if new_sheet_name:
                duplicate_check = check_duplicate_sheet_name_for_duplicate(sheets_service, spreadsheet_id, new_sheet_name)
                if duplicate_check["has_duplicates"]:
                    return compact_json_response({
                        "success": False,
                        "message": duplicate_check["error"]
                    })
            
            # Create duplicate sheet
            try:
                result = create_duplicate_sheet(sheets_service, spreadsheet_id, source_sheet_id, new_sheet_name, insert_position)
                
                if result["success"]:
                    # Prepare response
                    response_data = {
                        "success": True,
                        "spreadsheet_name": spreadsheet_name,
                        "source_sheet_name": source_sheet_name,
                        "new_sheet_name": result["title"],
                        "new_sheet_index": result["index"],
                        "insert_position": insert_position,
                        "message": f"Successfully created duplicate of sheet '{source_sheet_name}' as '{result['title']}' in '{spreadsheet_name}'",
                        "sheet_details": {
                            "sheet_id": result["sheet_id"],
                            "title": result["title"],
                            "index": result["index"]
                        }
                    }
                    
                    return compact_json_response(response_data)
                else:
                    return compact_json_response({
                        "success": False,
                        "message": result["error"]
                    })
                    
            except HttpError as e:
                error_details = e.error_details if hasattr(e, 'error_details') else str(e)
                return compact_json_response({
                    "success": False,
                    "message": f"Failed to create duplicate sheet: {error_details}",
                    "error_code": e.resp.status if hasattr(e, 'resp') else None
                })
            
        except Exception as e:
            return compact_json_response({
                "success": False,
                "message": f"Unexpected error: {str(e)}",
                "error_type": type(e).__name__
            })
  • Registers 'create_duplicate_sheet_tool' as an MCP tool with FastMCP, defines input schema using Pydantic Field descriptions, and delegates execution to the handler function.
    @mcp.tool()
    def create_duplicate_sheet_tool(
        spreadsheet_name: str = Field(..., description="The name of the Google Spreadsheet"),
        source_sheet_name: str = Field(..., description="Name of the sheet to duplicate"),
        new_sheet_name: str = Field(default="", description="Name for the duplicated sheet (optional, will auto-generate if not provided)"),
        insert_position: int = Field(default=None, description="Position to insert the duplicated sheet (1-based index, optional - will insert at end if not specified)")
    ) -> str:
        """
        Create a duplicate of an existing sheet.
        """
        sheets_service, drive_service = _get_google_services()
        return create_duplicate_sheet_handler(drive_service, sheets_service, spreadsheet_name, source_sheet_name, new_sheet_name, insert_position)
  • Core helper function that executes the Google Sheets API batchUpdate request to duplicate the specified source sheet.
    def create_duplicate_sheet(sheets_service, spreadsheet_id: str, source_sheet_id: int, new_sheet_name: str = None, insert_position: int = None) -> Dict[str, Any]:
        """Create a duplicate sheet within the same spreadsheet."""
        try:
            # Prepare the duplicate sheet request
            request = {
                "duplicateSheet": {
                    "sourceSheetId": source_sheet_id,
                    "insertSheetIndex": insert_position,  # Will be inserted at specified position or at the end if None
                    "newSheetId": None,  # Let Google assign a new ID
                    "newSheetName": new_sheet_name
                }
            }
            
            response = sheets_service.spreadsheets().batchUpdate(
                spreadsheetId=spreadsheet_id,
                body={"requests": [request]}
            ).execute()
            
            # Extract the created sheet information
            reply = response.get("replies", [{}])[0]
            if "duplicateSheet" in reply:
                sheet_props = reply["duplicateSheet"]["properties"]
                return {
                    "success": True,
                    "sheet_id": sheet_props["sheetId"],
                    "title": sheet_props["title"],
                    "index": sheet_props["index"]
                }
            else:
                return {
                    "success": False,
                    "error": "Failed to create duplicate sheet"
                }
                
        except HttpError as e:
            return {
                "success": False,
                "error": f"Failed to create duplicate sheet: {str(e)}"
            }
  • Helper function to validate the new sheet name against Google Sheets naming rules (length, invalid chars, reserved names).
    def validate_sheet_name(name: str) -> Dict[str, Any]:
        """
        Validate a sheet name according to Google Sheets rules.
        
        Args:
            name: Sheet name to validate
        
        Returns:
            Dictionary with validation result
        """
        if not name or name.strip() == "":
            return {"valid": False, "error": "Sheet name cannot be empty"}
        
        # Remove leading/trailing whitespace
        name = name.strip()
        
        # Check length (Google Sheets limit is 100 characters)
        if len(name) > 100:
            return {"valid": False, "error": f"Sheet name '{name}' is too long (max 100 characters)"}
        
        # Check for invalid characters
        # Google Sheets doesn't allow: [ ] * ? / \
        invalid_chars = ['[', ']', '*', '?', '/', '\\']
        for char in invalid_chars:
            if char in name:
                return {"valid": False, "error": f"Sheet name '{name}' contains invalid character '{char}'"}
        
        # Check for reserved names (Google Sheets has some reserved names)
        reserved_names = ['Sheet1', 'Sheet2', 'Sheet3']  # Common default names
        if name in reserved_names:
            return {"valid": False, "error": f"Sheet name '{name}' is a reserved name"}
        
        return {"valid": True, "cleaned_name": name}
  • Pydantic-based input schema definition for the tool parameters using Field with descriptions and defaults.
    def create_duplicate_sheet_tool(
        spreadsheet_name: str = Field(..., description="The name of the Google Spreadsheet"),
        source_sheet_name: str = Field(..., description="Name of the sheet to duplicate"),
        new_sheet_name: str = Field(default="", description="Name for the duplicated sheet (optional, will auto-generate if not provided)"),
        insert_position: int = Field(default=None, description="Position to insert the duplicated sheet (1-based index, optional - will insert at end if not specified)")
    ) -> str:

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/henilcalagiya/google-sheets-mcp'

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