Skip to main content
Glama

fdic-banks-mcp-server

Query staged dataframes with SQL

fdic_dataframe_query
Read-onlyIdempotent

Run one read-only SELECT (DuckDB SQL) across the df_ dataframes that fdic_query_financials and fdic_get_deposits staged or an earlier register_as saved; joins, aggregates, window functions, and CTEs work. Before writing SQL, pass each table name to fdic_dataframe_describe to read its columns. DOUBLE columns come back as JSON numbers and dollar columns are thousands of US dollars; BIGINT results such as COUNT(*) come back as strings, so CAST them to INTEGER or DOUBLE for arithmetic. Writes, DDL, file-reading functions, and system catalogs are rejected. register_as materializes the result as a new dataframe with a fresh TTL.

Input Schema

NameRequiredDescriptionDefault
sqlYesOne SELECT against df_<id> tables named in a dataset field or by fdic_dataframe_describe, up to 20,000 characters.
previewNoRows to return inline; defaults to the effective row_limit and is clamped to it. Set it low when register_as keeps the full result.
row_limitNoRequested materialization cap (default 1,000; hard input ceiling 1,000,000), clamped to the execution cap of 10,000. Without register_as, row_count_capped reports more matches; continue with ordered LIMIT/OFFSET pages. register_as keeps the whole result within the staging budget.
register_asNoMaterialize the full result as a new dataframe under this unused name (df_XXXXX_XXXXX: uppercase letters and digits). A name already staged fails as register_as_clash — including on a repeat of a call that already saved it. The live dataframes share a 1,000,000-row budget: the oldest are dropped to make room, and a result over the budget on its own fails as register_as_too_large. Omit to return rows only.

Output Schema

