Skip to main content
Glama

eia-energy-mcp-server

Query EIA Route Data

eia_query_route
Read-only

Fetches data from a leaf route with optional facet filters, date range, frequency, and column selection. Use eia_describe_route first to discover valid facet IDs, facet values, column IDs, and frequency codes. Data values are strings in the response (EIA API returns all numeric values as strings, e.g. "9.13"); cast to DOUBLE in SQL when arithmetic is needed. Returns a preview inline and stages nothing by default — one upstream request, whatever total says. Pass stage: true to also page past the preview and stage the accumulated set as a DataCanvas table, then pass the returned dataset name to eia_dataframe_describe for its column names and eia_dataframe_query for SQL. Every dataset a tenant stages lands in the same canvas, so tables from different routes cross-join by name with nothing to thread between calls.

Input Schema

NameRequiredDescriptionDefault
endNoPeriod end, read the same way as start: a coarser end selects only its first period, so "2020" ends at 2020-01 at monthly — use "2020-12" to include the whole year. At hourly a date-only end covers its whole day.
sortNoResult ordering.
routeYesLeaf route path (e.g. "electricity/retail-sales", "steo"). Discoverable via eia_browse_routes or eia_search_routes. Whitespace and slashes are normalized, then one complete leading v2 segment is removed: "/v2/electricity/retail-sales/" resolves to "electricity/retail-sales". Full URLs and /data suffixes are not normalized.
stageNoStage the matching rows as a DataCanvas table for SQL (default false). Off, the call makes one upstream request and returns the preview alone. On, the service pages past the preview up to the staging row cap this server sets and registers the accumulated rows, starting at offset, returning the handle in dataset — several extra upstream requests and seconds of latency on a large route, so turn it on when moving to analysis, not while exploring. Requires the server to have a canvas, which it does unless its operator turned it off; without one nothing is staged whatever this is set to.
startNoPeriod start in the route date format (e.g. "2020-01" for monthly, "2020" for annual). Format from eia_describe_route. EIA reads a bound as the period of the effective frequency containing its first day, so a coarser bound selects that one period ("2020" is 2020-01 at monthly, "2020-Q4" is 2020-10). At local-hourly every bound needs its hour and UTC offset (YYYY-MM-DDTHH±HH, e.g. "2024-02-01T02-06").
lengthNoRows per page. Default 25; a larger value returns at most 5,000 and says so. With stage: true, staging is not bounded by this — it pages past the page on its own.
offsetNoRow offset into the matching set (default 0). An offset at or beyond total returns zero rows.
columnsNoData column IDs to return (reduces payload). Defaults to all. IDs discoverable via eia_describe_route data_columns[].id. Every row also carries period and each facet ID whatever this lists, so naming those here is unnecessary and they are dropped from the request.
filtersNoFacet filters keyed by facet ID (e.g. { "stateid": "TX", "sectorid": ["RES", "COM"] }). Use the facets[].id values returned by eia_describe_route as keys here. Every value travels in the request URI, which EIA caps at about 8 KB — a few hundred values across all filters; split a longer list across calls.
frequencyNoAggregation frequency ID (e.g. "monthly", "annual"). Defaults to route default. Valid IDs from eia_describe_route.

Output Schema

