Skip to main content
Glama

update_dropdown_options_tool

Add or remove dropdown options in Google Sheets table columns to maintain data validation and improve data entry accuracy.

Instructions

Update dropdown options in a table column.

This tool can add or remove specific dropdown options from an existing column in a table.
For 'add' action: Adds new options to existing dropdown (preserves existing options).
For 'remove' action: Removes specific options from existing dropdown.

Args:
    spreadsheet_name: Name of the spreadsheet
    sheet_name: Name of the sheet containing the table
    table_name: Name of the table to update dropdown options in
    action: Action to perform - "add" or "remove"
    column_name: Name of the column to update dropdown options for
    dropdown_options: List of dropdown options to add/remove

Returns:
    JSON string with success status and dropdown update details

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
spreadsheet_nameYesThe name of the Google Spreadsheet
sheet_nameYesThe name of the sheet containing the table
table_nameYesName of the table to update dropdown options in
actionYesAction to perform: 'add' or 'remove'
column_nameYesName of the column to update dropdown options for
dropdown_optionsNoList of dropdown options to add/remove (required for 'add' and 'remove' actions)

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The main handler function that performs input validation, retrieves spreadsheet/sheet/table IDs using helper utilities, constructs Google Sheets API batchUpdate requests to modify column dataValidationRule for DROPDOWN columns (add or remove options), and returns JSON response.
    def update_dropdown_options_handler(
        drive_service,
        sheets_service,
        spreadsheet_name: str,
        sheet_name: str,
        table_name: str,
        action: str,
        column_name: str,
        dropdown_options: Optional[List[str]] = None
    ) -> str:
        """
        Update dropdown options in a table column in Google Sheets using the official updateTable operation.
        
        According to the official Google Sheets API documentation, to update dropdown options:
        1. Use UpdateTableRequest to update column properties with data validation rules
        2. Set the column type to DROPDOWN and add validation options, or remove validation
        
        Args:
            drive_service: Google Drive service instance
            sheets_service: Google Sheets service instance
            spreadsheet_name: Name of the spreadsheet
            sheet_name: Name of the sheet containing the table
            table_name: Name of the table to update dropdown options in
            action: Action to perform - "add" or "remove"
            column_name: Name of the column to update dropdown options for
            dropdown_options: List of dropdown options to add/remove:
                - For "add" action: List of new options to add to existing dropdown
                - For "remove" action: List of options to remove from existing dropdown
        
        Returns:
            str: Success message with dropdown update details or error message
        """
        try:
            # Validate inputs
            if not table_name or table_name.strip() == "":
                return compact_json_response({
                    "success": False,
                    "message": "Table name is required."
                })
            
            if action not in ["add", "remove"]:
                return compact_json_response({
                    "success": False,
                    "message": "Action must be 'add' or 'remove'."
                })
            
            if not column_name or not isinstance(column_name, str) or column_name.strip() == "":
                return compact_json_response({
                    "success": False,
                    "message": "Column name is required and cannot be empty."
                })
            
            # Validate dropdown options for add/remove actions
            if action in ["add", "remove"]:
                if not dropdown_options or not isinstance(dropdown_options, list):
                    return compact_json_response({
                        "success": False,
                        "message": f"Dropdown options are required for '{action}' action and must be a list."
                    })
            
            # Validate column name
            validated_column = column_name.strip()
            
            # Validate dropdown options for add/remove actions
            validated_operations = []
            if action in ["add", "remove"]:
                if not dropdown_options:
                    return compact_json_response({
                        "success": False,
                        "message": f"Dropdown options are required for '{action}' action."
                    })
                
                if not isinstance(dropdown_options, list):
                    return compact_json_response({
                        "success": False,
                        "message": "Dropdown options must be a list."
                    })
                
                if not dropdown_options:
                    return compact_json_response({
                        "success": False,
                        "message": "Dropdown options cannot be empty."
                    })
                
                # Validate individual options
                valid_options = []
                invalid_options = []
                
                for j, option in enumerate(dropdown_options):
                    if not isinstance(option, str) or option.strip() == "":
                        invalid_options.append({"option_index": j, "option": option, "error": "Option cannot be empty"})
                    else:
                        valid_options.append(option.strip())
                
                if invalid_options:
                    error_messages = [f"Option {item['option_index']+1}: {item['error']}" for item in invalid_options]
                    return compact_json_response({
                        "success": False,
                        "message": f"Invalid options: {'; '.join(error_messages)}"
                    })
                
                if not valid_options:
                    return compact_json_response({
                        "success": False,
                        "message": "No valid options provided."
                    })
                
                validated_operations.append({
                    "column_name": validated_column,
                    "options": valid_options
                })
            
            # 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 sheet ID
            sheet_ids = get_sheet_ids_by_names(sheets_service, spreadsheet_id, [sheet_name])
            sheet_id = sheet_ids.get(sheet_name)
            if sheet_id is None:
                return compact_json_response({
                    "success": False,
                    "message": f"Sheet '{sheet_name}' not found in spreadsheet '{spreadsheet_name}'."
                })
            
            # Get table ID
            table_ids = get_table_ids_by_names(sheets_service, spreadsheet_id, sheet_name, [table_name])
            table_id = table_ids.get(table_name)
            if not table_id:
                return compact_json_response({
                    "success": False,
                    "message": f"Table '{table_name}' not found in sheet '{sheet_name}'."
                })
            
            # Get table information
            try:
                table_info = get_table_info(sheets_service, spreadsheet_id, table_id)
                columns = table_info.get('columns', [])
            except Exception as e:
                return compact_json_response({
                    "success": False,
                    "message": f"Could not retrieve information for table '{table_name}': {str(e)}"
                })
            
            # Validate that the specified column exists in the table
            existing_column_names = [col.get("name", "") for col in columns]
            missing_columns = []
            valid_operations = []
            
            if action == "add":
                # For add action, check if column exists
                if validated_column not in existing_column_names:
                    missing_columns.append(validated_column)
                else:
                    valid_operations.append({
                        "column_name": validated_column,
                        "options": dropdown_options
                    })
            elif action == "remove":
                # For remove action, check if column exists and has dropdown validation
                for col in columns:
                    if col.get("name", "") == validated_column:
                        col_type = col.get("type", "TEXT")
                        has_validation = "dataValidationRule" in col
                        
                        if col_type == "DROPDOWN" and has_validation:
                            valid_operations.append({
                                "column_name": validated_column,
                                "options": dropdown_options
                            })
                        else:
                            missing_columns.append(validated_column)
                        break
            
            if missing_columns:
                return compact_json_response({
                    "success": False,
                    "message": f"Column(s) not found or invalid: {', '.join(missing_columns)}"
                })
            
            if not valid_operations:
                return compact_json_response({
                    "success": False,
                    "message": f"No valid {action} operations after validation."
                })
            
            # Create batch update requests
            requests = []
            
            # Update table column properties
            updated_columns = []
            for col in columns:
                col_name = col.get("name", "")
                col_index = col.get("index", 0)
                col_updated = False
                
                if action == "add":
                    # Add dropdown validation or add options to existing dropdown
                    for operation in valid_operations:
                        if operation["column_name"] == col_name:
                            # Get existing dropdown options if any
                            existing_options = []
                            if col.get("type") == "DROPDOWN" and "dataValidationRule" in col:
                                existing_values = col["dataValidationRule"].get("condition", {}).get("values", [])
                                existing_options = [val.get("userEnteredValue", "") for val in existing_values if val.get("userEnteredValue")]
                            
                            # Combine existing and new options, removing duplicates
                            all_options = list(set(existing_options + operation["options"]))
                            
                            updated_col = {
                                "columnIndex": col_index,
                                "columnName": col_name,
                                "columnType": "DROPDOWN",
                                "dataValidationRule": {
                                    "condition": {
                                        "type": "ONE_OF_LIST",
                                        "values": [{"userEnteredValue": opt} for opt in all_options]
                                    }
                                }
                            }
                            updated_columns.append(updated_col)
                            col_updated = True
                            break
                elif action == "remove":
                    # Remove specific options from dropdown
                    for operation in valid_operations:
                        if operation["column_name"] == col_name:
                            # Get existing dropdown options
                            existing_options = []
                            if col.get("type") == "DROPDOWN" and "dataValidationRule" in col:
                                existing_values = col["dataValidationRule"].get("condition", {}).get("values", [])
                                existing_options = [val.get("userEnteredValue", "") for val in existing_values if val.get("userEnteredValue")]
                            
                            # Remove specified options
                            options_to_remove = set(operation["options"])
                            remaining_options = [opt for opt in existing_options if opt not in options_to_remove]
                            
                            if remaining_options:
                                # Keep dropdown with remaining options
                                updated_col = {
                                    "columnIndex": col_index,
                                    "columnName": col_name,
                                    "columnType": "DROPDOWN",
                                    "dataValidationRule": {
                                        "condition": {
                                            "type": "ONE_OF_LIST",
                                            "values": [{"userEnteredValue": opt} for opt in remaining_options]
                                        }
                                    }
                                }
                            else:
                                # Convert to TEXT if no options remain
                                updated_col = {
                                    "columnIndex": col_index,
                                    "columnName": col_name,
                                    "columnType": "TEXT"
                                }
                            
                            updated_columns.append(updated_col)
                            col_updated = True
                            break
                
                if not col_updated:
                    # Keep existing column unchanged - only include required fields
                    updated_col = {
                        "columnIndex": col_index,
                        "columnName": col_name,
                        "columnType": col.get("type", "TEXT")
                    }
                    # Preserve dataValidationRule if it exists
                    if "dataValidationRule" in col:
                        updated_col["dataValidationRule"] = col["dataValidationRule"]
                    updated_columns.append(updated_col)
            
            update_table_request = {
                "updateTable": {
                    "table": {
                        "tableId": table_id,
                        "columnProperties": updated_columns
                    },
                    "fields": "columnProperties.dataValidationRule"
                }
            }
            requests.append(update_table_request)
            
            # Execute the batch update
            response = sheets_service.spreadsheets().batchUpdate(
                spreadsheetId=spreadsheet_id,
                body={"requests": requests}
            ).execute()
            
            # Extract response information
            replies = response.get("replies", [])
            successful_operations = len(valid_operations)
            
            if action == "add":
                response_data = {
                    "success": True,
                    "spreadsheet_name": spreadsheet_name,
                    "sheet_name": sheet_name,
                    "table_name": table_name,
                    "action": "add",
                    "dropdowns_updated": successful_operations,
                    "options_added": valid_operations,
                    "message": f"Successfully added dropdown options to {successful_operations} column(s) in table '{table_name}' in '{sheet_name}'"
                }
            elif action == "remove":
                response_data = {
                    "success": True,
                    "spreadsheet_name": spreadsheet_name,
                    "sheet_name": sheet_name,
                    "table_name": table_name,
                    "action": "remove",
                    "dropdowns_updated": successful_operations,
                    "options_removed": valid_operations,
                    "message": f"Successfully removed dropdown options from {successful_operations} column(s) in table '{table_name}' in '{sheet_name}'"
                }
            
            return compact_json_response(response_data)
            
        except HttpError as error:
            return compact_json_response({
                "success": False,
                "message": f"Google Sheets API error: {str(error)}"
            })
        except Exception as e:
            return compact_json_response({
                "success": False,
                "message": f"Error managing dropdown options: {str(e)}"
            }) 
  • Registers the MCP tool 'update_dropdown_options_tool' with Pydantic input schema using @mcp.tool() decorator. Initializes Google services and delegates execution to the handler function.
    @mcp.tool()
    def update_dropdown_options_tool(
        spreadsheet_name: str = Field(..., description="The name of the Google Spreadsheet"),
        sheet_name: str = Field(..., description="The name of the sheet containing the table"),
        table_name: str = Field(..., description="Name of the table to update dropdown options in"),
        action: str = Field(..., description="Action to perform: 'add' or 'remove'"),
        column_name: str = Field(..., description="Name of the column to update dropdown options for"),
        dropdown_options: List[str] = Field(default=[], description="List of dropdown options to add/remove (required for 'add' and 'remove' actions)")
    ) -> str:
        """
        Update dropdown options in a table column.
        
        This tool can add or remove specific dropdown options from an existing column in a table.
        For 'add' action: Adds new options to existing dropdown (preserves existing options).
        For 'remove' action: Removes specific options from existing dropdown.
        
        Args:
            spreadsheet_name: Name of the spreadsheet
            sheet_name: Name of the sheet containing the table
            table_name: Name of the table to update dropdown options in
            action: Action to perform - "add" or "remove"
            column_name: Name of the column to update dropdown options for
            dropdown_options: List of dropdown options to add/remove
        
        Returns:
            JSON string with success status and dropdown update details
        """
        sheets_service, drive_service = _get_google_services()
        return update_dropdown_options_handler(drive_service, sheets_service, spreadsheet_name, sheet_name, table_name, action, column_name, dropdown_options)
  • Pydantic Field definitions providing the input schema, validation, and descriptions for the tool parameters.
    spreadsheet_name: str = Field(..., description="The name of the Google Spreadsheet"),
    sheet_name: str = Field(..., description="The name of the sheet containing the table"),
    table_name: str = Field(..., description="Name of the table to update dropdown options in"),
    action: str = Field(..., description="Action to perform: 'add' or 'remove'"),
    column_name: str = Field(..., description="Name of the column to update dropdown options for"),
    dropdown_options: List[str] = Field(default=[], description="List of dropdown options to add/remove (required for 'add' and 'remove' actions)")
