Skip to main content
Glama

get_sheet_cells_by_range_tool

Retrieve cells from a specific range in a Google Sheet. Specify spreadsheet, sheet, and start/end cells with A1 notation. Optionally include headers.

Instructions

Get sheet cells by range.

This tool retrieves cell data from a specific range within a sheet.
You can specify the exact cell range using A1 notation.

Args:
    spreadsheet_name: Name of the spreadsheet
    sheet_name: Name of the sheet to get cells from
    start_cell: Starting cell reference (e.g., 'A1', 'B2')
    end_cell: Ending cell reference (e.g., 'C5', 'D10')
    include_headers: Whether to include header row

Returns:
    JSON string with cells data and metadata

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
spreadsheet_nameYesThe name of the Google Spreadsheet
sheet_nameYesThe name of the sheet to get cells from
start_cellYesStarting cell reference (e.g., 'A1', 'B2')
end_cellYesEnding cell reference (e.g., 'C5', 'D10')
include_headersNoWhether to include header row (default: False)

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The @mcp.tool() decorator registers 'get_sheet_cells_by_range_tool' as an MCP tool. It accepts parameters: spreadsheet_name, sheet_name, start_cell, end_cell, and include_headers (optional, default False). It delegates to get_sheet_cells_by_range_handler.
    @mcp.tool()
    def get_sheet_cells_by_range_tool(
        spreadsheet_name: str = Field(..., description="The name of the Google Spreadsheet"),
        sheet_name: str = Field(..., description="The name of the sheet to get cells from"),
        start_cell: str = Field(..., description="Starting cell reference (e.g., 'A1', 'B2')"),
        end_cell: str = Field(..., description="Ending cell reference (e.g., 'C5', 'D10')"),
        include_headers: bool = Field(default=False, description="Whether to include header row (default: False)")
    ) -> str:
        """
        Get sheet cells by range.
        
        This tool retrieves cell data from a specific range within a sheet.
        You can specify the exact cell range using A1 notation.
        
        Args:
            spreadsheet_name: Name of the spreadsheet
            sheet_name: Name of the sheet to get cells from
            start_cell: Starting cell reference (e.g., 'A1', 'B2')
            end_cell: Ending cell reference (e.g., 'C5', 'D10')
            include_headers: Whether to include header row
        
        Returns:
            JSON string with cells data and metadata
        """
        sheets_service, drive_service = _get_google_services()
        return get_sheet_cells_by_range_handler(
            drive_service, 
            sheets_service, 
            spreadsheet_name, 
            sheet_name, 
            start_cell, 
            end_cell, 
            include_headers
        )
  • The full implementation of get_sheet_cells_by_range_handler. It validates inputs (start_cell, end_cell), parses cell references, looks up the spreadsheet/sheet IDs, calls the Google Sheets API (spreadsheets().values().get()) with A1 notation range, processes cell data, and returns a compact JSON response with data and summary stats.
    """Handler for getting cell values by range from sheets in Google Sheets."""
    
    from typing import List, Dict, Any, Optional, Union
    from googleapiclient.errors import HttpError
    
    from gsheet_mcp_server.helper.spreadsheet_utils import get_spreadsheet_id_by_name
    from gsheet_mcp_server.helper.sheets_utils import get_sheet_ids_by_names
    from gsheet_mcp_server.helper.tables_utils import parse_cell_reference
    from gsheet_mcp_server.helper.json_utils import compact_json_response
    
    def get_sheet_cells_by_range_handler(
        drive_service,
        sheets_service,
        spreadsheet_name: str,
        sheet_name: str,
        start_cell: str,
        end_cell: str,
        include_headers: bool = False
    ) -> str:
        """
        Get values from a range of cells in a sheet in Google Sheets.
        
        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 to get cells from
            start_cell: Starting cell reference (e.g., 'A1', 'B2')
            end_cell: Ending cell reference (e.g., 'C5', 'D10')
            include_headers: Whether to include header row in results
        
        Returns:
            str: Success message with cell values and mapping or error message
        """
        try:
            # Validate inputs
            if not start_cell or not isinstance(start_cell, str):
                return compact_json_response({
                    "success": False,
                    "message": "Start cell is required and must be a string."
                })
            
            if not end_cell or not isinstance(end_cell, str):
                return compact_json_response({
                    "success": False,
                    "message": "End cell is required and must be a string."
                })
            
            # Validate cell references
            try:
                start_row, start_col = parse_cell_reference(start_cell.strip())
                end_row, end_col = parse_cell_reference(end_cell.strip())
            except ValueError as e:
                return compact_json_response({
                    "success": False,
                    "message": f"Invalid cell reference format: {str(e)}"
                })
            
            # Validate range (start should be before end)
            if start_row > end_row or (start_row == end_row and start_col > end_col):
                return compact_json_response({
                    "success": False,
                    "message": "Start cell must be before or equal to end cell in the range."
                })
            
            # 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 cell values using sheets.values.get
            try:
                # Create range notation
                range_notation = f"'{sheet_name}'!{start_cell.strip()}:{end_cell.strip()}"
                
                response = sheets_service.spreadsheets().values().get(
                    spreadsheetId=spreadsheet_id,
                    range=range_notation
                ).execute()
                
                values = response.get('values', [])
                
                if not values:
                    return compact_json_response({
                        "success": True,
                        "message": f"No data found in range {start_cell}:{end_cell}",
                        "spreadsheet_name": spreadsheet_name,
                        "sheet_name": sheet_name,
                        "range": f"{start_cell}:{end_cell}",
                        "cell_count": 0,
                        "data": [],
                        "summary": {
                            "total_rows": 0,
                            "total_columns": 0,
                            "non_empty_cells": 0
                        }
                    })
                
                # Process the data
                processed_data = []
                non_empty_cells = 0
                
                for row_idx, row in enumerate(values):
                    processed_row = []
                    for col_idx, cell_value in enumerate(row):
                        if cell_value is not None and str(cell_value).strip() != "":
                            non_empty_cells += 1
                        processed_row.append(cell_value)
                    processed_data.append(processed_row)
                
                # Calculate dimensions
                max_cols = max(len(row) for row in processed_data) if processed_data else 0
                total_rows = len(processed_data)
                
                # Prepare response
                response_data = {
                    "success": True,
                    "message": f"Successfully retrieved data from range {start_cell}:{end_cell}",
                    "spreadsheet_name": spreadsheet_name,
                    "sheet_name": sheet_name,
                    "range": f"{start_cell}:{end_cell}",
                    "cell_count": total_rows * max_cols if total_rows > 0 and max_cols > 0 else 0,
                    "data": processed_data,
                    "summary": {
                        "total_rows": total_rows,
                        "total_columns": max_cols,
                        "non_empty_cells": non_empty_cells,
                        "empty_cells": (total_rows * max_cols) - non_empty_cells if total_rows > 0 and max_cols > 0 else 0
                    }
                }
                
                return compact_json_response(response_data)
                
            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 retrieve cell values: {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__
            })
