Skip to main content
Glama

Query a connected table

query_table
Read-onlyIdempotent

A bounded, structured query over one table's current version. NO SQL: send columns, filters, order_by, aggregates, group_by and limit as JSON. Example: {"table_id": "0f2f...", "columns": ["observed_at", "air_temp_f"], "filters": [{"column": "air_temp_f", "operator": "gte", "value": 80}], "order_by": [{"column": "observed_at", "direction": "desc"}], "limit": 50}. Ceilings: 64 columns, 8 filters, 2 sort keys, 4 aggregates, 4 group keys, 10000 rows a page (25 when limit is omitted), 8 MiB of JSON. Every page answers with next_cursor; send it back as cursor (same columns, filters and order_by) for the next page until it is null, and you have read the whole table on one immutable version. Operators, all ANDed: eq, neq, in (an array of at most 20 values), gt, gte, lt, lte, is_null and is_not_null (no value), between (exactly two non-null bounds, inclusive at both ends), and contains, starts_with and ends_with (one non-empty string, case-sensitive, text columns only). Dates and timestamps compare as ISO strings, so a month is one between or a gte plus an lt. GROUPED AGGREGATES: send group_by beside aggregates for one row per distinct combination, keyed by the group column names and the aggregate aliases. Example: {"table_id": "0f2f...", "columns": ["station"], "group_by": ["station"], "aggregates": [{"function": "avg", "column": "air_temp_f", "as": "avg_temp"}], "order_by": [{"column": "avg_temp", "direction": "desc"}], "limit": 10}. An aggregate answers under its as, or under {function}{column or "all"}{position} without one. group_by needs at least one aggregate, no two result columns may share a name and names are compared without case (group_by ["city"] refuses an alias of "CITY", and two aggregates cannot share one alias), and order_by may only name a group column or an alias. limit counts GROUPS, execution.truncated means the limit was reached so there may be more groups, and a grouped answer has no next page: next_cursor is null and offset and cursor stay refused beside aggregates. Without group_by an aggregate query returns one row for the whole table and cannot be ordered. TEXT SEARCH: when get_table_schema returns capabilities.search, add search: {"text": "...", "columns": its keyword_columns (or some of them), "spec_digest": its spec_digest} for the existing all-terms search and its unchanged response. For words, prefixes, typos and meaning on public tables, explicitly add search.engine: "resident" and search.settled: true. Public ready packages return rows, applied plan, planner origin/reason, package generation/digest, timings and next_cursor without a total. Send later pages with search.plan and search.cursor; explicit search.plan is validated by the service and invalid_plan diagnostics pass through. Request lazy count separately with search.plan and search.count (matching_rows or relevance_window). Preparing/unavailable first pages answer by the existing scan with a path note; an unavailable continuation returns restart_required (restart_from: 1). Scan fallbacks do not apply the resident plan; count covers lexical matching rows. Private and link-shared tables retain scan search and explain unsupported resident members in the note. For scan answers, execution.search_mode says how it ran and execution.search_scope what the count covers. A refusal saying search is unavailable means the table's version changed: call get_table_schema again. Requires an mr_use_ workspace key (Authorization: Bearer) or an OAuth connection. The first query over a dataset connects it to the workspace; connect_dataset makes that explicit but is not required. Resident answers return row_id and fields, the applied plan, planner, package and timings; cite the package generation/digest. Scan answers return rows plus table.version_id and table.content_digest; cite those. For the whole table in one request, download the Parquet instead. Reads past the free sample (the first 500 rows of a table in stored order) count against the workspace's shared free monthly allowance of 100,000 rows and 1,000 queries (the workspace of the key or grant in use) unless it is subscribed. A download counts the rows it contains, plus one query per table. At the limit the tool answers usage_limit_exceeded with the reset time and an upgrade URL.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNo
cursorNo
offsetNo
searchNo
columnsYes
filtersNo
group_byNo
order_byNo
table_idYes
aggregatesNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changed
    • addedInput schema / properties / search / properties / count
      Added value: +{
      +  "enum": [
      +    "matching_rows",
      +    "relevance_window"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / search / properties / cursor
      Added value: +{
      +  "maxLength": 4096,
      +  "minLength": 1,
      +  "type": "string"
      +}
    • addedInput schema / properties / search / properties / engine
      Added value: +{
      +  "const": "resident",
      +  "type": "string"
      +}
    • addedInput schema / properties / search / properties / plan
      Added value: +{
      +  "additionalProperties": {},
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • addedInput schema / properties / search / properties / settled
      Added value: +{
      +  "const": true,
      +  "type": "boolean"
      +}
  2. Changed1 schema field changed
    • addedInput schema / properties / search
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "columns": {
      +      "items": {
      +        "maxLength": 128,
      +        "minLength": 1,
      +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
      +        "type": "string"
      +      },
      +      "maxItems": 16,
      +      "type": "array"
      +    },
      +    "generation_digest": {
      +      "pattern": "^sha256:[0-9a-f]{64}$",
      +      "type": "string"
      +    },
      +    "mode": {
      +      "enum": [
      +        "lexical",
      +        "hybrid"
      +      ],
      +      "type": "string"
      +    },
      +    "spec_digest": {
      +      "pattern": "^sha256:[0-9a-f]{64}$",
      +      "type": "string"
      +    },
      +    "text": {
      +      "maxLength": 512,
      +      "minLength": 1,
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "text",
      +    "columns",
      +    "spec_digest"
      +  ],
      +  "type": "object"
      +}
  3. Changed2 schema fields changed
    • changedInput schema / properties / filters / items / properties / operator / enum
      Previous value: -[
      -  "eq",
      -  "neq",
      -  "in",
      -  "gt",
      -  "gte",
      -  "lt",
      -  "lte",
      -  "is_null",
      -  "is_not_null"
      -]New value: +[
      +  "eq",
      +  "neq",
      +  "in",
      +  "gt",
      +  "gte",
      +  "lt",
      +  "lte",
      +  "is_null",
      +  "is_not_null",
      +  "between",
      +  "contains",
      +  "starts_with",
      +  "ends_with"
      +]
    • addedInput schema / properties / group_by
      Added value: +{
      +  "default": [],
      +  "items": {
      +    "maxLength": 128,
      +    "minLength": 1,
      +    "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
      +    "type": "string"
      +  },
      +  "maxItems": 4,
      +  "type": "array"
      +}
  4. Changed3 schema fields changed
    • addedInput schema / properties / cursor
      Added value: +{
      +  "maxLength": 512,
      +  "minLength": 1,
      +  "type": "string"
      +}
    • changedInput schema / properties / limit / maximum
      Previous value: -100New value: +10000
    • addedInput schema / properties / offset
      Added value: +{
      +  "maximum": 100000000,
      +  "minimum": 0,
      +  "type": "integer"
      +}
  5. First observed

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, yet the description adds substantial operational context: cursor-based pagination over one immutable version, per-page semantics, execution.truncated, restart_required with restart_from, auth requirement (mr_use_ workspace key or OAuth), free-sample boundary, and the shared 100,000-row/1,000-query allowance with usage_limit_exceeded behavior. No contradiction with the read-only annotations.

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?

Extremely long but justified by a 10-parameter tool with nested search, pagination and billing semantics; it is front-loaded with the core contract and uses ALL-CAPS section markers (NO SQL, GROUPED AGGREGATES, TEXT SEARCH). However, several run-on sentences cram multiple rules together, so the structure is dense rather than clean.

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

Completeness5/5

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

There is no output schema, and the description compensates by describing return shapes and citations: next_cursor/execution.truncated, row_id and fields for resident answers, table.version_id and table.content_digest for scan answers, planner/package/timings, and validation diagnostics such as invalid_plan. Auth, quota and refusal behavior round out a complete picture for calling this tool correctly.

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

Parameters5/5

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

Schema description coverage is 0%, so the description carries full weight and delivers: every operator's arity and semantics (is_null takes no value, between is exactly two inclusive bounds, contains/starts_with/ends_with are one non-empty case-sensitive string on text columns), limit counting GROUPS in aggregate mode, order_by restrictions, aggregate alias naming rules and group_by interdependencies, plus per-request ceilings and the cursor/offset refusal beside aggregates. Only minor fields (search.mode, generation_digest) go unexplained.

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?

Opens with a precise verb+resource+scope: 'A bounded, structured query over one table's current version', immediately followed by the crucial constraint 'NO SQL'. It also routes away to alternatives (get_table_schema for capabilities.search, download the Parquet for the whole table), so an agent can place it against siblings like sample_rows, fetch or get_table without opening a schema.

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

Usage Guidelines5/5

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

Explicit when-to-use branches are given: add search only when get_table_schema returns capabilities.search; use the resident engine for words/prefixes/typos on public tables; use download for a whole table; connect_dataset makes the implicit connection explicit but is not required. It also states when-not and the recovery path ('A refusal saying search is unavailable means the table's version changed: call get_table_schema again').

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources