Skip to main content
Glama

Secedgar Dataframe Query

secedgar_dataframe_query
Read-onlyIdempotent

Run a single-statement SELECT against the canvas dataframes registered by the data-returning secedgar_* tools — any tool whose response carries a dataset handle. Inspect a dataframe with secedgar_dataframe_describe first; its column schema is what the SQL has to match. Read-only: writes, DDL, DROP, COPY, PRAGMA, ATTACH, and external-file table functions are rejected. System catalogs (information_schema, pg_catalog, sqlite_master, duckdb_*) are denied — list dataframes via secedgar_dataframe_describe. Optional register_as chains the result as a new dataframe with a fresh TTL.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sqlYesSingle-statement SELECT against df_<id> tables on the shared canvas. Standard DuckDB SQL — joins, aggregates, window functions, CTEs all supported. Reference dataframes by the names returned in fetch/search responses or listed by secedgar_dataframe_describe. BIGINT columns (e.g., XBRL `value`, COUNT/SUM results) serialize as JSON strings to preserve precision past 2^53 — CAST(col AS DOUBLE) in projections for inline arithmetic.
previewNoRows to include in the immediate response. Defaults to the row limit. Set lower (e.g., 50) when chaining via register_as and only a sample is needed inline.
row_limitNoHard cap on rows materialized in the response. Default 1000, max 10000. A query matching more rows than this stops at the cap and `row_count_capped` comes back true; the full result lives on-canvas under register_as when provided, so do not raise this to keep large results. One case is not detectable: a SQL LIMIT exactly equal to this cap reads identically to a result that genuinely holds that many rows, and is reported as exact.
register_asNoWhen set, persist the result as a new dataframe under this name (must match df_XXXXX_XXXXX shape, or pass a fresh df_<id> generated by the agent). Fresh TTL window — not inherited from the parents in the SELECT. Use to chain analyses without re-running the source SQL.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
capNoThe row cap that actually bound — `preview` when it is lower than `row_limit`, otherwise `row_limit`.
rowsNoMaterialized rows, bounded by `preview` / `row_limit`.
errorNoPresent when the call failed. Absent on success.
shownNoNumber of rows returned inline.
noticeNoGuidance when the query returned no rows, or when the row cap withheld some.
columnsNoColumn names in projection order.
row_countNoRows the query produced, up to `row_limit`; exceeds `rows.length` when `preview` returned fewer. When `row_count_capped` is true this is the cap, not the full size.
truncatedNoTrue when the result set held more rows than the row cap allowed through.
expires_atNoISO 8601 expiry timestamp for the newly registered dataframe, when applicable.
registered_asNoSet when `register_as` was supplied and the new dataframe was materialized.
row_count_cappedNoTrue when more rows matched than `row_limit`, so `row_count` is the cap; false means `row_count` is exact.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changed
    • changedOutput schema / properties / row_count / description
      Previous value: -"Rows the query produced, up to `row_limit` (exceeds `rows.length` when `preview` returned fewer). Read it with `row_count_capped`: when that is true this number is the `row_limit` cap itself, and the size of the full result is not in this response."New value: +"Rows the query produced, up to `row_limit`; exceeds `rows.length` when `preview` returned fewer. When `row_count_capped` is true this is the cap, not the full size."
    • changedOutput schema / properties / row_count_capped / description
      Previous value: -"True when the query matched more rows than `row_limit`, so `row_count` is that cap rather than a total. False means `row_count` is exact — including when it happens to equal `row_limit`."New value: +"True when more rows matched than `row_limit`, so `row_count` is the cap; false means `row_count` is exact."
  2. Changed2 schema fields changed
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: The DataCanvas service is not configured for this deployment `system_catalog_access`: The SQL query references a denied DuckDB system catalog (information_schema, pg_catalog, sqlite_master, duckdb_*) `missing_table`: The SQL query references a df_<id> table that does not exist or has expired `invalid_sql`: The SQL statement contains a syntax or execution error not covered by a more specific reason `register_as_clash`: The register_as target name already exists on the canvas `non_select_statement`: The SQL is a non-SELECT statement (DROP, INSERT, UPDATE, DDL, etc.) — only read-only SELECTs run against dataframes Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: The DataCanvas service is not configured for this deployment. `system_catalog_access`: The SQL query references a denied DuckDB system catalog (information_schema, pg_catalog, sqlite_master, duckdb_*). `missing_table`: The SQL query references a df_<id> table that does not exist or has expired. `invalid_sql`: The SELECT fails to prepare — an unknown column or an invalid expression — or hits an engine error no more specific reason covers. `sql_execution_error`: The SELECT prepared but failed on the data it read — a cast or conversion that does not fit, an out-of-range value, or invalid input to a function. `register_as_clash`: The register_as target name already exists on the canvas. `non_select_statement`: The SQL is not a SELECT (DROP, INSERT, UPDATE, DDL, PRAGMA, EXPLAIN, etc.) or does not parse — only read-only SELECTs run against dataframes. `multi_statement`: The SQL holds more than one statement. `denied_function`: The SQL calls a file-reading or external-data table function such as read_csv, read_parquet, or glob. `plan_operator_not_allowed`: The query plan uses an operator outside the read-only allowlist, such as the range() or generate_series() table functions. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / error / properties / data / properties / reason / examples
      Previous value: -[
      -  "canvas_unavailable",
      -  "system_catalog_access",
      -  "missing_table",
      -  "invalid_sql",
      -  "register_as_clash",
      -  "non_select_statement"
      -]New value: +[
      +  "canvas_unavailable",
      +  "system_catalog_access",
      +  "missing_table",
      +  "invalid_sql",
      +  "sql_execution_error",
      +  "register_as_clash",
      +  "non_select_statement",
      +  "multi_statement",
      +  "denied_function",
      +  "plan_operator_not_allowed"
      +]
  3. Changed4 schema fields changed
    • changedInput schema / properties / row_limit / description
      Previous value: -"Hard cap on rows materialized in the response. Default 1000, max 10000. The full result lives on-canvas under register_as when provided — do not raise this to keep large results."New value: +"Hard cap on rows materialized in the response. Default 1000, max 10000. A query matching more rows than this stops at the cap and `row_count_capped` comes back true; the full result lives on-canvas under register_as when provided, so do not raise this to keep large results. One case is not detectable: a SQL LIMIT exactly equal to this cap reads identically to a result that genuinely holds that many rows, and is reported as exact."
    • changedOutput schema / anyOf
      Previous value: -[
      -  {
      -    "not": {
      -      "required": [
      -        "error"
      -      ]
      -    },
      -    "required": [
      -      "columns",
      -      "row_count",
      -      "rows"
      -    ]
      -  },
      -  {
      -    "required": [
      -      "error"
      -    ]
      -  }
      -]New value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "columns",
      +      "row_count",
      +      "row_count_capped",
      +      "rows"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • changedOutput schema / properties / row_count / description
      Previous value: -"Total rows the query produced (may exceed `rows.length` when capped)."New value: +"Rows the query produced, up to `row_limit` (exceeds `rows.length` when `preview` returned fewer). Read it with `row_count_capped`: when that is true this number is the `row_limit` cap itself, and the size of the full result is not in this response."
    • addedOutput schema / properties / row_count_capped
      Added value: +{
      +  "description": "True when the query matched more rows than `row_limit`, so `row_count` is that cap rather than a total. False means `row_count` is exact — including when it happens to equal `row_limit`.",
      +  "type": "boolean"
      +}
  4. Changed10 schema fields changed
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / additionalProperties
      Added value: +false
    • changedOutput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedOutput schema / anyOf
      Added value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "columns",
      +      "row_count",
      +      "rows"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • addedOutput schema / properties / cap
      Added value: +{
      +  "description": "The row cap that actually bound — `preview` when it is lower than `row_limit`, otherwise `row_limit`.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / error
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "Present when the call failed. Absent on success.",
      +  "properties": {
      +    "code": {
      +      "description": "JSON-RPC error code for this failure.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "data": {
      +      "additionalProperties": {},
      +      "properties": {
      +        "reason": {
      +          "description": "Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: The DataCanvas service is not configured for this deployment `system_catalog_access`: The SQL query references a denied DuckDB system catalog (information_schema, pg_catalog, sqlite_master, duckdb_*) `missing_table`: The SQL query references a df_<id> table that does not exist or has expired `invalid_sql`: The SQL statement contains a syntax or execution error not covered by a more specific reason `register_as_clash`: The register_as target name already exists on the canvas `non_select_statement`: The SQL is a non-SELECT statement (DROP, INSERT, UPDATE, DDL, etc.) — only read-only SELECTs run against dataframes Other values are possible when a failure originates below the handler.",
      +          "examples": [
      +            "canvas_unavailable",
      +            "system_catalog_access",
      +            "missing_table",
      +            "invalid_sql",
      +            "register_as_clash",
      +            "non_select_statement"
      +          ],
      +          "type": "string"
      +        },
      +        "recovery": {
      +          "additionalProperties": {},
      +          "description": "Actionable next step for the caller.",
      +          "properties": {
      +            "hint": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "hint"
      +          ],
      +          "type": "object"
      +        },
      +        "retryable": {
      +          "description": "Whether retrying may succeed.",
      +          "type": "boolean"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "message": {
      +      "description": "Human-readable description of what went wrong.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "code",
      +    "message"
      +  ],
      +  "type": "object"
      +}
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when the query returned no rows, or when results were capped."New value: +"Guidance when the query returned no rows, or when the row cap withheld some."
    • addedOutput schema / properties / shown
      Added value: +{
      +  "description": "Number of rows returned inline.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / truncated
      Added value: +{
      +  "description": "True when the result set held more rows than the row cap allowed through.",
      +  "type": "boolean"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "columns",
      -  "row_count",
      -  "rows"
      -]
  5. Changed1 schema field changed
    • addedInput schema / properties / register_as / pattern
      Added value: +"^df_[A-Z0-9]{5}_[A-Z0-9]{5}$"
  6. Changed1 schema field changed
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Guidance when the query returned no rows, or when results were capped.",
      +  "type": "string"
      +}
  7. Added

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true and openWorldHint=false, so safety is covered structurally. The description still adds real behavioral context: which statement types are rejected (writes, DDL, DROP, COPY, PRAGMA, ATTACH, external-file functions), denied system catalogs, the row-cap/row_count_capped semantics, and the fresh-TTL behavior of register_as.

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

Conciseness5/5

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

Front-loaded with the core operation, then prerequisites, then denials, then the register_as option. Every clause conveys a distinct constraint or routing rule; 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 4-param read-only query tool with an output schema and full annotation coverage, the description supplies the remaining gaps: denial rules, catalog restrictions, prerequisite inspection step, and chaining semantics. An agent has everything needed to invoke it correctly.

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% and the schema prose is already unusually detailed (BIGINT-as-string caveat, cap behavior, register_as pattern). The description largely restates that material, adding only the fresh-TTL framing. Baseline 3 is appropriate when the schema carries the parameter burden.

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+resource: run a single-statement SELECT against canvas dataframes registered by data-returning secedgar_* tools. It also scopes the operand (a `dataset` handle) and distinguishes itself from secedgar_dataframe_describe, which it names as the inspection prerequisite.

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 routing: inspect with secedgar_dataframe_describe first so the SQL matches the column schema, and list dataframes there since system catalogs are denied. It also gives conditional guidance for register_as chaining and for lowering preview when only a sample is needed.

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.