Skip to main content
Glama

ilostat-mcp-server

Query staged ILOSTAT dataframes

ilostat_dataframe_query
Read-onlyIdempotent

Run a single-statement SELECT against the df_ dataframes staged by ilostat_query_indicator and ilostat_compare_geographies or stored by an earlier register_as. Inspect a dataframe with ilostat_dataframe_describe first; its column schema is what the SQL has to match. Read-only: writes, DDL, DROP, COPY, PRAGMA, ATTACH, file references, file-reading table functions, and functions that read engine settings or name a table from a string are rejected, and system catalogs (information_schema, pg_catalog, sqlite_master, duckdb_*) are denied. Breakdown versions overlap (AGE_YTHADULT_*, AGE_AGGREGATE_*, AGE_10YRBANDS_*), so filter to one version before summing. Optional register_as stores the result as a new dataframe with a fresh TTL.

Input Schema

NameRequiredDescriptionDefault
sqlYesOne SELECT over df_<id> tables (DuckDB SQL: joins, aggregates, window functions, CTEs), at most 20,000 characters. BIGINT results such as COUNT or SUM of integers serialize as strings; CAST to DOUBLE for inline arithmetic.
previewNoRows returned inline; defaults to row_limit, and a larger value is applied as row_limit. Inline rows also stop at a size budget (applied_limits.preview_chars). Set lower when register_as keeps the full result.
row_limitNoCap on rows materialized; defaults to 1,000, or the per-call cap when that is lower. The per-call cap is 10,000, or the lower cap the deployment sets; a larger value, up to 1,000,000, is applied as that cap. A query matching more stops at the cap and row_count_capped is true; register_as keeps the full result.
register_asNoStore the result as a new dataframe under this name (df_XXXXX_XXXXX: letters and digits, five in each part; stored uppercased after df_) with a fresh TTL, to chain analyses. A result over 1,000,000 rows is refused, and storing one can evict the oldest dataframes, which evicted names.

Output Schema