Behavior3/5

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

No annotations are provided, so the description carries the full burden. It states the tool is read-only (retrieves data) and explains parameters like include_headers, but it does not disclose potential error behaviors (e.g., if range is invalid) or any other operational characteristics beyond the basic retrieval action.

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

Conciseness4/5

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

The description is concise with a clear first sentence defining the tool's purpose. The Args section is helpful but somewhat redundant given the input schema, and it is not excessively long. It could be more concise by removing the Args section since schema already covers it.

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?

Given the tool has 5 parameters, an output schema, and a straightforward retrieval operation, the description is mostly complete. It explains the range notation and the include_headers option. However, it lacks details about error handling, return format specifics (e.g., data structure), and potential performance implications.

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% with all parameter descriptions clearly provided. The description adds little beyond restating the schema, such as in the Args section which mirrors the schema. Therefore, the description adds minimal incremental value over the schema.

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

Purpose4/5

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

The description clearly states the tool retrieves cell data from a specific range within a sheet using A1 notation. It specifies the verb 'Get' and resource 'sheet cells by range'. However, it does not explicitly differentiate from the sibling tool 'get_sheet_cells_by_notation_tool' which may also use A1 notation, so it lacks full sibling distinction.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives like 'get_table_data_tool' or 'get_sheet_cells_by_notation_tool'. There is no mention of preferred contexts, limitations, or conditions under which this tool should be chosen.

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