Skip to main content
Glama

Brapi Dataframe Query

brapi_dataframe_query

Run SQL across in-memory dataframes. Dataframes auto-populate when find_* tools spill (named df_<uuid>) — the dataframe name appears inline on every find_* response that spilled (result.dataframe.tableName), so the typical flow is find_* → read the name → query here. Use brapi_dataframe_describe to inspect schema and provenance for a known name. SELECT only — writes/DDL/COPY/PRAGMA/ATTACH/file-reads are rejected. Use SQL as the paging idiom: LIMIT/OFFSET to walk results, projection to trim columns, aggregation to summarize. Use registerAs to chain — the result lands as a new dataframe.

Input Schema

NameRequiredDescriptionDefault
sqlYesSELECT statement against dataframes. Single statement only — writes, DDL, DESCRIBE / SUMMARIZE, file reads, and exports are rejected. Use brapi_dataframe_describe to discover available dataframes. SQL is the primary paging idiom: use `LIMIT/OFFSET` to walk a large dataframe, projection to trim columns, and aggregation (`COUNT`, `GROUP BY`, `AVG`) to summarize without materializing every row.
previewNoCap the number of rows returned in this response. A value above `rowLimit` (or, when `rowLimit` is omitted, above the deployment-wide response cap) returns rows up to that ceiling. When omitted, the ceiling applies. Lower this with `registerAs` when you only need a sample to verify the query.
rowLimitNoHard cap on rows materialized into the response, bounded by the deployment-wide response cap. For larger result sets, use `registerAs` to keep the full result queryable instead of raising this.
registerAsNoPersist the full result as a new dataframe under this name. The response is bounded by preview and a 24,000-byte row budget. Conflicts fail — choose a different name, or remove the existing dataframe with brapi_dataframe_drop where this deployment enables it. Identifier rules: letters, digits, and underscores; must start with a letter or underscore; max 63 characters.

Output Schema