NameRequiredDescriptionDefault
capNoThe row cap that bound: preview when lower than row_limit, else row_limit.
rowsNoResult rows keyed by the names in columns, bounded by preview, row_limit, and an inline size budget; rows stop before the first that would pass the budget, and a value is never clipped. BIGINT values arrive as strings.
errorNoPresent when the call failed. Absent on success.
shownNoRows returned inline.
noticeNoGuidance when the query returned no rows, a cap withheld some, or a limit was applied below the value sent.
columnsNoColumn names in projection order.
evictedNoDataframes dropped, oldest first, to keep this tenant within 1,000,000 staged rows and 100 dataframes; present only when storing the result evicted any.
row_countNoRows the query produced. With register_as this is the exact count of the stored dataframe, which row_limit does not bound; otherwise at most row_limit, and when row_count_capped is true it is the cap, not a total.
truncatedNoTrue when a cap withheld rows from this response.
expires_atNoISO 8601 expiry of the new dataframe.
registered_asNoThe new dataframe name, when register_as stored the result.
applied_limitsNoThe limits this call ran under, after any clamp.
row_count_cappedNoTrue when the query matched more rows than row_limit; never true with register_as, which stores every row.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed10 schema fields changed
    • changedInput schema / properties / preview / description
      Previous value: -"Rows returned inline; defaults to row_limit. Set lower when register_as keeps the full result."New value: +"Rows returned inline; defaults to row_limit, and a larger value is applied as row_limit. Inline rows also stop at a size budget (applied_limits.preview_chars). Set lower when register_as keeps the full result."
    • changedInput schema / properties / preview / maximum
      Previous value: -10000New value: +9007199254740991
    • removedInput schema / properties / row_limit / default
      Removed value: -1000
    • changedInput schema / properties / row_limit / description
      Previous value: -"Hard cap on rows materialized (1–10,000). A query matching more stops at the cap and row_count_capped is true; register_as keeps the full result."New value: +"Cap on rows materialized; defaults to 1,000, or the per-call cap when that is lower. The per-call cap is 10,000, or the lower cap the deployment sets; a larger value, up to 1,000,000, is applied as that cap. A query matching more stops at the cap and row_count_capped is true; register_as keeps the full result."
    • changedInput schema / properties / row_limit / maximum
      Previous value: -10000New value: +1000000
    • addedOutput schema / properties / applied_limits
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "The limits this call ran under, after any clamp.",
      +  "properties": {
      +    "preview": {
      +      "description": "Inline rows applied: preview, at most the applied row_limit.",
      +      "type": "number"
      +    },
      +    "preview_chars": {
      +      "description": "Inline size budget applied, in characters; rows stop before the first that would pass it.",
      +      "type": "number"
      +    },
      +    "row_limit": {
      +      "description": "Row cap applied: row_limit (default 1,000), or the per-call cap when that is lower. With register_as it bounds the inline rows, never the stored result.",
      +      "type": "number"
      +    }
      +  },
      +  "required": [
      +    "row_limit",
      +    "preview",
      +    "preview_chars"
      +  ],
      +  "type": "object"
      +}
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: The DataCanvas DuckDB engine cannot load in this deployment. `system_catalog_access`: The SQL references a system catalog. `missing_table`: A referenced df_<id> does not exist or has expired. `invalid_sql`: The SELECT fails to prepare: an unknown column or an invalid expression. `sql_execution_error`: The SELECT prepared but failed on the data. `register_as_clash`: register_as names an existing dataframe. `register_as_too_large`: The register_as result holds more than 1,000,000 rows. `non_select_statement`: The SQL is not a SELECT. `multi_statement`: The SQL holds more than one statement, or a PIVOT with no IN list, which DuckDB expands into several. `denied_function`: The SQL calls a file-reading or external table function. `plan_operator_not_allowed`: The plan uses an operator outside the read-only allowlist, such as range(). 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 DuckDB engine cannot load in this deployment. `system_catalog_access`: The SQL references a system catalog. `missing_table`: A referenced df_<id> does not exist or has expired. `invalid_sql`: The SELECT fails to prepare: an unknown column or an invalid expression. `sql_execution_error`: The SELECT prepared but failed on the data. `register_as_clash`: register_as names an existing dataframe. `register_as_too_large`: The register_as result holds more than 1,000,000 rows. `non_select_statement`: The SQL is not a SELECT. `multi_statement`: The SQL holds more than one statement, or a PIVOT with no IN list, which DuckDB expands into several. `denied_function`: The SQL calls a file-reading or external table function, a function that reads engine settings (current_setting, current_schema), or one that runs SQL or names a table from a string (query_table, query() over anything but one string literal). `sql_read_only`: The SQL names a file in place of a table, or attempts a write the engine refuses. `plan_operator_not_allowed`: The plan uses an operator outside the read-only allowlist, such as range(). 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",
      -  "sql_execution_error",
      -  "register_as_clash",
      -  "register_as_too_large",
      -  "non_select_statement",
      -  "multi_statement",
      -  "denied_function",
      -  "plan_operator_not_allowed"
      -]New value: +[
      +  "canvas_unavailable",
      +  "system_catalog_access",
      +  "missing_table",
      +  "invalid_sql",
      +  "sql_execution_error",
      +  "register_as_clash",
      +  "register_as_too_large",
      +  "non_select_statement",
      +  "multi_statement",
      +  "denied_function",
      +  "sql_read_only",
      +  "plan_operator_not_allowed"
      +]
    • changedOutput schema / properties / notice / description
      Previous value: -"Guidance when the query returned no rows or a cap withheld some."New value: +"Guidance when the query returned no rows, a cap withheld some, or a limit was applied below the value sent."
    • changedOutput schema / properties / rows / description
      Previous value: -"Result rows keyed by the names in columns, bounded by preview and row_limit; BIGINT values arrive as strings."New value: +"Result rows keyed by the names in columns, bounded by preview, row_limit, and an inline size budget; rows stop before the first that would pass the budget, and a value is never clipped. BIGINT values arrive as strings."
  2. First observed

TDQS

A4.5/5.0
Behavior5/5

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

The description adds substantial behavioral context beyond the annotations: it lists rejected SQL operations, denied system catalogs, the read-only enforcement scope, and the overlap warning for breakdown versions. It also notes that register_as creates a new dataframe with a fresh TTL and that registration can evict older dataframes.

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?

The description is front-loaded with the core operation, then layers in the inspection prerequisite, read-only constraints, overlap warning, and register_as behavior without redundant restatement. Every sentence carries useful guidance for invoking the tool correctly.

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?

Given the query complexity, full schema coverage, output schema, and read-only annotations, the description supplies the remaining operational context: what is rejected, which catalogs are denied, when to inspect schema first, and how register_as enables chaining. Nothing an agent needs in order to call the tool correctly is missing.

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%, so the schema already documents all four parameters thoroughly. The description adds little parameter-specific meaning beyond what the schema provides, aside from briefly noting that register_as stores a new dataframe with a fresh TTL.

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?

The description states a specific verb and resource: running a single-statement SELECT against df_<id> dataframes. It distinguishes the tool from its siblings by identifying those dataframes as staged by ilostat_query_indicator and ilostat_compare_geographies or created by an earlier register_as.

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?

It clearly explains the context of use: query staged dataframes, inspect them first with ilostat_dataframe_describe, and optionally chain results with register_as. It does not explicitly state when to prefer this over querying raw indicators directly, so it falls just short of a full when/when-not/alternatives statement.

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.