Google Sheets
GoogleSheets_InspectSpreadsheet
Inspect a Google Sheets spreadsheet's structure or read a range of cells. Use the default 'structure' mode to understand a workbook cheaply before reading. Switch to 'read' mode to pull a range as a grid of rows, optionally with per-cell annotations and a rendered markdown/csv/tsv export. In 'read' mode the response's per-tab 'sheets' block reports only tab identity and the allocated grid; its scan-derived fields (used_range, populated_cell_count, formula_cell_count, first_row, table_regions) are placeholders (0/empty) because read mode does not scan the tab — they do NOT mean the tab is empty or that it has no tables. The data you read is in the top-level 'range' and 'rows'. Call 'structure' mode for those aggregates and for the workbook's charts, merges, protected ranges, and conditional formats. Workflow for a tab that holds multiple tables, or a table that does not start at A1: call 'structure' first and use that tab's estimated 'table_regions' to choose the a1_range to read or filter, so you target one table instead of a glued multi-table range. Always check the response's top-level 'warnings' list: read mode reports there when a result was capped or trimmed (cell budget, the per-cell annotation cap, or an empty filter scan) and tells you how to recover (page 'next_range', narrow 'a1_range', 'select_columns', or request fewer annotation kinds).
Remote (network-hosted)
Other tools also called GoogleSheets_InspectSpreadsheet?
See providers with this name
Input Schema
{
"type": "object",
"properties": {
"mode": {
"enum": [
"structure",
"read"
],
"type": "string",
"description": "What to return. 'structure' (default) gives a cheap workbook overview: every tab's ids, allocated grid, frozen panes, merges, charts, protected ranges, conditional-format counts, real used range, first row, and ESTIMATED table_regions (A1 ranges of distinct data blocks per tab — a heuristic for spotting multiple tables in one tab; scope a1_range to one of these to read or filter a single table; empty for tabs too large to peek). 'read' pulls cell data from one tab."
},
"a1_range": {
"type": "string",
"description": "Read mode only: the range of cells to pull, in A1 notation (e.g. 'A1:F100'), WITHIN the selected tab — the tab is chosen by sheet_id/sheet_title, and any sheet prefix here (e.g. 'Other!A1:B2') is ignored. Defaults to the tab's used range. This is also the paging knob — request the next range to page."
},
"max_rows": {
"type": "integer",
"description": "Read mode only: maximum rows to return. Sets truncated=True when the range has more rows; pass the returned next_range as a1_range to page. When filtering, this bounds the rows SCANNED per page (matches may be fewer, even 0 — page until next_range is empty). Also capped so rows x columns stays within 4000 cells: a wide range returns fewer rows than requested (with a warning) and pages the rest. Defaults to 200."
},
"sheet_id": {
"type": "integer",
"description": "Read mode only: select the tab by its numeric sheetId. Mutually exclusive with sheet_title. Defaults to the first tab when both are omitted."
},
"export_as": {
"enum": [
"markdown",
"csv",
"tsv"
],
"type": "string",
"description": "Read mode only: also render the returned values as text. Omit to return structured values only. csv/tsv are lossless; markdown is display-oriented (in-cell newlines become <br>, pipes are escaped)."
},
"max_length": {
"type": "integer",
"description": "Read mode only: cap each returned cell string at this many characters. A longer cell becomes '<first chars>…(+N chars)' (the suffix is not counted; N = hidden chars). Pass 0 for full, untruncated strings; a positive value below the floor (or negative) clamps up to the floor. Filtering still matches the full cell value. Defaults to a small cap (50)."
},
"annotations": {
"type": "array",
"items": {
"enum": [
"formulas",
"notes",
"number_formats",
"data_validation",
"conditional_formats",
"merges",
"types",
"hyperlinks",
"protected",
"spill"
],
"type": "string"
},
"description": "Read mode only: per-cell extras to include — pass only the kinds you need (e.g. ['formulas','notes']); each extra kind adds payload. Omit or leave empty to return values only (cheaper). Returned sparsely — one entry only per cell that carries a requested extra — and capped at the first 500 entries (row-major). Over that cap a warning is returned; rows may extend past the annotated slice, so a missing annotation beyond the cap is NOT authoritative — re-read a narrower a1_range, use select_columns, or request fewer kinds to confirm."
},
"sheet_title": {
"type": "string",
"description": "Read mode only: select the tab by name. Mutually exclusive with sheet_id. Defaults to the first tab when both are omitted."
},
"value_render": {
"enum": [
"formatted",
"unformatted"
],
"type": "string",
"description": "Read mode only: 'formatted' (default) returns display strings like '$1,234.50'; 'unformatted' returns raw values suitable for math."
},
"filter_combine": {
"enum": [
"and",
"or"
],
"type": "string",
"description": "Read mode only: how to combine multiple filter_conditions — a single top-level 'and'/'or' applied to all conditions (no nested grouping or mixed and/or). Defaults to 'and'."
},
"select_columns": {
"type": "array",
"items": {
"type": "string"
},
"description": "Read mode only: return only these columns, by spreadsheet column LETTER (not header name), in this order. Defaults to all columns in a1_range."
},
"spreadsheet_id": {
"type": "string",
"description": "The id of the spreadsheet to inspect."
},
"include_headers": {
"type": "boolean",
"description": "Structure mode only: include each tab's first row in the overview. Defaults to True."
},
"filter_conditions": {
"type": "array",
"items": {
"type": "object",
"required": [
"column",
"op",
"value"
],
"properties": {
"op": {
"enum": [
"eq",
"ne",
"contains",
"not_contains",
"gt",
"gte",
"lt",
"lte",
"blank",
"not_blank"
],
"type": "string"
},
"value": {
"type": "string"
},
"column": {
"type": "string"
}
},
"additionalProperties": false
},
"description": "Read mode only: keep only rows matching these conditions. Each is {column, op, value} where column is the spreadsheet column LETTER (e.g. 'C'), NOT the header name, and must be inside a1_range. Ops: eq/ne (exact string), contains/not_contains (case-insensitive substring), gt/gte/lt/lte (NUMERIC only — text columns match nothing), blank/not_blank (value is ignored — pass ''). Numeric ops parse currency like $1,234.50, but NOT percents (21%) or other formatted text — set value_render='unformatted' and compare against the underlying number (percents are stored as fractions, e.g. 0.21 for 21%). A warning is returned when a numeric filter matches nothing it scanned. Scans within a1_range only — page next_range for completeness, and scope a1_range to a single homogeneous table (use structure mode's table_regions to find each table's range; exclude header/title rows, which would otherwise be filtered as data)."
}
}
}