NameRequiredDescriptionDefault
capNoThe cap that bound: preview when lower, else row_limit.
rowsNoResult rows, bounded by preview and row_limit.
errorNoPresent when the call failed. Absent on success.
shownNoRows returned inline.
noticeNoGuidance when the query returned no rows or a cap withheld some.
columnsNoColumns in projection order.
row_countNoRows the query produced, up to effective_row_limit; with register_as, the exact count of the new dataframe.
truncatedNoTrue when rows were withheld by preview or row_limit.
expires_atNoWhen the register_as dataframe is dropped (ISO 8601).
registered_asNoName of the dataframe register_as created.
row_count_cappedNoTrue when the query matched more rows than effective_row_limit, so row_count is that cap.
effective_previewNoInline row cap after clamping preview to the effective row_limit.
requested_previewNoExplicit preview before clamping; absent when omitted.
effective_row_limitNoEffective row_limit, at most 10,000.
requested_row_limitNoRequested row_limit before the execution cap.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: DataCanvas is not configured in this deployment. `missing_table`: A table the SQL names is not staged — a df_ name that expired, was dropped to make room for newer dataframes, or is mistyped, or any other table name. `invalid_sql`: A SELECT fails to parse or prepare (syntax error, unknown column or function, bad expression). `sql_execution_error`: SELECT prepared but failed on the data. `non_select_statement`: The statement is not a SELECT, or cannot be parsed as one. `multi_statement`: The SQL holds more than one statement. `denied_function`: The SQL calls a file-reading, external-data, engine-setting, or dynamic SQL function the read-only gate refuses. `plan_operator_not_allowed`: The query plan uses an operator outside the read-only allowlist (scans of staged tables, filters, joins, aggregates, set operations, sorts, window functions, CTEs, unnest). `system_catalog_access`: The SQL references a system catalog: information_schema, pg_catalog, sqlite_master, or a duckdb_*() function. `register_as_clash`: register_as names a dataframe that is already staged. `register_as_too_large`: The register_as result holds more rows than the staging budget (1,000,000 rows) allows on its own. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: DataCanvas is not configured in this deployment. `missing_table`: A table the SQL names is not staged — a df_ name that expired, was dropped to make room for newer dataframes, or is mistyped, or any other table name. `invalid_sql`: A SELECT fails to parse or prepare (syntax error, unknown column or function, bad expression). `sql_execution_error`: SELECT prepared but failed on the data. `non_select_statement`: The statement is not a SELECT, or cannot be parsed as one. `multi_statement`: The SQL holds more than one statement. `denied_function`: The SQL calls a file-reading, external-data, engine-setting, or dynamic SQL function the read-only gate refuses, or names current_schema unqualified, which DuckDB reads as the current_schema() function. `plan_operator_not_allowed`: The query plan uses an operator outside the read-only allowlist (scans of staged tables, filters, joins, aggregates, set operations, sorts, window functions, CTEs, unnest). `system_catalog_access`: The SQL references a system catalog: information_schema, pg_catalog, sqlite_master, or a duckdb_*() function. `register_as_clash`: register_as names a dataframe that is already staged. `register_as_too_large`: The register_as result holds more rows than the staging budget (1,000,000 rows) allows on its own. Other values are possible when a failure originates below the handler."
  2. Changed12 schema fields changed
    • changedInput schema / properties / preview / description
      Previous value: -"Rows to return inline (0–10,000); defaults to row_limit, and a value above row_limit is treated as row_limit. Set it low when register_as keeps the full result."New value: +"Rows to return inline; defaults to the effective row_limit and is clamped to it. Set it low when register_as keeps the full result."
    • changedInput schema / properties / preview / maximum
      Previous value: -10000New value: +9007199254740991
    • changedInput schema / properties / row_limit / description
      Previous value: -"Hard cap on rows materialized (1–10,000). A query matching more stops here and row_count_capped comes back true; use register_as to keep the whole result."New value: +"Requested materialization cap (default 1,000; hard input ceiling 1,000,000), clamped to the execution cap of 10,000. Without register_as, row_count_capped reports more matches; continue with ordered LIMIT/OFFSET pages. register_as keeps the whole result within the staging budget."
    • changedInput schema / properties / row_limit / maximum
      Previous value: -10000New value: +1000000
    • changedOutput schema / anyOf
      Previous value: -[
      -  {
      -    "not": {
      -      "required": [
      -        "error"
      -      ]
      -    },
      -    "required": [
      -      "columns",
      -      "row_count",
      -      "row_count_capped",
      -      "rows"
      -    ]
      -  },
      -  {
      -    "required": [
      -      "error"
      -    ]
      -  }
      -]New value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "requested_row_limit",
      +      "effective_row_limit",
      +      "effective_preview",
      +      "columns",
      +      "row_count",
      +      "row_count_capped",
      +      "rows"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • addedOutput schema / properties / effective_preview
      Added value: +{
      +  "description": "Inline row cap after clamping preview to the effective row_limit.",
      +  "maximum": 9007199254740991,
      +  "minimum": -9007199254740991,
      +  "type": "integer"
      +}
    • addedOutput schema / properties / effective_row_limit
      Added value: +{
      +  "description": "Effective row_limit, at most 10,000.",
      +  "maximum": 9007199254740991,
      +  "minimum": -9007199254740991,
      +  "type": "integer"
      +}
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: DataCanvas is not configured in this deployment. `missing_table`: A table the SQL names is not staged — a df_ name that expired, was dropped to make room for newer dataframes, or is mistyped, or any other table name. `invalid_sql`: A SELECT fails to parse or prepare (syntax error, unknown column or function, bad expression). `sql_execution_error`: SELECT prepared but failed on the data. `non_select_statement`: The statement is not a SELECT, or cannot be parsed as one. `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 or read_parquet. `plan_operator_not_allowed`: The query plan uses an operator outside the read-only allowlist (scans of staged tables, filters, joins, aggregates, set operations, sorts, window functions, CTEs, unnest). `system_catalog_access`: The SQL references a system catalog: information_schema, pg_catalog, sqlite_master, or a duckdb_*() function. `register_as_clash`: register_as names a dataframe that is already staged. `register_as_too_large`: The register_as result holds more rows than the staging budget (1,000,000 rows) allows on its own. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: DataCanvas is not configured in this deployment. `missing_table`: A table the SQL names is not staged — a df_ name that expired, was dropped to make room for newer dataframes, or is mistyped, or any other table name. `invalid_sql`: A SELECT fails to parse or prepare (syntax error, unknown column or function, bad expression). `sql_execution_error`: SELECT prepared but failed on the data. `non_select_statement`: The statement is not a SELECT, or cannot be parsed as one. `multi_statement`: The SQL holds more than one statement. `denied_function`: The SQL calls a file-reading, external-data, engine-setting, or dynamic SQL function the read-only gate refuses. `plan_operator_not_allowed`: The query plan uses an operator outside the read-only allowlist (scans of staged tables, filters, joins, aggregates, set operations, sorts, window functions, CTEs, unnest). `system_catalog_access`: The SQL references a system catalog: information_schema, pg_catalog, sqlite_master, or a duckdb_*() function. `register_as_clash`: register_as names a dataframe that is already staged. `register_as_too_large`: The register_as result holds more rows than the staging budget (1,000,000 rows) allows on its own. Other values are possible when a failure originates below the handler."
    • addedOutput schema / properties / requested_preview
      Added value: +{
      +  "description": "Explicit preview before clamping; absent when omitted.",
      +  "maximum": 9007199254740991,
      +  "minimum": -9007199254740991,
      +  "type": "integer"
      +}
    • addedOutput schema / properties / requested_row_limit
      Added value: +{
      +  "description": "Requested row_limit before the execution cap.",
      +  "maximum": 9007199254740991,
      +  "minimum": -9007199254740991,
      +  "type": "integer"
      +}
    • changedOutput schema / properties / row_count / description
      Previous value: -"Rows the query produced, up to row_limit; with register_as, the exact count of the new dataframe."New value: +"Rows the query produced, up to effective_row_limit; with register_as, the exact count of the new dataframe."
    • 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."New value: +"True when the query matched more rows than effective_row_limit, so row_count is that cap."
  3. First observed

TDQS

A4.6/5.0
Behavior5/5

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

Goes well beyond the readOnly/idempotent annotations: it discloses type coercion quirks (DOUBLE as JSON numbers, dollar columns in thousands of USD, BIGINT returned as strings requiring CAST), rejected statement classes, the 1,000,000-row staging budget with oldest-dataframe eviction, and the register_as_clash and register_as_too_large failure modes. The clash-on-repeat behavior even qualifies the idempotent annotation, which is honest disclosure rather than a contradiction.

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-loads the core action, then the prerequisite, then the gotchas, in a tight six-sentence block. Some material (row budget, name-clash repeat behavior) partly duplicates the rich schema, but almost every sentence gives the agent something actionable.

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 four-parameter SQL tool with an output schema, the description covers everything an agent needs: where tables come from, the describe-first step, type-mapping pitfalls, rejected SQL, and register_as lifecycle/limits. Return-value shape is correctly left to the output schema.

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

Parameters4/5

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

Schema coverage is 100%, so the schema already carries the parameter documentation and a 3 would be the floor. The description adds genuine semantics on top: register_as produces a materialized dataframe with a fresh TTL and unique-name requirement, and the CAST guidance shapes how the sql parameter must be written.

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 — running one read-only SELECT (DuckDB SQL) across df_<id> dataframes — and names the exact sibling tools that stage those dataframes (fdic_query_financials, fdic_get_deposits) plus fdic_dataframe_describe. An agent can distinguish this from the sibling query tools without opening the schema.

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

Usage Guidelines4/5

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

Gives a clear prerequisite workflow ('Before writing SQL, pass each table name to fdic_dataframe_describe') and states the exclusion boundary (writes, DDL, file-reading functions and system catalogs rejected). It is clear about context and sequence but never explicitly contrasts when to query a staged dataframe versus calling fdic_query_financials directly.

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.