NameRequiredDescriptionDefault
dataNoInline rows: the length rows from offset, fewer only at the end of the matching set. All numeric values are strings per the EIA API (e.g. "9.13"). Cast to DOUBLE in SQL for arithmetic: CAST(value AS DOUBLE). Per-column units appear as {col}-units fields inline in each row. Keys are dynamic column IDs from the EIA route.
errorNoPresent when the call failed. Absent on success.
routeNoThe canonical route path queried: whitespace/slashes normalized and one complete leading v2 segment removed. Reusable verbatim in a follow-up call.
totalNoTotal matching rows in the EIA dataset for this query (may exceed returned rows when pagination or spillover applies).
noticeNoComposed guidance for empty results or an offset past total, unmatched filter values in complete cached vocabularies, year-only bounds on effective monthly YYYY-MM data, and requested/effective length when clamped. Submitted filters and date bounds are preserved.
datasetNodf_<id> handle for the staged rows — eia_dataframe_describe lists its column names; eia_dataframe_query runs SQL over it (SELECT … FROM df_<id>). Present only when a stage: true call registered a table on a deployment with a canvas configured; absent otherwise, since nothing was staged. Every dataset a tenant stages shares one canvas, so handles from different routes join directly.
frequencyNoFrequency of the returned data.
appliedEndNoEcho of the end period as applied, when an end was provided.
totalCountNoTotal matching rows in the EIA dataset.
appliedSortNoEcho of the result ordering as applied, when a sort was provided — the ordering that decided which rows a capped stage holds.
date_formatNoPeriod format for the returned data (e.g. "YYYY-MM").
next_offsetNoOffset that continues right after the rows in data (offset + returned_count) — pass it as offset for the next page, with no gap or overlap. Present whenever rows remain past this page; absent on the last page.
appliedStartNoEcho of the start period as applied, when a start was provided.
appliedLengthNoRows per page applied to this call — length, after any clamp.
appliedOffsetNoRow offset applied to the query — the cause when a page comes back empty.
returnedCountNoRows in this response. When returnedCount < totalCount, continue at next_offset or stage the rest.
appliedColumnsNoEcho of the column projection as sent to EIA, when columns named at least one data column — period and facet IDs, which every row carries anyway, are not part of it.
appliedFiltersNoFacet filters applied to the query, when provided.
effectiveRouteNoThe route path that was queried.
returned_countNoNumber of rows in data. When returned_count < total, continue at next_offset or stage the rest for SQL.
appliedFrequencyNoEcho of the frequency as applied, when a frequency was provided.
truncation_warningNoUpstream advisories forwarded verbatim from EIA's warnings[], joined with '; ' when more than one applies. These describe the inline page — EIA's "incomplete return" entry fires whenever the requested length is under total, at any size — not a 5,000-row ceiling on this response. Absent when the response already accounts for the gap the advisory names (the staged table reaches the last row, notice explains the empty page, or canvas_preview_note places the inline page against total because nothing was staged).
canvas_preview_noteNoHuman-readable note, present whenever dataset is set or staging failed, and otherwise when total exceeds the inline rows. On a stage: true call it opens with the stage outcome: the staged row count and dataset name, naming eia_dataframe_describe for the staged column names (quoting one rename when staging renamed a column) and then eia_dataframe_query for SQL — or, when the canvas failed, that no dataframe was created (dataset is then absent), with the retry — from offset 0 past the first page — and, while rows remain, offset paging. Next, where in the matching set the staged rows sit whenever the stage does not start at row 1, and when staging stopped short of total (the staging row cap this server sets, the time limit of the call, or an upstream page that did not return) the offset to resume from; last, the row range of the inline page (e.g. rows 21–30 of 55), whether it is the last page, and next_offset — and, after a registered stage, that the inline rows page with stage left off, since another stage: true call stages a new table. Where staging was not requested it names the row range of the inline page, says when it is the last page, and names stage: true and eia_dataframe_query as the way to get SQL access to the matching rows — with offset 0 past the first page, since a stage starts at offset — and offset paging while rows remain; where this server has no canvas, it says staging is unavailable on this deployment and, while rows remain, names offset paging instead.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changed
    • changedInput schema / properties / stage / description
      Previous value: -"Stage the matching rows as a DataCanvas table for SQL (default false). Off, the call makes one upstream request and returns the preview alone. On, the service pages past the preview up to EIA_CANVAS_MAX_ROWS and registers the accumulated rows, returning the handle in dataset — several extra upstream requests and seconds of latency on a large route, so turn it on when moving to analysis, not while exploring. Requires a canvas, which is on unless the server sets CANVAS_PROVIDER_TYPE=none; without one nothing is staged whatever this is set to."New value: +"Stage the matching rows as a DataCanvas table for SQL (default false). Off, the call makes one upstream request and returns the preview alone. On, the service pages past the preview up to the staging row cap this server sets and registers the accumulated rows, starting at offset, returning the handle in dataset — several extra upstream requests and seconds of latency on a large route, so turn it on when moving to analysis, not while exploring. Requires the server to have a canvas, which it does unless its operator turned it off; without one nothing is staged whatever this is set to."
    • changedOutput schema / properties / canvas_preview_note / description
      Previous value: -"Human-readable note, present whenever dataset is set or staging failed, and otherwise when total exceeds the inline rows. On a stage: true call it opens with the stage outcome: the staged row count and dataset name, naming eia_dataframe_describe for the staged column names (quoting one rename when staging renamed a column) and then eia_dataframe_query for SQL — or, when the canvas failed, that no dataframe was created (dataset is then absent), with the retry and offset paging. Next, where in the matching set the staged rows sit whenever the stage does not start at row 1, and when staging stopped short of total (the EIA_CANVAS_MAX_ROWS cap, the time limit of the call, or an upstream page that did not return) the offset to resume from; last, the inline page against total and next_offset — and, after a registered stage, that the inline rows page with stage left off, since another stage: true call stages a new table. Where staging was not requested it places the inline page against total and names stage: true and eia_dataframe_query as the way to get SQL access to the rest; where no canvas is configured at all, staging is unavailable, so it names offset paging and CANVAS_PROVIDER_TYPE=duckdb instead."New value: +"Human-readable note, present whenever dataset is set or staging failed, and otherwise when total exceeds the inline rows. On a stage: true call it opens with the stage outcome: the staged row count and dataset name, naming eia_dataframe_describe for the staged column names (quoting one rename when staging renamed a column) and then eia_dataframe_query for SQL — or, when the canvas failed, that no dataframe was created (dataset is then absent), with the retry — from offset 0 past the first page — and, while rows remain, offset paging. Next, where in the matching set the staged rows sit whenever the stage does not start at row 1, and when staging stopped short of total (the staging row cap this server sets, the time limit of the call, or an upstream page that did not return) the offset to resume from; last, the row range of the inline page (e.g. rows 21–30 of 55), whether it is the last page, and next_offset — and, after a registered stage, that the inline rows page with stage left off, since another stage: true call stages a new table. Where staging was not requested it names the row range of the inline page, says when it is the last page, and names stage: true and eia_dataframe_query as the way to get SQL access to the matching rows — with offset 0 past the first page, since a stage starts at offset — and offset paging while rows remain; where this server has no canvas, it says staging is unavailable on this deployment and, while rows remain, names offset paging instead."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `upstream_invalid_response`: EIA returned an unusable response body or a missing route or data envelope. `upstream_unavailable`: EIA answered with a retryable HTTP service failure. `upstream_timeout`: EIA did not answer in time: one attempt passed 45 s, or the call passed its 56 s deadline across retries. Staging that runs out of time ends early instead, keeping the rows already staged. `route_not_found`: Route does not exist in the EIA taxonomy. `route_not_queryable`: Route is a category node with sub-routes, not a queryable leaf. `invalid_facet`: An unknown facet key was used in filters. `invalid_column`: An unknown data column ID was passed in columns. `invalid_frequency`: An unknown frequency code was passed. `invalid_sort`: A sort entry named a column the route does not sort by. `invalid_period`: start or end was not in a period format the route accepts, named a month, day, or hour that does not exist in the period shape its frequency reads exactly (YYYY-MM-DD at daily or weekly, YYYY-MM-DDTHH at hourly, YYYY-MM-DDTHH±HH at local-hourly), or lacked its UTC offset at local-hourly frequency. `uri_too_long`: The request URI passed the EIA limit of about 8 KB (HTTP 414) — typically a filter list of several hundred values. `no_data`: EIA returned no rows and start selects a later period than end at the effective frequency (the range is inverted). `rate_limited`: EIA rate limit hit (OVER_RATE_LIMIT). `upstream_unreachable`: EIA could not be reached (connection refused or reset, DNS failure) on the data request, the route metadata request, or the route-tree build. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `upstream_invalid_response`: EIA returned an unusable response body or a missing route or data envelope. `upstream_unavailable`: EIA answered with a retryable HTTP service failure. `upstream_timeout`: EIA did not answer in time: one attempt passed 45 s, or the call passed its 56 s deadline across retries. Staging that runs out of time ends early instead, keeping the rows already staged. `route_not_found`: Route does not exist in the EIA taxonomy. `route_not_queryable`: Route is a category node with sub-routes, not a queryable leaf. `invalid_facet`: An unknown facet key was used in filters. `invalid_column`: An unknown data column ID was passed in columns. `invalid_frequency`: An unknown frequency code was passed. `invalid_sort`: A sort entry named a column the route does not sort by. `invalid_period`: start or end was not in a period format the route accepts; named a month outside 01–12 or an hour that is not two digits; named a day its month lacks or an hour 24–99 that rolls the bound into another period at the chosen frequency (any such day or hour at daily, hourly, and local-hourly, and any such day at weekly and four-week-average); or lacked its UTC offset at local-hourly frequency. `uri_too_long`: The request URI passed the EIA limit of about 8 KB (HTTP 414) — typically a filter list of several hundred values. `no_data`: EIA returned no rows and start selects a later period than end at the effective frequency (the range is inverted). `rate_limited`: EIA rate limit hit (OVER_RATE_LIMIT). `upstream_unreachable`: EIA could not be reached (connection refused or reset, DNS failure) on the data request, the route metadata request, or the route-tree build. Other values are possible when a failure originates below the handler."
  2. Changed10 schema fields changed
    • changedInput schema / properties / length / default
      Previous value: -100New value: +25
    • changedInput schema / properties / length / description
      Previous value: -"Rows to fetch for the inline page (default 100; larger integers are clamped to 5000 with a notice). Every fetched row is used, but the response carries only as many as fit a 64,000-byte budget per surface — wide routes end the page early, said so in canvas_preview_note, with next_offset naming where to continue. With stage: true, staging is not bounded by this — it pages past the preview on its own."New value: +"Rows per page. Default 25; a larger value returns at most 5,000 and says so. With stage: true, staging is not bounded by this — it pages past the page on its own."
    • removedInput schema / properties / length / maximum
      Removed value: -9007199254740991
    • addedInput schema / properties / length / multipleOf
      Added value: +1
    • changedInput schema / properties / length / type
      Previous value: -"integer"New value: +"number"
    • changedOutput schema / properties / appliedFilters / description
      Previous value: -"Facet filters applied to the query, when provided. Past 4,000 bytes the echo keeps the leading values and adds a \"…\" entry counting those not echoed per facet — every value was still applied."New value: +"Facet filters applied to the query, when provided."
    • changedOutput schema / properties / appliedLength / description
      Previous value: -"Preview row count requested for this call."New value: +"Rows per page applied to this call — length, after any clamp."
    • changedOutput schema / properties / canvas_preview_note / description
      Previous value: -"Human-readable note, present whenever dataset is set or staging failed, and otherwise when total exceeds the inline rows. On a stage: true call it opens with the stage outcome: the staged row count and dataset name, naming eia_dataframe_describe for the staged column names (quoting one rename when staging renamed a column) and then eia_dataframe_query for SQL — or, when the canvas failed, that no dataframe was created (dataset is then absent), with the retry and offset paging. Next, where in the matching set the staged rows sit whenever the stage does not start at row 1, and when staging stopped short of total (the EIA_CANVAS_MAX_ROWS cap, the time limit of the call, or an upstream page that did not return) the offset to resume from; last, the inline page against total and next_offset — saying when the 64,000-byte response budget rather than length ended the page, or that a single row too large for the budget was withheld and offset + 1 steps past it — and, after a registered stage, that the inline rows page with stage left off, since another stage: true call stages a new table. Where staging was not requested it places the inline page against total and names stage: true and eia_dataframe_query as the way to get SQL access to the rest; where no canvas is configured at all, staging is unavailable, so it names offset paging and CANVAS_PROVIDER_TYPE=duckdb instead."New value: +"Human-readable note, present whenever dataset is set or staging failed, and otherwise when total exceeds the inline rows. On a stage: true call it opens with the stage outcome: the staged row count and dataset name, naming eia_dataframe_describe for the staged column names (quoting one rename when staging renamed a column) and then eia_dataframe_query for SQL — or, when the canvas failed, that no dataframe was created (dataset is then absent), with the retry and offset paging. Next, where in the matching set the staged rows sit whenever the stage does not start at row 1, and when staging stopped short of total (the EIA_CANVAS_MAX_ROWS cap, the time limit of the call, or an upstream page that did not return) the offset to resume from; last, the inline page against total and next_offset — and, after a registered stage, that the inline rows page with stage left off, since another stage: true call stages a new table. Where staging was not requested it places the inline page against total and names stage: true and eia_dataframe_query as the way to get SQL access to the rest; where no canvas is configured at all, staging is unavailable, so it names offset paging and CANVAS_PROVIDER_TYPE=duckdb instead."
    • changedOutput schema / properties / data / description
      Previous value: -"Inline rows: the first length rows from offset, ended early when the next whole row would push either response surface past the 64,000-byte budget. All numeric values are strings per the EIA API (e.g. \"9.13\"). Cast to DOUBLE in SQL for arithmetic: CAST(value AS DOUBLE). Per-column units appear as {col}-units fields inline in each row. Keys are dynamic column IDs from the EIA route."New value: +"Inline rows: the length rows from offset, fewer only at the end of the matching set. All numeric values are strings per the EIA API (e.g. \"9.13\"). Cast to DOUBLE in SQL for arithmetic: CAST(value AS DOUBLE). Per-column units appear as {col}-units fields inline in each row. Keys are dynamic column IDs from the EIA route."
    • changedOutput schema / properties / notice / description
      Previous value: -"Composed guidance for empty results or an offset past total, unmatched filter values in complete cached vocabularies, year-only bounds on effective monthly YYYY-MM data, and requested/effective length when clamped. Submitted filters and date bounds are preserved. A row withheld by the response byte budget is explained in canvas_preview_note."New value: +"Composed guidance for empty results or an offset past total, unmatched filter values in complete cached vocabularies, year-only bounds on effective monthly YYYY-MM data, and requested/effective length when clamped. Submitted filters and date bounds are preserved."
  3. Changed5 schema fields changed
    • changedInput schema / properties / end / description
      Previous value: -"Period end (same format as start)."New value: +"Period end, read the same way as start: a coarser end selects only its first period, so \"2020\" ends at 2020-01 at monthly — use \"2020-12\" to include the whole year. At hourly a date-only end covers its whole day."
    • changedInput schema / properties / start / description
      Previous value: -"Period start in the route date format (e.g. \"2020-01\" for monthly, \"2020\" for annual). Format from eia_describe_route."New value: +"Period start in the route date format (e.g. \"2020-01\" for monthly, \"2020\" for annual). Format from eia_describe_route. EIA reads a bound as the period of the effective frequency containing its first day, so a coarser bound selects that one period (\"2020\" is 2020-01 at monthly, \"2020-Q4\" is 2020-10). At local-hourly every bound needs its hour and UTC offset (YYYY-MM-DDTHH±HH, e.g. \"2024-02-01T02-06\")."
    • changedOutput schema / properties / canvas_preview_note / description
      Previous value: -"Human-readable note, present whenever dataset is set or staging failed, and otherwise when total exceeds the inline rows. On a stage: true call it opens with the stage outcome: the staged row count and dataset name, naming eia_dataframe_describe for the staged column names (quoting one rename when staging renamed a column) and then eia_dataframe_query for SQL — or, when the canvas failed, that no dataframe was created (dataset is then absent), with the retry and offset paging. Next, where in the matching set the staged rows sit whenever the stage does not start at row 1, and when staging stopped short of total (the EIA_CANVAS_MAX_ROWS cap, or an upstream page that did not return) the offset to resume from; last, the inline page against total and next_offset — saying when the 64,000-byte response budget rather than length ended the page, or that a single row too large for the budget was withheld and offset + 1 steps past it — and, after a registered stage, that the inline rows page with stage left off, since another stage: true call stages a new table. Where staging was not requested it places the inline page against total and names stage: true and eia_dataframe_query as the way to get SQL access to the rest; where no canvas is configured at all, staging is unavailable, so it names offset paging and CANVAS_PROVIDER_TYPE=duckdb instead."New value: +"Human-readable note, present whenever dataset is set or staging failed, and otherwise when total exceeds the inline rows. On a stage: true call it opens with the stage outcome: the staged row count and dataset name, naming eia_dataframe_describe for the staged column names (quoting one rename when staging renamed a column) and then eia_dataframe_query for SQL — or, when the canvas failed, that no dataframe was created (dataset is then absent), with the retry and offset paging. Next, where in the matching set the staged rows sit whenever the stage does not start at row 1, and when staging stopped short of total (the EIA_CANVAS_MAX_ROWS cap, the time limit of the call, or an upstream page that did not return) the offset to resume from; last, the inline page against total and next_offset — saying when the 64,000-byte response budget rather than length ended the page, or that a single row too large for the budget was withheld and offset + 1 steps past it — and, after a registered stage, that the inline rows page with stage left off, since another stage: true call stages a new table. Where staging was not requested it places the inline page against total and names stage: true and eia_dataframe_query as the way to get SQL access to the rest; where no canvas is configured at all, staging is unavailable, so it names offset paging and CANVAS_PROVIDER_TYPE=duckdb instead."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `upstream_invalid_response`: EIA returned an unusable response body or a missing route or data envelope. `upstream_unavailable`: EIA answered with a retryable HTTP service failure. `route_not_found`: Route does not exist in the EIA taxonomy. `route_not_queryable`: Route is a category node with sub-routes, not a queryable leaf. `invalid_facet`: An unknown facet key was used in filters. `invalid_column`: An unknown data column ID was passed in columns. `invalid_frequency`: An unknown frequency code was passed. `invalid_sort`: A sort entry named a column the route does not sort by. `invalid_period`: start or end was not in a period format the route accepts. `uri_too_long`: The request URI passed the EIA limit of about 8 KB (HTTP 414) — typically a filter list of several hundred values. `no_data`: Date range is inverted (start is after end). `rate_limited`: EIA rate limit hit (OVER_RATE_LIMIT). `upstream_unreachable`: EIA could not be reached (connection refused or reset, DNS failure) on the data request, the route metadata request, or the route-tree build. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `upstream_invalid_response`: EIA returned an unusable response body or a missing route or data envelope. `upstream_unavailable`: EIA answered with a retryable HTTP service failure. `upstream_timeout`: EIA did not answer in time: one attempt passed 45 s, or the call passed its 56 s deadline across retries. Staging that runs out of time ends early instead, keeping the rows already staged. `route_not_found`: Route does not exist in the EIA taxonomy. `route_not_queryable`: Route is a category node with sub-routes, not a queryable leaf. `invalid_facet`: An unknown facet key was used in filters. `invalid_column`: An unknown data column ID was passed in columns. `invalid_frequency`: An unknown frequency code was passed. `invalid_sort`: A sort entry named a column the route does not sort by. `invalid_period`: start or end was not in a period format the route accepts, named a month, day, or hour that does not exist in the period shape its frequency reads exactly (YYYY-MM-DD at daily or weekly, YYYY-MM-DDTHH at hourly, YYYY-MM-DDTHH±HH at local-hourly), or lacked its UTC offset at local-hourly frequency. `uri_too_long`: The request URI passed the EIA limit of about 8 KB (HTTP 414) — typically a filter list of several hundred values. `no_data`: EIA returned no rows and start selects a later period than end at the effective frequency (the range is inverted). `rate_limited`: EIA rate limit hit (OVER_RATE_LIMIT). `upstream_unreachable`: EIA could not be reached (connection refused or reset, DNS failure) on the data request, the route metadata request, or the route-tree build. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / error / properties / data / properties / reason / examples
      Previous value: -[
      -  "upstream_invalid_response",
      -  "upstream_unavailable",
      -  "route_not_found",
      -  "route_not_queryable",
      -  "invalid_facet",
      -  "invalid_column",
      -  "invalid_frequency",
      -  "invalid_sort",
      -  "invalid_period",
      -  "uri_too_long",
      -  "no_data",
      -  "rate_limited",
      -  "upstream_unreachable"
      -]New value: +[
      +  "upstream_invalid_response",
      +  "upstream_unavailable",
      +  "upstream_timeout",
      +  "route_not_found",
      +  "route_not_queryable",
      +  "invalid_facet",
      +  "invalid_column",
      +  "invalid_frequency",
      +  "invalid_sort",
      +  "invalid_period",
      +  "uri_too_long",
      +  "no_data",
      +  "rate_limited",
      +  "upstream_unreachable"
      +]
  4. Changed8 schema fields changed
    • changedInput schema / properties / length / description
      Previous value: -"Rows to fetch for the inline page (default 100, max 5000 per EIA limit). Every fetched row is used, but the response carries only as many as fit a 64,000-byte budget per surface — wide routes end the page early, said so in canvas_preview_note, with next_offset naming where to continue. With stage: true, staging is not bounded by this — it pages past the preview on its own."New value: +"Rows to fetch for the inline page (default 100; larger integers are clamped to 5000 with a notice). Every fetched row is used, but the response carries only as many as fit a 64,000-byte budget per surface — wide routes end the page early, said so in canvas_preview_note, with next_offset naming where to continue. With stage: true, staging is not bounded by this — it pages past the preview on its own."
    • changedInput schema / properties / length / maximum
      Previous value: -5000New value: +9007199254740991
    • changedInput schema / properties / route / description
      Previous value: -"Leaf route path (e.g. \"electricity/retail-sales\", \"steo\"). Discoverable via eia_browse_routes or eia_search_routes. Leading, trailing, and doubled slashes are stripped, so an EIA-doc spelling like \"/electricity/retail-sales/\" resolves to the same route."New value: +"Leaf route path (e.g. \"electricity/retail-sales\", \"steo\"). Discoverable via eia_browse_routes or eia_search_routes. Whitespace and slashes are normalized, then one complete leading v2 segment is removed: \"/v2/electricity/retail-sales/\" resolves to \"electricity/retail-sales\". Full URLs and /data suffixes are not normalized."
    • changedInput schema / properties / stage / description
      Previous value: -"Stage the matching rows as a DataCanvas table for SQL (default false). Off, the call makes one upstream request and returns the preview alone. On, the service pages past the preview up to EIA_CANVAS_MAX_ROWS and registers the accumulated rows, returning the handle in dataset — several extra upstream requests and seconds of latency on a large route, so turn it on when moving to analysis, not while exploring. Requires a canvas (CANVAS_PROVIDER_TYPE=duckdb); without one nothing is staged whatever this is set to."New value: +"Stage the matching rows as a DataCanvas table for SQL (default false). Off, the call makes one upstream request and returns the preview alone. On, the service pages past the preview up to EIA_CANVAS_MAX_ROWS and registers the accumulated rows, returning the handle in dataset — several extra upstream requests and seconds of latency on a large route, so turn it on when moving to analysis, not while exploring. Requires a canvas, which is on unless the server sets CANVAS_PROVIDER_TYPE=none; without one nothing is staged whatever this is set to."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `route_not_found`: Route does not exist in the EIA taxonomy. `route_not_queryable`: Route is a category node with sub-routes, not a queryable leaf. `invalid_facet`: An unknown facet key was used in filters. `invalid_column`: An unknown data column ID was passed in columns. `invalid_frequency`: An unknown frequency code was passed. `invalid_sort`: A sort entry named a column the route does not sort by. `invalid_period`: start or end was not in a period format the route accepts. `uri_too_long`: The request URI passed the EIA limit of about 8 KB (HTTP 414) — typically a filter list of several hundred values. `no_data`: Date range is inverted (start is after end). `rate_limited`: EIA rate limit hit (OVER_RATE_LIMIT). `upstream_unreachable`: EIA could not be reached (connection refused or reset, DNS failure) on the data request, the route metadata request, or the route-tree build. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `upstream_invalid_response`: EIA returned an unusable response body or a missing route or data envelope. `upstream_unavailable`: EIA answered with a retryable HTTP service failure. `route_not_found`: Route does not exist in the EIA taxonomy. `route_not_queryable`: Route is a category node with sub-routes, not a queryable leaf. `invalid_facet`: An unknown facet key was used in filters. `invalid_column`: An unknown data column ID was passed in columns. `invalid_frequency`: An unknown frequency code was passed. `invalid_sort`: A sort entry named a column the route does not sort by. `invalid_period`: start or end was not in a period format the route accepts. `uri_too_long`: The request URI passed the EIA limit of about 8 KB (HTTP 414) — typically a filter list of several hundred values. `no_data`: Date range is inverted (start is after end). `rate_limited`: EIA rate limit hit (OVER_RATE_LIMIT). `upstream_unreachable`: EIA could not be reached (connection refused or reset, DNS failure) on the data request, the route metadata request, or the route-tree build. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / error / properties / data / properties / reason / examples
      Previous value: -[
      -  "route_not_found",
      -  "route_not_queryable",
      -  "invalid_facet",
      -  "invalid_column",
      -  "invalid_frequency",
      -  "invalid_sort",
      -  "invalid_period",
      -  "uri_too_long",
      -  "no_data",
      -  "rate_limited",
      -  "upstream_unreachable"
      -]New value: +[
      +  "upstream_invalid_response",
      +  "upstream_unavailable",
      +  "route_not_found",
      +  "route_not_queryable",
      +  "invalid_facet",
      +  "invalid_column",
      +  "invalid_frequency",
      +  "invalid_sort",
      +  "invalid_period",
      +  "uri_too_long",
      +  "no_data",
      +  "rate_limited",
      +  "upstream_unreachable"
      +]
    • changedOutput schema / properties / notice / description
      Previous value: -"Informational message when EIA returned no rows — either zero rows matched the filters (broaden the query) or offset paged past the last row (reduce offset below total). A page left empty because its first row alone exceeds the response budget carries no notice; canvas_preview_note names the offset that skips it."New value: +"Composed guidance for empty results or an offset past total, unmatched filter values in complete cached vocabularies, year-only bounds on effective monthly YYYY-MM data, and requested/effective length when clamped. Submitted filters and date bounds are preserved. A row withheld by the response byte budget is explained in canvas_preview_note."
    • changedOutput schema / properties / route / description
      Previous value: -"The route path queried, in canonical spelling — any leading, trailing, or doubled slashes the input carried are stripped. Reusable verbatim in a follow-up call."New value: +"The canonical route path queried: whitespace/slashes normalized and one complete leading v2 segment removed. Reusable verbatim in a follow-up call."
  5. Changed14 schema fields changed
    • changedInput schema / properties / columns / description
      Previous value: -"Data column IDs to return (reduces payload). Defaults to all. IDs discoverable via eia_describe_route."New value: +"Data column IDs to return (reduces payload). Defaults to all. IDs discoverable via eia_describe_route data_columns[].id. Every row also carries period and each facet ID whatever this lists, so naming those here is unnecessary and they are dropped from the request."
    • changedInput schema / properties / filters / description
      Previous value: -"Facet filters keyed by facet ID (e.g. { \"stateid\": \"TX\", \"sectorid\": [\"RES\", \"COM\"] }). Use the facets[].id values returned by eia_describe_route as keys here."New value: +"Facet filters keyed by facet ID (e.g. { \"stateid\": \"TX\", \"sectorid\": [\"RES\", \"COM\"] }). Use the facets[].id values returned by eia_describe_route as keys here. Every value travels in the request URI, which EIA caps at about 8 KB — a few hundred values across all filters; split a longer list across calls."
    • changedInput schema / properties / length / description
      Previous value: -"Rows in the inline preview (default 100, max 5000 per EIA limit). With stage: true, staging is not bounded by this — it pages past the preview on its own."New value: +"Rows to fetch for the inline page (default 100, max 5000 per EIA limit). Every fetched row is used, but the response carries only as many as fit a 64,000-byte budget per surface — wide routes end the page early, said so in canvas_preview_note, with next_offset naming where to continue. With stage: true, staging is not bounded by this — it pages past the preview on its own."
    • changedOutput schema / properties / appliedColumns / description
      Previous value: -"Echo of the column projection as applied, when columns were provided."New value: +"Echo of the column projection as sent to EIA, when columns named at least one data column — period and facet IDs, which every row carries anyway, are not part of it."
    • changedOutput schema / properties / appliedFilters / description
      Previous value: -"Facet filters applied to the query, when provided."New value: +"Facet filters applied to the query, when provided. Past 4,000 bytes the echo keeps the leading values and adds a \"…\" entry counting those not echoed per facet — every value was still applied."
    • changedOutput schema / properties / canvas_preview_note / description
      Previous value: -"Human-readable note when total exceeds the inline preview. On a stage: true call it names how many rows actually reached the canvas table, and where in the matching set those rows sit whenever the stage does not start at row 1; when staging also stopped short of total (the EIA_CANVAS_MAX_ROWS cap, or an upstream page that did not return), it says so and gives the offset to resume from. Where staging was not requested it places the inline page against total and names stage: true as the way to get SQL access to the rest; where no canvas is configured at all, staging is unavailable, so it names offset paging and CANVAS_PROVIDER_TYPE=duckdb instead."New value: +"Human-readable note, present whenever dataset is set or staging failed, and otherwise when total exceeds the inline rows. On a stage: true call it opens with the stage outcome: the staged row count and dataset name, naming eia_dataframe_describe for the staged column names (quoting one rename when staging renamed a column) and then eia_dataframe_query for SQL — or, when the canvas failed, that no dataframe was created (dataset is then absent), with the retry and offset paging. Next, where in the matching set the staged rows sit whenever the stage does not start at row 1, and when staging stopped short of total (the EIA_CANVAS_MAX_ROWS cap, or an upstream page that did not return) the offset to resume from; last, the inline page against total and next_offset — saying when the 64,000-byte response budget rather than length ended the page, or that a single row too large for the budget was withheld and offset + 1 steps past it — and, after a registered stage, that the inline rows page with stage left off, since another stage: true call stages a new table. Where staging was not requested it places the inline page against total and names stage: true and eia_dataframe_query as the way to get SQL access to the rest; where no canvas is configured at all, staging is unavailable, so it names offset paging and CANVAS_PROVIDER_TYPE=duckdb instead."
    • changedOutput schema / properties / data / description
      Previous value: -"Preview rows. All numeric values are strings per the EIA API (e.g. \"9.13\"). Cast to DOUBLE in SQL for arithmetic: CAST(value AS DOUBLE). Per-column units appear as {col}-units fields inline in each row. Keys are dynamic column IDs from the EIA route."New value: +"Inline rows: the first length rows from offset, ended early when the next whole row would push either response surface past the 64,000-byte budget. All numeric values are strings per the EIA API (e.g. \"9.13\"). Cast to DOUBLE in SQL for arithmetic: CAST(value AS DOUBLE). Per-column units appear as {col}-units fields inline in each row. Keys are dynamic column IDs from the EIA route."
    • changedOutput schema / properties / dataset / description
      Previous value: -"df_<id> table handle for the registered dataset — pass directly to eia_dataframe_query SQL (SELECT ... FROM df_<id>). Present only on a stage: true call against a deployment with a canvas configured; absent otherwise, since nothing was staged. Every dataset a tenant stages shares one canvas, so handles from different routes join directly."New value: +"df_<id> handle for the staged rows — eia_dataframe_describe lists its column names; eia_dataframe_query runs SQL over it (SELECT … FROM df_<id>). Present only when a stage: true call registered a table on a deployment with a canvas configured; absent otherwise, since nothing was staged. Every dataset a tenant stages shares one canvas, so handles from different routes join directly."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `route_not_found`: Route does not exist in the EIA taxonomy. `route_not_queryable`: Route is a category node with sub-routes, not a queryable leaf. `invalid_facet`: An unknown facet key was used in filters. `invalid_column`: An unknown data column ID was passed in columns. `invalid_frequency`: An unknown frequency code was passed. `invalid_sort`: A sort entry named a column the route does not sort by. `invalid_period`: start or end was not in a period format the route accepts. `no_data`: Date range is inverted (start is after end). `rate_limited`: EIA rate limit hit (OVER_RATE_LIMIT). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `route_not_found`: Route does not exist in the EIA taxonomy. `route_not_queryable`: Route is a category node with sub-routes, not a queryable leaf. `invalid_facet`: An unknown facet key was used in filters. `invalid_column`: An unknown data column ID was passed in columns. `invalid_frequency`: An unknown frequency code was passed. `invalid_sort`: A sort entry named a column the route does not sort by. `invalid_period`: start or end was not in a period format the route accepts. `uri_too_long`: The request URI passed the EIA limit of about 8 KB (HTTP 414) — typically a filter list of several hundred values. `no_data`: Date range is inverted (start is after end). `rate_limited`: EIA rate limit hit (OVER_RATE_LIMIT). `upstream_unreachable`: EIA could not be reached (connection refused or reset, DNS failure) on the data request, the route metadata request, or the route-tree build. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / error / properties / data / properties / reason / examples
      Previous value: -[
      -  "route_not_found",
      -  "route_not_queryable",
      -  "invalid_facet",
      -  "invalid_column",
      -  "invalid_frequency",
      -  "invalid_sort",
      -  "invalid_period",
      -  "no_data",
      -  "rate_limited"
      -]New value: +[
      +  "route_not_found",
      +  "route_not_queryable",
      +  "invalid_facet",
      +  "invalid_column",
      +  "invalid_frequency",
      +  "invalid_sort",
      +  "invalid_period",
      +  "uri_too_long",
      +  "no_data",
      +  "rate_limited",
      +  "upstream_unreachable"
      +]
    • addedOutput schema / properties / next_offset
      Added value: +{
      +  "description": "Offset that continues right after the rows in data (offset + returned_count) — pass it as offset for the next page, with no gap or overlap. Present whenever rows remain past this page; absent on the last page.",
      +  "type": "number"
      +}
    • changedOutput schema / properties / notice / description
      Previous value: -"Informational message when the response carries no rows — either zero rows matched the filters (broaden the query) or offset paged past the last row (reduce offset below total)."New value: +"Informational message when EIA returned no rows — either zero rows matched the filters (broaden the query) or offset paged past the last row (reduce offset below total). A page left empty because its first row alone exceeds the response budget carries no notice; canvas_preview_note names the offset that skips it."
    • changedOutput schema / properties / returnedCount / description
      Previous value: -"Rows in this response. When returnedCount < totalCount, use offset or canvas for the rest."New value: +"Rows in this response. When returnedCount < totalCount, continue at next_offset or stage the rest."
    • changedOutput schema / properties / returned_count / description
      Previous value: -"Number of rows in this response. When returned_count < total, use offset pagination or DataCanvas for the rest."New value: +"Number of rows in data. When returned_count < total, continue at next_offset or stage the rest for SQL."
  6. Changed6 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": [
      +      "route",
      +      "data",
      +      "total",
      +      "returned_count",
      +      "frequency",
      +      "date_format",
      +      "effectiveRoute",
      +      "totalCount",
      +      "returnedCount",
      +      "appliedOffset",
      +      "appliedLength"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • 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: `route_not_found`: Route does not exist in the EIA taxonomy. `route_not_queryable`: Route is a category node with sub-routes, not a queryable leaf. `invalid_facet`: An unknown facet key was used in filters. `invalid_column`: An unknown data column ID was passed in columns. `invalid_frequency`: An unknown frequency code was passed. `invalid_sort`: A sort entry named a column the route does not sort by. `invalid_period`: start or end was not in a period format the route accepts. `no_data`: Date range is inverted (start is after end). `rate_limited`: EIA rate limit hit (OVER_RATE_LIMIT). Other values are possible when a failure originates below the handler.",
      +          "examples": [
      +            "route_not_found",
      +            "route_not_queryable",
      +            "invalid_facet",
      +            "invalid_column",
      +            "invalid_frequency",
      +            "invalid_sort",
      +            "invalid_period",
      +            "no_data",
      +            "rate_limited"
      +          ],
      +          "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"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "route",
      -  "data",
      -  "total",
      -  "returned_count",
      -  "frequency",
      -  "date_format",
      -  "effectiveRoute",
      -  "totalCount",
      -  "returnedCount",
      -  "appliedOffset",
      -  "appliedLength"
      -]
  7. Changed7 schema fields changed
    • changedInput schema / properties / length / description
      Previous value: -"Rows in the inline preview (default 100, max 5000 per EIA limit). Canvas staging is not bounded by this — it pages past the preview on its own."New value: +"Rows in the inline preview (default 100, max 5000 per EIA limit). With stage: true, staging is not bounded by this — it pages past the preview on its own."
    • changedInput schema / properties / route / description
      Previous value: -"Leaf route path (e.g. \"electricity/retail-sales\", \"steo\"). Discoverable via eia_browse_routes or eia_search_routes."New value: +"Leaf route path (e.g. \"electricity/retail-sales\", \"steo\"). Discoverable via eia_browse_routes or eia_search_routes. Leading, trailing, and doubled slashes are stripped, so an EIA-doc spelling like \"/electricity/retail-sales/\" resolves to the same route."
    • addedInput schema / properties / stage
      Added value: +{
      +  "default": false,
      +  "description": "Stage the matching rows as a DataCanvas table for SQL (default false). Off, the call makes one upstream request and returns the preview alone. On, the service pages past the preview up to EIA_CANVAS_MAX_ROWS and registers the accumulated rows, returning the handle in dataset — several extra upstream requests and seconds of latency on a large route, so turn it on when moving to analysis, not while exploring. Requires a canvas (CANVAS_PROVIDER_TYPE=duckdb); without one nothing is staged whatever this is set to.",
      +  "type": "boolean"
      +}
    • changedOutput schema / properties / canvas_preview_note / description
      Previous value: -"Human-readable note when total exceeds the inline preview. With a canvas configured it names how many rows actually reached the canvas table, and where in the matching set those rows sit whenever the stage does not start at row 1; when staging also stopped short of total (the EIA_CANVAS_MAX_ROWS cap, or an upstream page that did not return), it says so and gives the offset to resume from. With no canvas configured nothing is staged, so it places the inline page against total and names offset paging and CANVAS_PROVIDER_TYPE=duckdb as the ways to reach the rest."New value: +"Human-readable note when total exceeds the inline preview. On a stage: true call it names how many rows actually reached the canvas table, and where in the matching set those rows sit whenever the stage does not start at row 1; when staging also stopped short of total (the EIA_CANVAS_MAX_ROWS cap, or an upstream page that did not return), it says so and gives the offset to resume from. Where staging was not requested it places the inline page against total and names stage: true as the way to get SQL access to the rest; where no canvas is configured at all, staging is unavailable, so it names offset paging and CANVAS_PROVIDER_TYPE=duckdb instead."
    • changedOutput schema / properties / dataset / description
      Previous value: -"df_<id> table handle for the registered dataset — pass directly to eia_dataframe_query SQL (SELECT ... FROM df_<id>). Every dataset a tenant stages shares one canvas, so handles from different routes join directly."New value: +"df_<id> table handle for the registered dataset — pass directly to eia_dataframe_query SQL (SELECT ... FROM df_<id>). Present only on a stage: true call against a deployment with a canvas configured; absent otherwise, since nothing was staged. Every dataset a tenant stages shares one canvas, so handles from different routes join directly."
    • changedOutput schema / properties / route / description
      Previous value: -"The route path queried."New value: +"The route path queried, in canonical spelling — any leading, trailing, or doubled slashes the input carried are stripped. Reusable verbatim in a follow-up call."
    • changedOutput schema / properties / truncation_warning / description
      Previous value: -"Upstream advisories forwarded verbatim from EIA's warnings[], joined with '; ' when more than one applies. These describe the inline page — EIA's \"incomplete return\" entry fires whenever the requested length is under total, at any size — not a 5,000-row ceiling on this response. Absent when the response already accounts for the gap the advisory names (the staged table reaches the last row, notice explains the empty page, or canvas_preview_note places the inline page against total where no canvas is configured)."New value: +"Upstream advisories forwarded verbatim from EIA's warnings[], joined with '; ' when more than one applies. These describe the inline page — EIA's \"incomplete return\" entry fires whenever the requested length is under total, at any size — not a 5,000-row ceiling on this response. Absent when the response already accounts for the gap the advisory names (the staged table reaches the last row, notice explains the empty page, or canvas_preview_note places the inline page against total because nothing was staged)."
  8. Changed2 schema fields changed
    • changedOutput schema / properties / canvas_preview_note / description
      Previous value: -"Human-readable note when total exceeds the inline preview — names how many rows actually reached the canvas table, and where in the matching set those rows sit whenever the stage does not start at row 1. When staging also stopped short of total (the EIA_CANVAS_MAX_ROWS cap, or an upstream page that did not return), it says so and gives the offset to resume from."New value: +"Human-readable note when total exceeds the inline preview. With a canvas configured it names how many rows actually reached the canvas table, and where in the matching set those rows sit whenever the stage does not start at row 1; when staging also stopped short of total (the EIA_CANVAS_MAX_ROWS cap, or an upstream page that did not return), it says so and gives the offset to resume from. With no canvas configured nothing is staged, so it places the inline page against total and names offset paging and CANVAS_PROVIDER_TYPE=duckdb as the ways to reach the rest."
    • changedOutput schema / properties / truncation_warning / description
      Previous value: -"Upstream advisories forwarded verbatim from EIA's warnings[], joined with '; ' when more than one applies. These describe the inline page — EIA's \"incomplete return\" entry fires whenever the requested length is under total, at any size — not a 5,000-row ceiling on this response. Absent when the response already accounts for the gap the advisory names (the staged table reaches the last row, or notice explains the empty page)."New value: +"Upstream advisories forwarded verbatim from EIA's warnings[], joined with '; ' when more than one applies. These describe the inline page — EIA's \"incomplete return\" entry fires whenever the requested length is under total, at any size — not a 5,000-row ceiling on this response. Absent when the response already accounts for the gap the advisory names (the staged table reaches the last row, notice explains the empty page, or canvas_preview_note places the inline page against total where no canvas is configured)."
  9. Changed3 schema fields changed
    • addedOutput schema / properties / appliedSort
      Added value: +{
      +  "description": "Echo of the result ordering as applied, when a sort was provided — the ordering that decided which rows a capped stage holds.",
      +  "items": {
      +    "additionalProperties": false,
      +    "description": "A sort criterion as applied.",
      +    "properties": {
      +      "column": {
      +        "description": "Column ID sorted by.",
      +        "type": "string"
      +      },
      +      "direction": {
      +        "description": "Sort direction.",
      +        "enum": [
      +          "asc",
      +          "desc"
      +        ],
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "column",
      +      "direction"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / properties / canvas_preview_note / description
      Previous value: -"Human-readable note when total exceeds the inline preview — names how many rows actually reached the canvas table and, when staging stopped short of total (the EIA_CANVAS_MAX_ROWS cap, or an upstream page that did not return), says so and gives the offset to resume from."New value: +"Human-readable note when total exceeds the inline preview — names how many rows actually reached the canvas table, and where in the matching set those rows sit whenever the stage does not start at row 1. When staging also stopped short of total (the EIA_CANVAS_MAX_ROWS cap, or an upstream page that did not return), it says so and gives the offset to resume from."
    • changedOutput schema / properties / truncation_warning / description
      Previous value: -"Forwarded from EIA's warnings[] when the API warns of truncated results near the 5,000 per-page limit."New value: +"Upstream advisories forwarded verbatim from EIA's warnings[], joined with '; ' when more than one applies. These describe the inline page — EIA's \"incomplete return\" entry fires whenever the requested length is under total, at any size — not a 5,000-row ceiling on this response. Absent when the response already accounts for the gap the advisory names (the staged table reaches the last row, or notice explains the empty page)."
  10. Changed10 schema fields changed
    • removedInput schema / properties / canvas_id
      Removed value: -{
      -  "description": "DataCanvas ID to register results into. Omit on first call — a new canvas is minted and returned. Pass the returned canvas_id on subsequent calls to accumulate multiple route results into one canvas for cross-route SQL joins.",
      -  "type": "string"
      -}
    • changedInput schema / properties / length / description
      Previous value: -"Rows to fetch per request (default 100, max 5000 per EIA limit)."New value: +"Rows in the inline preview (default 100, max 5000 per EIA limit). Canvas staging is not bounded by this — it pages past the preview on its own."
    • changedInput schema / properties / offset / description
      Previous value: -"Pagination offset (default 0)."New value: +"Row offset into the matching set (default 0). An offset at or beyond total returns zero rows."
    • addedOutput schema / properties / appliedLength
      Added value: +{
      +  "description": "Preview row count requested for this call.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / appliedOffset
      Added value: +{
      +  "description": "Row offset applied to the query — the cause when a page comes back empty.",
      +  "type": "number"
      +}
    • removedOutput schema / properties / canvas_id
      Removed value: -{
      -  "description": "Canvas workspace ID — present when spillover occurred or canvas_id was supplied. Pass to subsequent eia_query_route calls to accumulate datasets.",
      -  "type": "string"
      -}
    • changedOutput schema / properties / canvas_preview_note / description
      Previous value: -"Human-readable note when total > returned rows, describing how to access the full dataset via canvas SQL."New value: +"Human-readable note when total exceeds the inline preview — names how many rows actually reached the canvas table and, when staging stopped short of total (the EIA_CANVAS_MAX_ROWS cap, or an upstream page that did not return), says so and gives the offset to resume from."
    • changedOutput schema / properties / dataset / description
      Previous value: -"df_<id> table handle for the registered dataset — pass directly to eia_dataframe_query SQL (SELECT ... FROM df_<id>)."New value: +"df_<id> table handle for the registered dataset — pass directly to eia_dataframe_query SQL (SELECT ... FROM df_<id>). Every dataset a tenant stages shares one canvas, so handles from different routes join directly."
    • changedOutput schema / properties / notice / description
      Previous value: -"Informational message when zero rows matched the filters — guidance for broadening the query."New value: +"Informational message when the response carries no rows — either zero rows matched the filters (broaden the query) or offset paged past the last row (reduce offset below total)."
    • changedOutput schema / required
      Previous value: -[
      -  "route",
      -  "data",
      -  "total",
      -  "returned_count",
      -  "frequency",
      -  "date_format",
      -  "effectiveRoute",
      -  "totalCount",
      -  "returnedCount"
      -]New value: +[
      +  "route",
      +  "data",
      +  "total",
      +  "returned_count",
      +  "frequency",
      +  "date_format",
      +  "effectiveRoute",
      +  "totalCount",
      +  "returnedCount",
      +  "appliedOffset",
      +  "appliedLength"
      +]
  11. Changed4 schema fields changed
    • addedOutput schema / properties / appliedColumns
      Added value: +{
      +  "description": "Echo of the column projection as applied, when columns were provided.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / appliedEnd
      Added value: +{
      +  "description": "Echo of the end period as applied, when an end was provided.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / appliedFrequency
      Added value: +{
      +  "description": "Echo of the frequency as applied, when a frequency was provided.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / appliedStart
      Added value: +{
      +  "description": "Echo of the start period as applied, when a start was provided.",
      +  "type": "string"
      +}
  12. Changed4 schema fields changed
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Informational message when zero rows matched the filters — guidance for broadening the query.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / returned_count
      Added value: +{
      +  "description": "Number of rows in this response. When returned_count < total, use offset pagination or DataCanvas for the rest.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / total
      Added value: +{
      +  "description": "Total matching rows in the EIA dataset for this query (may exceed returned rows when pagination or spillover applies).",
      +  "type": "number"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "route",
      -  "data",
      -  "frequency",
      -  "date_format",
      -  "effectiveRoute",
      -  "totalCount",
      -  "returnedCount"
      -]New value: +[
      +  "route",
      +  "data",
      +  "total",
      +  "returned_count",
      +  "frequency",
      +  "date_format",
      +  "effectiveRoute",
      +  "totalCount",
      +  "returnedCount"
      +]
  13. Changed7 schema fields changed
    • addedOutput schema / properties / appliedFilters
      Added value: +{
      +  "additionalProperties": {
      +    "anyOf": [
      +      {
      +        "type": "string"
      +      },
      +      {
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      }
      +    ]
      +  },
      +  "description": "Facet filters applied to the query, when provided.",
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • addedOutput schema / properties / effectiveRoute
      Added value: +{
      +  "description": "The route path that was queried.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / returnedCount
      Added value: +{
      +  "description": "Rows in this response. When returnedCount < totalCount, use offset or canvas for the rest.",
      +  "type": "number"
      +}
    • removedOutput schema / properties / returned_count
      Removed value: -{
      -  "description": "Rows in this response. When returned_count < total, use offset or canvas for the rest.",
      -  "type": "number"
      -}
    • removedOutput schema / properties / total
      Removed value: -{
      -  "description": "Total matching rows in the EIA dataset.",
      -  "type": "number"
      -}
    • addedOutput schema / properties / totalCount
      Added value: +{
      +  "description": "Total matching rows in the EIA dataset.",
      +  "type": "number"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "route",
      -  "data",
      -  "total",
      -  "returned_count",
      -  "frequency",
      -  "date_format"
      -]New value: +[
      +  "route",
      +  "data",
      +  "frequency",
      +  "date_format",
      +  "effectiveRoute",
      +  "totalCount",
      +  "returnedCount"
      +]
  14. First observed

TDQS

A4.6/5.0
Behavior5/5

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

Annotations only cover read-only and closed-world safety; the description adds substantive behavior: all data values come back as strings needing a DOUBLE cast, the default path is a single upstream request returning a preview, and stage:true triggers extra paging requests, seconds of latency, and a staging row cap. It even discloses the failure mode that nothing is staged if the server has no canvas configured.

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?

Purpose and the prerequisite call are front-loaded, and nearly every sentence carries operational information. The closing sentence about all tenant datasets landing in one canvas and cross-joining by name is useful but sits awkwardly at the end of a long, clause-heavy block rather than being separated out.

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 10-parameter tool with nested filters and sort, the description covers the full lifecycle: discover, query, optionally stage, then query via SQL. An output schema exists, yet the description still clarifies the preview-versus-staged distinction, which is the one thing an agent could get wrong.

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 carries per-parameter meaning, and the description mostly restates those categories (filters, date range, frequency, columns). The one genuine addition beyond the schema is the workflow consequence of the stage flag, which is already covered under behavioral transparency. A baseline 3 is appropriate here.

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 ('Fetches data from a leaf route') plus the scope of options (facet filters, date range, frequency, column selection). It also implicitly separates itself from eia_describe_route (metadata discovery) and eia_dataframe_query (SQL over staged data), so an agent can place it in the workflow without opening schemas.

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?

Explicitly routes the agent: 'Use eia_describe_route first' to get valid facet IDs, values, column IDs and frequency codes, and 'pass the returned dataset name to eia_dataframe_describe ... and eia_dataframe_query' for the follow-on steps. It also gives a when/when-not for staging ('turn it on when moving to analysis, not while exploring'), which is exactly the decision an agent has to make.

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.