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 googlesheets

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)."
    }
  }
}