NameRequiredDescriptionDefault
capNoRow ceiling that bound the response: the smallest of preview, rowLimit, and the deployment-wide response cap.
rowsNoLeading rows bounded by preview/rowLimit and 24,000 bytes on each serialized row representation. May be empty when the first row is oversized.
errorNoPresent when the call failed. Absent on success.
shownNoRows materialized into `rows`.
noticeNoGuidance for reaching the rows this response left out.
columnsNoColumn names and types in projection order, enough to write a follow-up query.
rowCountNoTotal rows the query produced (may exceed `rows.length` when capped).
dataframeNoName of the dataframe holding the full result, populated when `registerAs` was supplied. Reference this name in follow-up queries.
truncatedNoTrue when the response carries fewer rows than the query produced.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changed
    • changedInput schema / properties / registerAs / description
      Previous value: -"Persist the result as a new dataframe under this name. The response still returns at most `preview` rows; the full result remains queryable as a new dataframe. Conflicts with an existing dataframe name fail — drop first via brapi_dataframe_drop. Identifier rules: letters, digits, and underscores; must start with a letter or underscore; max 63 characters."New value: +"Persist the full result as a new dataframe under this name. The response is bounded by preview and a 24,000-byte row budget. Conflicts fail — choose a different name, or remove the existing dataframe with brapi_dataframe_drop where this deployment enables it. Identifier rules: letters, digits, and underscores; must start with a letter or underscore; max 63 characters."
    • changedOutput schema / properties / rows / description
      Previous value: -"Materialized rows, bounded by preview/rowLimit."New value: +"Leading rows bounded by preview/rowLimit and 24,000 bytes on each serialized row representation. May be empty when the first row is oversized."
  2. Changed8 schema fields changed
    • changedInput schema / properties / preview / description
      Previous value: -"Cap the number of rows returned in this response (1–1000). When omitted, the deployment-wide response cap applies. Lower this with `registerAs` when you only need a sample to verify the query."New value: +"Cap the number of rows returned in this response. A value above `rowLimit` (or, when `rowLimit` is omitted, above the deployment-wide response cap) returns rows up to that ceiling. When omitted, the ceiling applies. Lower this with `registerAs` when you only need a sample to verify the query."
    • changedInput schema / properties / preview / maximum
      Previous value: -1000New value: +9007199254740991
    • changedInput schema / properties / sql / description
      Previous value: -"SELECT statement against dataframes. Single statement only — writes, DDL, file reads, and exports are rejected. Use brapi_dataframe_describe to discover available dataframes. SQL is the primary paging idiom: use `LIMIT/OFFSET` to walk a large dataframe, projection to trim columns, and aggregation (`COUNT`, `GROUP BY`, `AVG`) to summarize without materializing every row."New value: +"SELECT statement against dataframes. Single statement only — writes, DDL, DESCRIBE / SUMMARIZE, file reads, and exports are rejected. Use brapi_dataframe_describe to discover available dataframes. SQL is the primary paging idiom: use `LIMIT/OFFSET` to walk a large dataframe, projection to trim columns, and aggregation (`COUNT`, `GROUP BY`, `AVG`) to summarize without materializing every row."
    • changedOutput schema / properties / cap / description
      Previous value: -"Row ceiling that bound the response (the smaller of preview and rowLimit)."New value: +"Row ceiling that bound the response: the smallest of preview, rowLimit, and the deployment-wide response cap."
    • changedOutput schema / properties / columns / description
      Previous value: -"Column metadata in projection order — name and SQL type. Use this to write follow-up queries without round-tripping through brapi_dataframe_describe."New value: +"Column names and types in projection order, enough to write a follow-up query."
    • changedOutput schema / properties / columns / items / properties / type / description
      Previous value: -"SQL/DuckDB column type (e.g. VARCHAR, BIGINT, DOUBLE, BOOLEAN, JSON) sourced from DuckDB schema metadata. The same type appears whether or not `registerAs` was supplied — without it, the handler runs an internal probe to recover authoritative types that would otherwise be lost when DuckDB BigInts serialize to JSON strings."New value: +"DuckDB column type (e.g. VARCHAR, BIGINT, DOUBLE, BOOLEAN, JSON), the same with or without `registerAs`."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `sql_rejected`: SQL violated read-only rules (multi-statement, non-SELECT, or disallowed operation). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `sql_rejected`: SQL broke the read-only rules: more than one statement, a non-SELECT, a disallowed operation or function, a file or URL named as a table, a system-catalog read, or a DESCRIBE, SUMMARIZE, or SHOW statement. `sql_execution_error`: The SELECT passed the read-only rules but failed while running on the staged data, such as a cast of a value that does not convert. `missing_table`: The SQL names a dataframe this workspace does not hold, because it expired, was dropped, or the name is mistyped. `register_as_clash`: The registerAs name is already taken by a dataframe in this workspace. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / error / properties / data / properties / reason / examples
      Previous value: -[
      -  "sql_rejected"
      -]New value: +[
      +  "sql_rejected",
      +  "sql_execution_error",
      +  "missing_table",
      +  "register_as_clash"
      +]
  3. First observed

TDQS

A4.4/5.0
Behavior4/5

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

Annotations are thin (readOnlyHint=false, openWorldHint=false, idempotentHint=false), so the description carries most of the burden and does it well: SELECT-only enforcement, the exact rejected statement classes, and the registerAs chaining side effect. It stops short of naming error/conflict modes or cost characteristics, which caps it below 5.

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?

Front-loaded with the core action and the workflow that precedes it; each sentence carries distinct information (workflow, alternative tool, constraints, paging idiom, chaining). Slightly dense with back-to-back imperatives, but nothing is filler.

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?

For a SQL-execution tool with an output schema already covering return shape, the description supplies everything else an agent needs: how dataframes come to exist, where to find their names, the allowed statement class, the paging strategy, and how to persist results.

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 coverage is 100%, so preview, rowLimit, and registerAs are already fully documented in structured form; baseline 3 applies. The description adds only marginal value, framing registerAs as a chaining mechanism, but does not explain preview/rowLimit tradeoffs beyond what the schema states.

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?

States a specific verb and resource ('Run SQL across in-memory dataframes') and immediately grounds it in the find_* spill workflow, which distinguishes it from every sibling. An agent can tell it apart from brapi_dataframe_describe and the find_* tools 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?

Gives an explicit end-to-end flow (find_* → read result.dataframe.tableName → query here) and names the alternative (brapi_dataframe_describe) with the condition that selects it (inspect schema/provenance for a known name). Chaining via registerAs is also spelled out.

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.