Behavior4/5

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

With no annotations provided, the description carries full behavioral disclosure burden. It clearly explains the mutation behavior ('update dropdown options'), specifies that 'add' preserves existing options while 'remove' targets specific options, and mentions the return format ('JSON string with success status and dropdown update details'). However, it doesn't cover error conditions, permission requirements, or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Perfectly structured with a clear opening statement, action-specific explanations, parameter summary, and return value description. Every sentence adds value with zero redundancy. The description is appropriately sized for a 6-parameter mutation tool.

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

Completeness4/5

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

For a mutation tool with no annotations but with output schema (implied by 'Returns' statement), the description provides good coverage: clear purpose, behavioral details, parameter context, and return format. The main gap is lack of error handling or permission context, but overall it's substantially complete for agent usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 6 parameters thoroughly. The description adds minimal value beyond the schema - it clarifies that dropdown_options is 'required for add and remove actions' (implied by schema) and provides action semantics. Since schema does the heavy lifting, baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('update dropdown options'), resource ('in a table column'), and scope ('add or remove specific dropdown options'). It distinguishes itself from sibling tools like update_table_column_type_tool or update_table_column_name_tool by focusing specifically on dropdown option management rather than column properties or data types.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context through the explanation of 'add' and 'remove' actions, but doesn't explicitly state when to use this tool versus alternatives. It doesn't mention prerequisites (like requiring an existing dropdown column) or compare with other table modification tools. The guidance is functional but not strategic.

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

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