Skip to main content
Glama

bls-labor-mcp-server

Server Details

Fetch US Bureau of Labor Statistics data — CPI, unemployment, wages, JOLTS, and more via MCP.

If you are the author of this connector, you can claim ownership by verifying the domain or GitHub account it belongs to. Claimed connector authors can inspect health checks, view analytics, and manage their listing.
Status
Healthy
Uptime
100.0% over 78 days
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL
Repository
cyanheads/bls-labor-mcp-server
GitHub Stars
1
Server Listing
@cyanheads/bls-labor-mcp-server
ChatGPT
–
Claude
–

TDQS

A4.4/5.0

Scored across 6 tools

Disambiguation4/5

Discovery (bls_list_surveys, bls_search_series), retrieval (bls_get_series, bls_get_latest), and canvas analysis (bls_dataframe_describe, bls_dataframe_query) form clear, mostly non-overlapping groups. The only potential confusion is bls_get_latest vs bls_get_series, since the former is effectively a single-observation shortcut, but descriptions clarify the boundary.

Naming Consistency4/5

All names are snake_case with a consistent bls_ prefix. There's a minor structural deviation: get_latest, get_series, list_surveys, and search_series use verb_noun, while dataframe_describe and dataframe_query use noun_verb, but the pattern remains readable and predictable.

Tool Count5/5

Six tools is well-matched to the scope: two for catalog discovery, two for data retrieval, and two for canvas analysis. Each tool earns its place with no redundant surface.

Completeness4/5

The pipeline covers discovery, retrieval, and analysis cleanly, with no dead ends for core workflows. Minor gaps exist, such as no explicit tool to drop/clear a registered dataframe or inspect canvas storage limits, but these are workaroundable via TTL-based expiry.

Available Tools

6 tools
bls_dataframe_describeDescribe BLS DataframesA
Read-onlyIdempotent
Inspect

List canvas dataframes materialized by bls_get_series or by bls_dataframe_query register_as, with provenance (source tool, query parameters), TTL, row count, and column schema. Use before writing SQL to confirm column names and types. Lazy-sweeps expired tables before responding.

NameRequiredDescriptionDefault
nameNoOptional dataframe name to describe a single dataframe — a df_XXXXX_XXXXX name from bls_get_series, or a register_as name from bls_dataframe_query. Omit, or leave blank, to list all active dataframes.

Output Schema

NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
dataframesNoActive dataframes for this tenant, newest first.

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already cover read-only and idempotency, but the description adds real behavioral context: returned provenance, TTL, row counts, column schema, and the non-obvious side effect that expired tables are lazy-swept before responding. That sweep behavior is exactly the kind of trait an agent could not infer from structured fields.

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?

Three sentences, front-loaded with the verb and resource, then the usage trigger, then the side effect. Nothing is redundant with the tool name or title.

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?

Covers what is listed, where entries come from, what metadata accompanies each entry, when to call it, and a latent side effect — more than enough for a one-optional-parameter read tool, especially with an output schema carrying return structure.

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

Parameters3/5

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

Schema coverage is 100% and the single `name` parameter is already fully documented in the schema, including the omit-to-list-all case. The description reinforces 'list all' semantics but adds no format or edge-case detail beyond it, so the baseline 3 applies.

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 ("List canvas dataframes") and pins down provenance by naming the exact sibling tools that materialize them (bls_get_series, bls_dataframe_query register_as). An agent can immediately tell this apart from the sibling query/series tools.

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?

"Use before writing SQL to confirm column names and types" gives a clear selection context. It stops short of an explicit exclusion (e.g., 'use bls_dataframe_query instead if you already know the columns'), so the alternative is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bls_dataframe_queryQuery BLS DataframesA
Read-onlyIdempotent
Inspect

Run a single-statement SELECT against the canvas dataframes registered by bls_get_series or by an earlier register_as. Read-only: writes, DDL, DROP, COPY, PRAGMA, ATTACH, and external-file table functions are rejected. System catalogs (information_schema, pg_catalog, sqlite_master, duckdb_*) are denied at the bridge layer — use bls_dataframe_describe to list available dataframes. Supports JOINs, aggregates, window functions, and CTEs. Optional register_as persists the result as a new dataframe with a fresh TTL for chained analysis. Canvas SQL operations consume zero BLS API quota.

NameRequiredDescriptionDefault
sqlYesSingle-statement SELECT against df_<id> tables on the shared canvas. Reference dataframes by the names returned in bls_get_series responses or listed by bls_dataframe_describe. Standard DuckDB SQL — joins, aggregates, window functions, CTEs all supported. Example: SELECT series_id, year, period, value FROM df_AAAAA_BBBBB WHERE year >= '2020' ORDER BY year DESC.
previewNoInline row preview count, clamped to the applied row_limit (at most 10000) with notice. Defaults to row_limit. Set lower (e.g. 50) when chaining via register_as and only a sample is needed immediately.
row_limitNoResponse row limit (default 1000); requests above 10000 are clamped with notice. Full results live on-canvas under register_as when provided.
register_asNoWhen set, persist the query result as a new dataframe under this name. Fresh TTL — not inherited from parent tables. Use to chain analyses without re-running source SQL or consuming additional BLS quota.

Output Schema

NameRequiredDescription
capNoThe preview or row_limit cap that was applied.
rowsNoMaterialized rows, bounded by preview / row_limit.
errorNoPresent when the call failed. Absent on success.
shownNoNumber of rows returned inline.
noticeNoRequested and applied limits when clamped, plus guidance when preview or row_limit capped the result and how to retrieve the rest. Absent when limits were unchanged and all rows fit.
columnsNoColumn names in projection order.
row_countNoRows materialized by the query. Exact when register_as is used; otherwise equals row_limit when truncated is true.
truncatedNoTrue when the returned rows were capped.
expires_atNoISO 8601 expiry fixed at the new dataframe’s creation, when applicable; reads do not extend it.
registered_asNoSet when register_as was supplied and the result was materialized.

TDQS

A4.7/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 enumerates rejected statement types (writes, DDL, DROP, COPY, PRAGMA, ATTACH, external-file functions), denied system catalogs, the zero-quota characteristic, and that register_as gets a fresh TTL rather than inheriting the parent's. This is exactly the behavioral context annotations cannot convey.

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

Conciseness5/5

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

Front-loads the core operation, then layers security constraints, capabilities, and the register_as semantics in a tight sequence. Every sentence adds information; nothing is redundant padding.

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?

With an output schema present, rich annotations, and fully documented parameters, the description covers the remaining gaps: what SQL is rejected, catalog access rules, quota cost, and result-persistence behavior. An agent has everything needed to invoke it correctly.

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

Parameters4/5

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

Schema coverage is already 100%, so baseline is 3, but the description adds real meaning: register_as 'persists the result as a new dataframe with a fresh TTL' and enables chaining without re-running source SQL or consuming quota. Clamping behavior for preview/row_limit is handled in the schema, so the description complements rather than duplicates.

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?

Opens with a specific verb and resource: 'Run a single-statement SELECT against the canvas dataframes registered by bls_get_series or by an earlier register_as.' It names the sibling tools that produce the dataframes, so an agent can immediately distinguish this query tool from the registration/listing tools.

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?

Explicitly routes the agent to bls_dataframe_describe for listing dataframes rather than relying on catalog queries, and clarifies the dataframes originate from bls_get_series or register_as. It does not spell out when-not-to-use versus the sibling read tools, but the context is clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bls_get_latestGet Latest BLS ObservationA
Read-onlyIdempotent
Inspect

Return the single most recent observation for BLS series. SeriesIDs are trimmed, uppercased, and deduplicated in first-occurrence order. Processes the first 50 unique IDs and returns the exact remainder as unprocessedSeriesIds for a separate request. Each processed series costs one API query; bls_get_series with a 1-year window uses one query for a batch. Recommended limit: 10 series.

NameRequiredDescriptionDefault
series_idsYesBLS SeriesIDs, trimmed, uppercased, and deduplicated in first-occurrence order. Processes the first 50 unique IDs; unprocessedSeriesIds names the exact remainder. Each processed ID consumes one daily API query. Recommended: ≤10 series.

Output Schema

NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
failedNoSeries that failed to fetch. Inspect seriesId and error for per-item details. Not-found series appear here rather than as a tool-level error.
noticeNoGuidance for unprocessed IDs, unavailable observations, or failed series — bls_search_series for a SeriesID BLS rejected, the state or national row to request for an OEWS SeriesID BLS reports nonexistent, or the reason and recovery for a request failure that left other series answered. Absent when all requested IDs returned available observations.
resultsNoSuccessfully fetched series with their latest observations. Series that failed appear in failed[] instead.
succeededNoNumber of series with a successfully fetched observation.
unprocessedSeriesIdsNoCanonical unique SeriesIDs beyond the 50-series cap, in original order. Request these separately.

TDQS

A4.7/5.0
Behavior5/5

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

Goes well beyond the readOnly/idempotent annotations: discloses normalization (trim/uppercase/dedup in first-occurrence order), a hard 50-ID cap, that the remainder is returned as unprocessedSeriesIds, and the per-series query cost. This is exactly the operational context annotations cannot convey.

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?

Four tight sentences, front-loaded with the core action, then normalization, then truncation behavior, then cost guidance. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists so return values needn't be explained, and the description still covers the one non-obvious return field (unprocessedSeriesIds) plus truncation and cost. Nothing an agent needs to call it correctly is missing.

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 baseline is 3, but the description adds cost semantics ('each processed series costs one API query') and the recommended batch size, which the schema only partially mirrors. Marginal added value over the schema.

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 ('Return the single most recent observation for BLS series') and implicitly contrasts with bls_get_series for batch retrieval. An agent can distinguish it from siblings 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 concrete recommended limit (10 series) and names bls_get_series with a 1-year window as the cheaper batch alternative. It stops short of an explicit 'use this when / not when' rule, but the cost comparison effectively routes the agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bls_get_seriesGet BLS Time-Series DataA
Read-onlyIdempotent
Inspect

Fetch BLS time-series data in a single API request (one query). SeriesIDs are trimmed, uppercased, and deduplicated in first-occurrence order. Processes up to 25 unique IDs without a key or 50 with one; unprocessedSeriesIds names the exact remainder for a separate request. Supports optional year range (up to 20 years; BLS may reduce it) and BLS-computed net/percent changes when available. BLS can publish a '-' missing-value sentinel; check observation.available before arithmetic. Set annual_average to add BLS-computed annual summary rows, which are not additional periods or universally arithmetic means. Large results spill to a dataframe when canvas is configured; otherwise all observations return inline. Use dataset.name in bls_dataframe_describe, then bls_dataframe_query SQL. Use bls_search_series to resolve concepts to SeriesIDs.

NameRequiredDescriptionDefault
end_yearNoEnd year for the data range (inclusive). Supplying it without start_year is rejected before the request — BLS applies no default start year alongside an explicit end year. Pair it with start_year, or omit both for the API default window.
series_idsYesBLS SeriesIDs, trimmed, uppercased, and deduplicated in first-occurrence order. Process up to 25 unique IDs without a key or 50 with one; the exact remainder is returned as unprocessedSeriesIds. The batch costs one API query.
start_yearNoStart year for the data range (inclusive). BLS allows up to 20 years per request and requires both bounds or neither: supplying start_year alone resolves end_year to the current year, capped at start_year + 19. BLS may reduce this window for unregistered access. Omit both for the BLS three-calendar-year default, subject to series coverage.
calculationsNoWhen true, request BLS-computed period-over-period net/percent changes. BLS returns supported types and intervals; some surveys omit calculations while preserving observations, while an explicit unsupported-calculations rejection raises calculations_not_supported. Consult bls_list_surveys for support. Monthly series may return 1, 3, 6, and 12-month intervals. Mirror rows carry no calculations. calculationsApplied is false when any data-bearing series returns no calculation values; notice names affected series and available calculations remain intact.
annual_averageNoWhen true, include BLS-computed annual summary rows named "Annual": M13 for monthly series, Q05 for quarterly, S03 for semiannual. These are not universally arithmetic means or additional periods; exclude them from sums or averages over periods. Defaults to false. Independent of year bounds. Surveys without annual summaries return the same rows either way; annualAverageRows reports the count.

Output Schema

NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
noticeNoGuidance for agents — names any SeriesID that returned zero observations with its reason (including a failed live fallback's reason and recovery for a SeriesID the local observation mirror does not hold, and the state or national row to request for an OEWS SeriesID BLS reports nonexistent), names mirror-served series that lack requested calculations, reports a resolved end_year the 20-year window capped, and reports the bls_dataframe_describe then bls_dataframe_query workflow when results spill to canvas. Absent when every requested series returned data over the window as asked and it all fit inline.
seriesNoSeries data, in request order.
datasetNoCanvas dataframe handle — present when the observation volume exceeded the inline budget. Call bls_dataframe_describe with dataset.name to inspect column_schema, then use that table name in bls_dataframe_query SQL across the full data.
spilledNoTrue when results spilled to canvas due to inline budget overflow.
endYearAppliedNoEnd year applied to the query. Resolved from start_year when end_year was omitted, so it can differ from the requested range; notice names the cap when the 20-year window decided it. Absent when no year range was in effect.
seriesRequestedNoNumber of SeriesIDs requested. Do not compare it against series[] length to find empty series — a SeriesID that returned no data is still listed in series[] with observationCount 0. Check observationCount per entry, or read notice, which names every SeriesID that came back empty.
startYearAppliedNoStart year applied to the query, whether it was served live or from the local observation mirror. Absent when no year range was in effect.
annualAverageRowsNoHow many observations across all series are annual-average rows (period M13/Q05/S03). Present only when annual_average is true; 0 means none of the requested surveys publish annual averages.
totalObservationsNoTotal observation rows across all requested series.
calculationsAppliedNoTrue when calculations were requested and every data-bearing series returned calculation values. False when disabled, no observations returned, or any data-bearing series lacks calculations; notice names affected series. Absent when calculations was omitted.
annualAverageAppliedNoWhether annual-average rows were requested. When false, observations hold real periods only; filter on available before aggregation.
unprocessedSeriesIdsNoCanonical unique SeriesIDs beyond the request cap, in original order. Request these separately.
availableObservationsNoRows with a published numeric value.
unavailableObservationsNoRows carrying the BLS "-" missing-value sentinel.

TDQS

A4.4/5.0
Behavior5/5

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

Annotations already cover the safety profile (readOnly, idempotent, openWorld), and the description adds substantial behavioral context beyond them: input normalization order, the 25/50 batch ceiling with an explicit remainder field, the '-' missing-value sentinel with the need to check observation.available, and the fact that large results spill to a dataframe only when canvas is configured. These are exactly the operational details an agent cannot infer from annotations.

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

Conciseness4/5

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

Front-loaded with the purpose and the batching constraints, and most sentences carry distinct information. It is somewhat long and repeats schema content such as the 25/50 ID limit and trimming/dedup behavior that also appears verbatim in the parameter descriptions.

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 read-only fetch tool with full schema coverage and an output schema, nothing essential is missing: normalization, batch limits, overflow handling, missing-value sentinels, year-range defaults, and the downstream handoff to dataframe tools are all covered. Return-format explanation is correctly omitted since an output schema exists.

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 every parameter, including the start_year/end_year pairing rule and the semantics of annual_average. The description restates much of this (year range up to 20, annual_average caveat) rather than adding syntax or format details the schema lacks, so baseline 3 applies.

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 ('Fetch BLS time-series data') plus the batching model ('one query'), which is the defining characteristic versus a per-series fetch. It contrasts with siblings implicitly by naming bls_search_series as the lookup step and bls_dataframe_query as the follow-on, so an agent can place it in the workflow without opening a schema.

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

Usage Guidelines4/5

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

Explicit routing is present: 'Use bls_search_series to resolve concepts to SeriesIDs' and 'Use dataset.name in bls_dataframe_describe, then bls_dataframe_query SQL.' It also gives a hard precondition (up to 25/50 IDs; remainder in unprocessedSeriesIds). The only gap is that it never says when to prefer bls_get_latest over this tool, so the closest sibling is left for inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bls_list_surveysList BLS SurveysA
Read-onlyIdempotent
Inspect

List BLS survey programs with their abbreviation codes, full names, and metadata about calculation support and annual averages. Use to discover which survey covers a topic before calling bls_search_series; each row's searchCoverage says whether bls_search_series reaches the survey through its offline index, composes its SeriesIDs from code tables, or cannot search it, in which case its series are fetched by SeriesID with bls_get_series. Optional category filter narrows results to prices, employment, wages, productivity, injuries, or time_use surveys.

NameRequiredDescriptionDefault
categoryNoOptional category filter. One of: prices, employment, wages, productivity, injuries, time_use. A survey can appear under more than one category (CES under employment and wages). Omit to list all surveys.

Output Schema

NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
totalNoTotal surveys returned.
surveysNoBLS survey programs matching the filter, sorted alphabetically by abbreviation.
categoryFilterNoCategory filter applied, if any. Absent when all surveys were listed.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnly, idempotent, openWorld), so the bar is lower; the description instead spends its words on the meaningful behavioral detail an agent needs — the three possible values of searchCoverage and what each implies for the next call. It does not mention result size, pagination, or whether the survey catalog is static, which keeps it from a 5.

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

Conciseness4/5

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

Purpose is front-loaded in the first clause, and the remaining sentences all carry routing or filtering information. It is dense — one long compound sentence about searchCoverage is harder to parse than a short list would be — but nothing is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and full schema coverage on the single parameter, the description only needs to supply the routing logic, and it does: how to pick a survey and what to call next for each coverage case. Nothing an agent needs to invoke this 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 coverage is 100% and the enum is fully documented in the schema, including the nuance that a survey can appear under multiple categories. The description restates the same category list with no added semantics (no defaults beyond 'omit', no ordering or matching behavior), so baseline 3 applies.

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 ('List BLS survey programs') plus what each row contains (abbreviation codes, full names, calculation-support and annual-average metadata). It is clearly separable from siblings because it names bls_search_series and bls_get_series as the downstream tools rather than overlapping with them.

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

Usage Guidelines5/5

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

Gives an explicit trigger ('Use to discover which survey covers a topic before calling bls_search_series') and then spells out the routing decision: searchCoverage tells the agent whether bls_search_series can reach the survey, composes SeriesIDs from code tables, or requires bls_get_series by SeriesID. The alternative path is named with its condition, not left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bls_search_seriesSearch BLS SeriesA
Read-only
Inspect

Search the BLS series catalog by natural language query, survey code, geographic area, or keywords to resolve cryptic SeriesIDs. Returns matching series with decoded components (survey, area, item, seasonal flag, and publication frequency for surveys that publish one series at several frequencies) and plain-language names, ranked by relevance and paged with limit and offset. Use this before bls_get_series when you have a concept but not a SeriesID. Operates offline against an index of the major surveys — no API quota consumed. Survey filter accepts the two-letter code of an indexed survey (CU, AP, CE, LN, LA, PC, WP, JT, EC, PR, MP, CW, CM, CI, SM, LE, EI, SU, IP, BD, LU, EE; OE is indexed only when the server sets BLS_CATALOG_INCLUDE_OES=true, and otherwise composes OEWS SeriesIDs from the OE code tables, marked composed and unconfirmed); series in other surveys are fetched by SeriesID with bls_get_series. Area filter accepts place names, USPS state codes, and FIPS, CBSA, and CPI area codes.

NameRequiredDescriptionDefault
areaNoGeographic area to narrow results to, case-insensitive. A USPS state code (TX) or 2-digit state FIPS code (48) selects the state: its statewide series, the areas in it (metro areas reaching into it included), and series with no decoded area whose title names it. An all-digit area code selects the area it names in every survey that decodes it: 3 digits a combined statistical area (CSA), 4 a CPI area (0000 is the U.S. city average), 5 a county FIPS or metro area (CBSA) code, 7 a city or town (state + place FIPS); a code naming no indexed area returns no series. Any other value, such as a place name ("Seattle") or a SeriesID fragment ("ST48"), matches as a substring of the area name, title, or SeriesID; another all-digit value does too, with a notice. Under survey OE with no indexed OE rows, area selects the OEWS areas to compose: a USPS state code or 2-digit state FIPS names the state, a 5-digit CBSA or 7-digit OEWS area code (0042660, 5300000) its area, and any other value is a substring of an OEWS area name; each metro or state it names also composes its state and national rows. Without this filter, a place query names in full (every distinctive word of it, e.g. "black hawk") ranks first among the series matching every query word; otherwise, among equal matches, current series rank first, then national ones.
limitNoMaximum number of results to return (default 10); requests above 50 are clamped to 50 with notice.
queryYesNatural language or keyword query (e.g. "unemployment rate", "CPI food", "nonfarm payrolls"). Also accepts a SeriesID directly for exact lookup.
offsetNoNumber of ranked results to skip, for paging past the first page (default 0). Pass nextOffset from the previous response to get the next page.
surveyNoTwo-letter LABSTAT survey abbreviation to filter results, case-insensitive (e.g. CU for CPI, CE for CES, SM for state and metro CES, LN for CPS, LA for LAUS, JT for JOLTS). Indexed surveys: CU, AP, CE, LN, LA, PC, WP, JT, EC, PR, MP, CW, CM, CI, SM, LE, EI, SU, IP, BD, LU, EE; OE (OEWS) is indexed only when the server sets BLS_CATALOG_INCLUDE_OES=true, and without its rows OE composes OEWS SeriesIDs from the OE code tables for the occupation, place, and data type the query and area name, each marked composed. Omit to search all indexed surveys.
seasonal_adjustmentNoWhen true, return only seasonally adjusted series. When false, return only not-seasonally-adjusted. Omit to return both.

Output Schema

NameRequiredDescription
capNoThe result limit that capped the returned list.
errorNoPresent when the call failed. Absent on success.
shownNoNumber of series returned in this response.
cappedNoTrue when the FTS candidate pool, after the survey/area/seasonal filters, reached the internal cap (~1000), or when composing OEWS SeriesIDs stopped at its 50-row cap with combinations left. totalCount is then a lower bound and offset paging stops at the pool. Narrow the query, add filters, or use a direct SeriesID to get an exact count.
noticeNoRequested and applied limits when clamped, and how an all-digit area that is not an area code matched, plus guidance on unindexed surveys, offsets past the end, empty results, the next page, the capped candidate pool, or composed OEWS SeriesIDs, which stay unconfirmed until bls_get_series returns them. Absent when neither applies and this page ends an uncapped list of indexed series.
seriesNoMatching series, ordered by relevance.
truncatedNoTrue when ranked results remain past this page; nextOffset fetches them.
areaFilterNoArea filter applied, trimmed. Absent when no area filter was passed or it was blank.
nextOffsetNoOffset of the next page. Present only when truncated is true.
totalCountNoTotal ranked results after every filter (area included), before limit and offset. A lower bound when capped is true — the catalog index may contain more matching series.
catalogSizeNoTotal series in the loaded catalog index. Distinguishes an empty-result search from a failed catalog load.
limitAppliedNoResult limit in effect (defaults to 10 when omitted).
surveyFilterNoSurvey filter applied, trimmed and uppercased. Absent when no survey filter was passed or it was blank.
offsetAppliedNoOffset in effect (defaults to 0 when omitted).
effectiveQueryNoQuery string as the server received and searched on. Confirms interpretation for self-correction.
seasonalFilterNoSeasonal-adjustment filter applied, if any. Absent when not passed.

TDQS

A4.6/5.0
Behavior5/5

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

Well beyond the annotations: it discloses that the tool runs offline against a bundled index with no API quota consumed (consistent with openWorldHint=false), that limits above 50 are clamped with a notice, how results are ranked, and the OE caveat that composed SeriesIDs are 'marked composed and unconfirmed.' These are exactly the operational traits an agent needs and that annotations cannot express.

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

Conciseness4/5

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

Front-loaded correctly: purpose first, then the use-before-bls_get_series rule, then operational caveats. It is dense but mostly earns its length; the main waste is re-listing the 23 survey codes and area-code digits that the schema already carries, which could have been left to the schema.

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 six-parameter discovery tool with an output schema, the description covers everything material: what it returns in outline, ranking and paging behavior, offline/quota status, and the OE indexing dependency. Nothing an agent needs in order to call it 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 coverage is 100%, so the schema already documents all six parameters, including the survey and area code semantics. The description largely restates that content (the survey code list is duplicated verbatim in the schema), adding little parameter-level meaning beyond the schema; at most it reinforces default paging via limit/offset. Baseline 3 is appropriate.

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 ('Search the BLS series catalog') and enumerates the accepted query forms (natural language, survey code, area, keywords) plus the goal ('resolve cryptic SeriesIDs'). It explicitly distinguishes itself from bls_get_series, so an agent can route correctly without opening either schema.

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

Usage Guidelines5/5

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

Gives an explicit ordering rule: 'Use this before bls_get_series when you have a concept but not a SeriesID,' and closes the loop with 'series in other surveys are fetched by SeriesID with bls_get_series.' The offline/no-quota note further signals when this is the cheap first move.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updates
    • Changedbls_get_latest1 field changed
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance for unprocessed IDs, unavailable observations, or failed series — bls_search_series for a SeriesID BLS rejected, or the reason and recovery for a request failure that left other series answered. Absent when all requested IDs returned available observations."New value: +"Guidance for unprocessed IDs, unavailable observations, or failed series — bls_search_series for a SeriesID BLS rejected, the state or national row to request for an OEWS SeriesID BLS reports nonexistent, or the reason and recovery for a request failure that left other series answered. Absent when all requested IDs returned available observations."
    • Changedbls_get_series2 fields changed
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `service_unavailable`: BLS is unreachable or returns an unsuccessful HTTP response and no mirrored observations can answer the request. `serialization_failure`: BLS returns malformed JSON and no mirrored observations can answer the request. `upstream_timeout`: The live BLS request exceeds its shared 45-second operation budget and no mirrored observations can answer the request. `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `request_rejected`: BLS returned a non-success status with a message matching no known failure mode, both for the request and for its automatic re-issue without catalog metadata — e.g. a rejected combination of request parameters. `series_not_found`: No requested series returned data and at least one SeriesID does not exist. A batch mixing an invalid SeriesID with one BLS has no data for lands here too, and names both in the message and recovery hint. `series_locked`: The BLS database is temporarily locked for the requested series. `no_data_for_period`: The requested year range is unusable before the request — start_year after end_year, a span of 20 years or more, or end_year without start_year — or BLS returned data for none of the requested series over the range. `calculations_not_supported`: calculations=true was requested for a survey that does not support it. `canvas_registration_failed`: The result set exceeds the inline budget and canvas is configured, but registering the dataframe failed. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `service_unavailable`: BLS is unreachable or returns an unsuccessful HTTP response and no mirrored observations can answer the request. `serialization_failure`: BLS returns malformed JSON and no mirrored observations can answer the request. `upstream_timeout`: The live BLS request exceeds its shared 45-second operation budget and no mirrored observations can answer the request. `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `request_rejected`: BLS returned a non-success status with a message matching no known failure mode, both for the request and for its automatic re-issue without catalog metadata — e.g. a rejected combination of request parameters. `series_not_found`: No requested series returned data and at least one SeriesID does not exist. A batch mixing an invalid SeriesID with one BLS has no data for lands here too, and names both in the message and recovery hint. For an OEWS SeriesID, usually an occupation–area cell BLS does not publish, the hint names the state or national row to request instead of bls_search_series. `series_locked`: The BLS database is temporarily locked for the requested series. `no_data_for_period`: The requested year range is unusable before the request — start_year after end_year, a span of 20 years or more, or end_year without start_year — or BLS returned data for none of the requested series over the range. `calculations_not_supported`: calculations=true was requested for a survey that does not support it. `canvas_registration_failed`: The result set exceeds the inline budget and canvas is configured, but registering the dataframe failed. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance for agents — names any SeriesID that returned zero observations with its reason (including a failed live fallback's reason and recovery for a SeriesID the local observation mirror does not hold), names mirror-served series that lack requested calculations, reports a resolved end_year the 20-year window capped, and reports the bls_dataframe_describe then bls_dataframe_query workflow when results spill to canvas. Absent when every requested series returned data over the window as asked and it all fit inline."New value: +"Guidance for agents — names any SeriesID that returned zero observations with its reason (including a failed live fallback's reason and recovery for a SeriesID the local observation mirror does not hold, and the state or national row to request for an OEWS SeriesID BLS reports nonexistent), names mirror-served series that lack requested calculations, reports a resolved end_year the 20-year window capped, and reports the bls_dataframe_describe then bls_dataframe_query workflow when results spill to canvas. Absent when every requested series returned data over the window as asked and it all fit inline."
    • Changedbls_list_surveys2 fields changed
      • addedOutput schema / properties / surveys / items / properties / searchCoverage
        Added value: +{
        +  "description": "How bls_search_series reaches this survey: \"indexed\" when its offline index holds the survey's series (seriesIndexed counts them), \"composed\" when it builds the survey's SeriesIDs from code tables instead (OE without indexed OE rows), \"none\" when it cannot search the survey — fetch those series by SeriesID with bls_get_series. Absent while the catalog index is still loading at startup.",
        +  "enum": [
        +    "indexed",
        +    "composed",
        +    "none"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / surveys / items / properties / seriesIndexed
        Added value: +{
        +  "description": "Series of this survey in the offline index. Present only when searchCoverage is \"indexed\".",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
    • Changedbls_search_series8 fields changed
      • changedInput schema / properties / area / description
        Previous value: -"State name, MSA name, or FIPS area code to narrow results to a geographic area — a case-insensitive substring of the area name, title, or SeriesID. Without this filter, specific whole place names in query are relevance preferences; otherwise national series rank first among equal matches."New value: +"Geographic area to narrow results to, case-insensitive. A USPS state code (TX) or 2-digit state FIPS code (48) selects the state: its statewide series, the areas in it (metro areas reaching into it included), and series with no decoded area whose title names it. An all-digit area code selects the area it names in every survey that decodes it: 3 digits a combined statistical area (CSA), 4 a CPI area (0000 is the U.S. city average), 5 a county FIPS or metro area (CBSA) code, 7 a city or town (state + place FIPS); a code naming no indexed area returns no series. Any other value, such as a place name (\"Seattle\") or a SeriesID fragment (\"ST48\"), matches as a substring of the area name, title, or SeriesID; another all-digit value does too, with a notice. Under survey OE with no indexed OE rows, area selects the OEWS areas to compose: a USPS state code or 2-digit state FIPS names the state, a 5-digit CBSA or 7-digit OEWS area code (0042660, 5300000) its area, and any other value is a substring of an OEWS area name; each metro or state it names also composes its state and national rows. Without this filter, a place query names in full (every distinctive word of it, e.g. \"black hawk\") ranks first among the series matching every query word; otherwise, among equal matches, current series rank first, then national ones."
      • changedInput schema / properties / survey / description
        Previous value: -"Two-letter LABSTAT survey abbreviation to filter results, case-insensitive (e.g. CU for CPI, CE for CES, LN for CPS, LA for LAUS, JT for JOLTS). Indexed surveys: CU, AP, CE, LN, LA, PC, WP, JT, EC, PR, MP, CW, CM, CI; OE (OEWS) only when the server sets BLS_CATALOG_INCLUDE_OES=true. Omit to search all indexed surveys."New value: +"Two-letter LABSTAT survey abbreviation to filter results, case-insensitive (e.g. CU for CPI, CE for CES, SM for state and metro CES, LN for CPS, LA for LAUS, JT for JOLTS). Indexed surveys: CU, AP, CE, LN, LA, PC, WP, JT, EC, PR, MP, CW, CM, CI, SM, LE, EI, SU, IP, BD, LU, EE; OE (OEWS) is indexed only when the server sets BLS_CATALOG_INCLUDE_OES=true, and without its rows OE composes OEWS SeriesIDs from the OE code tables for the occupation, place, and data type the query and area name, each marked composed. Omit to search all indexed surveys."
      • changedOutput schema / properties / capped / description
        Previous value: -"True when the FTS candidate pool, after the survey/area/seasonal filters, reached the internal cap (~1000). totalCount is then a lower bound and offset paging stops at the pool. Narrow the query, add filters, or use a direct SeriesID to get an exact count."New value: +"True when the FTS candidate pool, after the survey/area/seasonal filters, reached the internal cap (~1000), or when composing OEWS SeriesIDs stopped at its 50-row cap with combinations left. totalCount is then a lower bound and offset paging stops at the pool. Narrow the query, add filters, or use a direct SeriesID to get an exact count."
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `catalog_unavailable`: The catalog index failed to load at startup. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `catalog_loading`: The catalog index holds no series yet and a LABSTAT harvest is building it — at first startup, or while an hourly check retries an empty index. `catalog_unavailable`: The catalog index holds no series and no harvest is running — every LABSTAT download failed, or the load stopped with an error. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / error / properties / data / properties / reason / examples
        Previous value: -[
        -  "catalog_unavailable"
        -]New value: +[
        +  "catalog_loading",
        +  "catalog_unavailable"
        +]
      • changedOutput schema / properties / notice / description
        Previous value: -"Requested and applied limits when clamped, plus guidance on unindexed surveys, offsets past the end, empty results, the next page, or the capped candidate pool. Absent when the limit was unchanged and this page ends an uncapped list with results."New value: +"Requested and applied limits when clamped, and how an all-digit area that is not an area code matched, plus guidance on unindexed surveys, offsets past the end, empty results, the next page, the capped candidate pool, or composed OEWS SeriesIDs, which stay unconfirmed until bls_get_series returns them. Absent when neither applies and this page ends an uncapped list of indexed series."
      • addedOutput schema / properties / series / items / properties / composed
        Added value: +{
        +  "description": "True when the SeriesID was composed from the OEWS code tables rather than read from the index: unconfirmed until bls_get_series returns data for it, since BLS leaves many occupation–area cells unpublished. Composed rows carry no coverage years. Absent for indexed series.",
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / series / items / properties / frequency / description
        Previous value: -"Publication frequency — \"Monthly\", \"Semi-Annual\", \"Quarterly\", or \"Annual\" — for CU, CW, and LN, which publish one series at several frequencies under the same title. Absent for other surveys."New value: +"Publication frequency — \"Monthly\", \"Semi-Annual\", \"Quarterly\", or \"Annual\" — for CU, CW, LN, and BD, which publish one series at several frequencies under the same title. Absent for other surveys."
  2. 6 tool updates
    • Changedbls_dataframe_describe1 field changed
      • changedOutput schema / properties / dataframes / items / properties / expires_at / description
        Previous value: -"ISO 8601 expiry timestamp (sliding TTL)."New value: +"ISO 8601 table expiry fixed at creation; reads do not extend it."
    • Changedbls_dataframe_query8 fields changed
      • changedInput schema / properties / preview / description
        Previous value: -"Inline row preview count. Defaults to row_limit. Set lower (e.g. 50) when chaining via register_as and only a sample is needed immediately."New value: +"Inline row preview count, clamped to the applied row_limit (at most 10000) with notice. Defaults to row_limit. Set lower (e.g. 50) when chaining via register_as and only a sample is needed immediately."
      • changedInput schema / properties / preview / maximum
        Previous value: -10000New value: +9007199254740991
      • changedInput schema / properties / row_limit / description
        Previous value: -"Hard cap on rows materialized in the response (default 1000, max 10000). Full results live on-canvas under register_as when provided."New value: +"Response row limit (default 1000); requests above 10000 are clamped with notice. Full results live on-canvas under register_as when provided."
      • changedInput schema / properties / row_limit / maximum
        Previous value: -10000New value: +9007199254740991
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: The DataCanvas service is not configured for this deployment. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `register_as_clash`: The requested register_as name already identifies a dataframe. `canvas_unavailable`: The DataCanvas service is not configured for this deployment. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / error / properties / data / properties / reason / examples
        Previous value: -[
        -  "canvas_unavailable"
        -]New value: +[
        +  "register_as_clash",
        +  "canvas_unavailable"
        +]
      • changedOutput schema / properties / expires_at / description
        Previous value: -"ISO 8601 expiry for the newly registered dataframe, when applicable."New value: +"ISO 8601 expiry fixed at the new dataframe’s creation, when applicable; reads do not extend it."
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance when results were capped by preview or row_limit — names which parameter was the binding limiter and suggests how to retrieve the rest. Absent when all rows fit in the response."New value: +"Requested and applied limits when clamped, plus guidance when preview or row_limit capped the result and how to retrieve the rest. Absent when limits were unchanged and all rows fit."
    • Changedbls_get_latest12 fields changed
      • changedInput schema / properties / series_ids / description
        Previous value: -"One or more BLS SeriesIDs (1–50). Each consumes one daily API query. Use bls_search_series to resolve concepts to SeriesIDs. Recommended: ≤10 series."New value: +"BLS SeriesIDs, trimmed, uppercased, and deduplicated in first-occurrence order. Processes the first 50 unique IDs; unprocessedSeriesIds names the exact remainder. Each processed ID consumes one daily API query. Recommended: ≤10 series."
      • removedInput schema / properties / series_ids / maxItems
        Removed value: -50
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid, and no requested series returned an observation. `quota_exceeded`: The BLS API 500 query/day limit has been reached, and no requested series returned an observation. `series_locked`: The BLS database is temporarily locked for the requested series, and no requested series returned an observation. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `service_unavailable`: BLS is unreachable or returns an unsuccessful HTTP response, and no requested series returned an observation. `serialization_failure`: BLS returns malformed JSON, and no requested series returned an observation. `upstream_timeout`: The live BLS request exceeds its shared 45-second operation budget, and no requested series returned an observation. `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid, and no requested series returned an observation. `quota_exceeded`: The BLS API 500 query/day limit has been reached, and no requested series returned an observation. `series_locked`: The BLS database is temporarily locked for the requested series, and no requested series returned an observation. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / error / properties / data / properties / reason / examples
        Previous value: -[
        -  "invalid_api_key",
        -  "quota_exceeded",
        -  "series_locked"
        -]New value: +[
        +  "service_unavailable",
        +  "serialization_failure",
        +  "upstream_timeout",
        +  "invalid_api_key",
        +  "quota_exceeded",
        +  "series_locked"
        +]
      • changedOutput schema / properties / failed / items / properties / error / description
        Previous value: -"Error message. Common values: \"Series does not exist\" or \"Invalid Series\" (invalid SeriesID — use bls_search_series to find valid IDs), \"No observations returned\" (series exists but has no current data). The generic \"Your request has failed. Please check your input parameters, and try your request again.\" means BLS rejected the request itself twice, the second time without catalog metadata, rather than naming the SeriesID. A quota, API-key, or database-lock failure lands here only when another series returned an observation; notice then names its reason and recovery."New value: +"Error message. Common values: \"Series does not exist\" or \"Invalid Series\" (invalid SeriesID — use bls_search_series to find valid IDs), \"No observations returned\" (series exists but has no current data). The generic \"Your request has failed. Please check your input parameters, and try your request again.\" means BLS rejected the request itself twice, the second time without catalog metadata, rather than naming the SeriesID. A quota, API-key, database-lock, availability, malformed-response, or timeout failure lands here only when another series returned an observation; notice then names its reason and recovery."
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance when one or more series failed — bls_search_series for a SeriesID BLS rejected, or the reason and recovery for a quota, API-key, or database-lock failure that left other series answered. Absent when all series returned data."New value: +"Guidance for unprocessed IDs, unavailable observations, or failed series — bls_search_series for a SeriesID BLS rejected, or the reason and recovery for a request failure that left other series answered. Absent when all requested IDs returned available observations."
      • changedOutput schema / properties / results / items / properties / area / description
        Previous value: -"Geographic area when returned by the API."New value: +"Geographic area from BLS or the catalog index."
      • changedOutput schema / properties / results / items / properties / item / description
        Previous value: -"Item/subject when returned by the API."New value: +"Item/subject from BLS or the catalog index."
      • addedOutput schema / properties / results / items / properties / measure
        Added value: +{
        +  "description": "Measurement type and units supplied by BLS.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / results / items / properties / seasonal / description
        Previous value: -"Seasonality indicator when returned by the API."New value: +"Seasonality indicator from BLS or the catalog index."
      • changedOutput schema / properties / results / items / properties / title / description
        Previous value: -"Series name when returned by the API."New value: +"Series name from BLS or the catalog index."
      • addedOutput schema / properties / unprocessedSeriesIds
        Added value: +{
        +  "description": "Canonical unique SeriesIDs beyond the 50-series cap, in original order. Request these separately.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
    • Changedbls_get_series12 fields changed
      • changedInput schema / properties / annual_average / description
        Previous value: -"When true, add each year's annual-average row to the observations. An annual average is the mean of that year's real periods, returned as an extra row named \"Annual\" with period M13 (monthly series), Q05 (quarterly) or S03 (semiannual) — not an additional month or quarter, so it must be excluded from any sum or average over observations. Defaults to false, which returns real periods only; check available before aggregating. Independent of start_year/end_year. Surveys that publish no annual averages return the same rows either way; enrichment.annualAverageRows reports how many rows were actually added."New value: +"When true, include BLS-computed annual summary rows named \"Annual\": M13 for monthly series, Q05 for quarterly, S03 for semiannual. These are not universally arithmetic means or additional periods; exclude them from sums or averages over periods. Defaults to false. Independent of year bounds. Surveys without annual summaries return the same rows either way; annualAverageRows reports the count."
      • changedInput schema / properties / calculations / description
        Previous value: -"When true, request BLS-computed period-over-period calculations. The flag is a single boolean (you cannot select an individual calculation type), but the API returns whichever the survey supports and omits the rest — CPI and PPI return percent change only (the inflation rate), and a survey that supports neither simply returns its observations without calculation fields. Requesting calculations never fails, so it is always safe to set; consult bls_list_surveys (allowsNetChange / allowsPercentChange) only to predict which fields will come back. Monthly-cadence series return each supported change type over 1, 3, 6, and 12-month intervals; other cadences return a subset. A series served from the local observation mirror, when the server runs one, carries no calculation fields; enrichment.calculationsApplied is then false and notice names it."New value: +"When true, request BLS-computed period-over-period net/percent changes. BLS returns supported types and intervals; some surveys omit calculations while preserving observations, while an explicit unsupported-calculations rejection raises calculations_not_supported. Consult bls_list_surveys for support. Monthly series may return 1, 3, 6, and 12-month intervals. Mirror rows carry no calculations. calculationsApplied is false when any data-bearing series returns no calculation values; notice names affected series and available calculations remain intact."
      • changedInput schema / properties / series_ids / description
        Previous value: -"One or more BLS SeriesIDs (1–50). The entire batch counts as one API query. Use bls_search_series to resolve concepts to SeriesIDs."New value: +"BLS SeriesIDs, trimmed, uppercased, and deduplicated in first-occurrence order. Process up to 25 unique IDs without a key or 50 with one; the exact remainder is returned as unprocessedSeriesIds. The batch costs one API query."
      • removedInput schema / properties / series_ids / maxItems
        Removed value: -50
      • changedInput schema / properties / start_year / description
        Previous value: -"Start year for the data range (inclusive). The BLS API allows up to 20 years per request and requires both bounds or neither: supplying start_year alone resolves end_year to the current year, capped at start_year + 19 so the window stays inside the 20-year limit. Omit both for the API default (typically 3–20 years depending on survey)."New value: +"Start year for the data range (inclusive). BLS allows up to 20 years per request and requires both bounds or neither: supplying start_year alone resolves end_year to the current year, capped at start_year + 19. BLS may reduce this window for unregistered access. Omit both for the BLS three-calendar-year default, subject to series coverage."
      • changedOutput schema / properties / calculationsApplied / description
        Previous value: -"Whether BLS net/percent-change calculations were applied. True when calculations=true reached BLS for every returned series; false when calculations=false, or when the local observation mirror served a series, whose rows carry no calculations — notice then names those series. Absent when calculations was omitted."New value: +"True when calculations were requested and every data-bearing series returned calculation values. False when disabled, no observations returned, or any data-bearing series lacks calculations; notice names affected series. Absent when calculations was omitted."
      • changedOutput schema / properties / dataset / properties / expires_at / description
        Previous value: -"ISO 8601 expiry timestamp (sliding 24h window)."New value: +"ISO 8601 per-table expiry, fixed at creation; the enclosing canvas has a separate sliding lifetime."
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `request_rejected`: BLS returned a non-success status with a message matching no known failure mode, both for the request and for its automatic re-issue without catalog metadata — e.g. a rejected combination of request parameters. `series_not_found`: No requested series returned data and at least one SeriesID does not exist. A batch mixing an invalid SeriesID with one BLS has no data for lands here too, and names both in the message and recovery hint. `series_locked`: The BLS database is temporarily locked for the requested series. `no_data_for_period`: The requested year range is unusable before the request — start_year after end_year, a span of 20 years or more, or end_year without start_year — or BLS returned data for none of the requested series over the range. `calculations_not_supported`: calculations=true was requested for a survey that does not support it. `canvas_unavailable`: The result set exceeds the inline budget and canvas (DuckDB) is not configured. `canvas_registration_failed`: The result set exceeds the inline budget and canvas is configured, but registering the dataframe failed. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `service_unavailable`: BLS is unreachable or returns an unsuccessful HTTP response and no mirrored observations can answer the request. `serialization_failure`: BLS returns malformed JSON and no mirrored observations can answer the request. `upstream_timeout`: The live BLS request exceeds its shared 45-second operation budget and no mirrored observations can answer the request. `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `request_rejected`: BLS returned a non-success status with a message matching no known failure mode, both for the request and for its automatic re-issue without catalog metadata — e.g. a rejected combination of request parameters. `series_not_found`: No requested series returned data and at least one SeriesID does not exist. A batch mixing an invalid SeriesID with one BLS has no data for lands here too, and names both in the message and recovery hint. `series_locked`: The BLS database is temporarily locked for the requested series. `no_data_for_period`: The requested year range is unusable before the request — start_year after end_year, a span of 20 years or more, or end_year without start_year — or BLS returned data for none of the requested series over the range. `calculations_not_supported`: calculations=true was requested for a survey that does not support it. `canvas_registration_failed`: The result set exceeds the inline budget and canvas is configured, but registering the dataframe failed. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / error / properties / data / properties / reason / examples
        Previous value: -[
        -  "invalid_api_key",
        -  "quota_exceeded",
        -  "request_rejected",
        -  "series_not_found",
        -  "series_locked",
        -  "no_data_for_period",
        -  "calculations_not_supported",
        -  "canvas_unavailable",
        -  "canvas_registration_failed"
        -]New value: +[
        +  "service_unavailable",
        +  "serialization_failure",
        +  "upstream_timeout",
        +  "invalid_api_key",
        +  "quota_exceeded",
        +  "request_rejected",
        +  "series_not_found",
        +  "series_locked",
        +  "no_data_for_period",
        +  "calculations_not_supported",
        +  "canvas_registration_failed"
        +]
      • addedOutput schema / properties / series / items / properties / measure
        Added value: +{
        +  "description": "Measurement type and units supplied by BLS.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / series / items / properties / observations / items / properties / period / description
        Previous value: -"BLS period code: M01–M12 are months, Q01–Q04 quarters, S01–S02 semiannual halves. M13, Q05 and S03 are not further periods — each is the mean of that year's real observations, named \"Annual\", and appears only when annual_average is true. Exclude them from any sum or average over observations."New value: +"BLS period code: M01–M12 are months, Q01–Q04 quarters, S01–S02 semiannual halves. M13, Q05 and S03 are BLS-computed annual summaries, named \"Annual\", and appear only when annual_average is true. They are not additional periods or universally arithmetic means. Exclude them from sums or averages over periods."
      • addedOutput schema / properties / unprocessedSeriesIds
        Added value: +{
        +  "description": "Canonical unique SeriesIDs beyond the request cap, in original order. Request these separately.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
    • Changedbls_list_surveys2 fields changed
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `service_unavailable`: BLS /surveys API is unreachable or returns a non-200 response. `serialization_failure`: BLS /surveys response cannot be parsed (malformed JSON or unexpected schema). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `service_unavailable`: BLS /surveys API is unreachable or returns a non-200 response. `serialization_failure`: BLS /surveys response cannot be parsed as JSON. `upstream_timeout`: The live BLS request exceeds its shared 45-second operation budget. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / error / properties / data / properties / reason / examples
        Previous value: -[
        -  "invalid_api_key",
        -  "service_unavailable",
        -  "serialization_failure"
        -]New value: +[
        +  "invalid_api_key",
        +  "service_unavailable",
        +  "serialization_failure",
        +  "upstream_timeout"
        +]
    • Changedbls_search_series3 fields changed
      • changedInput schema / properties / limit / description
        Previous value: -"Maximum number of results to return (1–50, default 10)."New value: +"Maximum number of results to return (default 10); requests above 50 are clamped to 50 with notice."
      • changedInput schema / properties / limit / maximum
        Previous value: -50New value: +9007199254740991
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance on the result: the survey is not in the offline index, the offset is past the last result, nothing matched, which offset fetches the next page, or, on the last page of a capped list, that other series may also match. Absent when this page ends an uncapped list with results."New value: +"Requested and applied limits when clamped, plus guidance on unindexed surveys, offsets past the end, empty results, the next page, or the capped candidate pool. Absent when the limit was unchanged and this page ends an uncapped list with results."
  3. 1 tool update
    • Changedbls_search_series4 fields changed
      • changedInput schema / properties / area / description
        Previous value: -"State name, MSA name, or FIPS area code to narrow results to a geographic area — a case-insensitive substring of the area name, title, or SeriesID. Omit for national series, which then rank first among equal matches."New value: +"State name, MSA name, or FIPS area code to narrow results to a geographic area — a case-insensitive substring of the area name, title, or SeriesID. Without this filter, specific whole place names in query are relevance preferences; otherwise national series rank first among equal matches."
      • addedOutput schema / properties / series / items / properties / endPeriod
        Added value: +{
        +  "description": "Last observation period code in the catalog snapshot, when available (e.g. M08 or Q04).",
        +  "type": "string"
        +}
      • addedOutput schema / properties / series / items / properties / endYear
        Added value: +{
        +  "description": "Last observation year in the catalog snapshot, when available.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • addedOutput schema / properties / series / items / properties / startYear
        Added value: +{
        +  "description": "First observation year in the catalog snapshot, when available; does not imply continuous coverage.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
  4. 3 tool updates
    • Changedbls_dataframe_describe5 fields changed
      • changedInput schema / properties / name / description
        Previous value: -"Optional table name (df_XXXXX_XXXXX) to describe a single dataframe. Omit to list all active dataframes."New value: +"Optional dataframe name to describe a single dataframe — a df_XXXXX_XXXXX name from bls_get_series, or a register_as name from bls_dataframe_query. Omit, or leave blank, to list all active dataframes."
      • changedOutput schema / properties / dataframes / items / properties / column_schema / items / properties / type / description
        Previous value: -"DuckDB column type (VARCHAR, BIGINT, DOUBLE, ...)."New value: +"Column type as the canvas reports it: VARCHAR, INTEGER, BIGINT, DOUBLE, BOOLEAN, DATE, TIMESTAMP, JSON, or BLOB. A register_as column of another DuckDB type (DECIMAL, HUGEINT from SUM over integers, SMALLINT, a list) reports VARCHAR, though SQL still sees its real type."
      • changedOutput schema / properties / dataframes / items / properties / name / description
        Previous value: -"Canvas table name (df_XXXXX_XXXXX)."New value: +"Canvas table name — df_XXXXX_XXXXX, or the register_as name given."
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: The DataCanvas service is not configured for this deployment. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: The DataCanvas service is not configured for this deployment. `invalid_dataframe_name`: name is not blank and is not a canvas identifier, so no dataframe can carry it. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / error / properties / data / properties / reason / examples
        Previous value: -[
        -  "canvas_unavailable"
        -]New value: +[
        +  "canvas_unavailable",
        +  "invalid_dataframe_name"
        +]
    • Changedbls_get_latest3 fields changed
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `series_locked`: The BLS database is temporarily locked for the requested series. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid, and no requested series returned an observation. `quota_exceeded`: The BLS API 500 query/day limit has been reached, and no requested series returned an observation. `series_locked`: The BLS database is temporarily locked for the requested series, and no requested series returned an observation. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / failed / items / properties / error / description
        Previous value: -"Error message. Common values: \"Series does not exist\" (invalid SeriesID — use bls_search_series to find valid IDs), \"No observations returned\" (series exists but has no current data). BLS does not always name the series it rejected: an invalid SeriesID sometimes comes back as the generic \"Your request has failed. Please check your input parameters, and try your request again.\", which means the same thing here."New value: +"Error message. Common values: \"Series does not exist\" or \"Invalid Series\" (invalid SeriesID — use bls_search_series to find valid IDs), \"No observations returned\" (series exists but has no current data). The generic \"Your request has failed. Please check your input parameters, and try your request again.\" means BLS rejected the request itself twice, the second time without catalog metadata, rather than naming the SeriesID. A quota, API-key, or database-lock failure lands here only when another series returned an observation; notice then names its reason and recovery."
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance when one or more series failed — e.g. to use bls_search_series to verify SeriesIDs. Absent when all series returned data."New value: +"Guidance when one or more series failed — bls_search_series for a SeriesID BLS rejected, or the reason and recovery for a quota, API-key, or database-lock failure that left other series answered. Absent when all series returned data."
    • Changedbls_get_series4 fields changed
      • changedInput schema / properties / calculations / description
        Previous value: -"When true, request BLS-computed period-over-period calculations. The flag is a single boolean (you cannot select an individual calculation type), but the API returns whichever the survey supports and omits the rest — CPI and PPI return percent change only (the inflation rate), and a survey that supports neither simply returns its observations without calculation fields. Requesting calculations never fails, so it is always safe to set; consult bls_list_surveys (allowsNetChange / allowsPercentChange) only to predict which fields will come back. Monthly-cadence series return each supported change type over 1, 3, 6, and 12-month intervals; other cadences return a subset."New value: +"When true, request BLS-computed period-over-period calculations. The flag is a single boolean (you cannot select an individual calculation type), but the API returns whichever the survey supports and omits the rest — CPI and PPI return percent change only (the inflation rate), and a survey that supports neither simply returns its observations without calculation fields. Requesting calculations never fails, so it is always safe to set; consult bls_list_surveys (allowsNetChange / allowsPercentChange) only to predict which fields will come back. Monthly-cadence series return each supported change type over 1, 3, 6, and 12-month intervals; other cadences return a subset. A series served from the local observation mirror, when the server runs one, carries no calculation fields; enrichment.calculationsApplied is then false and notice names it."
      • changedOutput schema / properties / calculationsApplied / description
        Previous value: -"Whether BLS net/percent-change calculations were requested."New value: +"Whether BLS net/percent-change calculations were applied. True when calculations=true reached BLS for every returned series; false when calculations=false, or when the local observation mirror served a series, whose rows carry no calculations — notice then names those series. Absent when calculations was omitted."
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `request_rejected`: BLS returned a non-success status with a message matching no known failure mode — e.g. a rejected combination of request parameters. `series_not_found`: No requested series returned data and at least one SeriesID does not exist. A batch mixing an invalid SeriesID with one BLS has no data for lands here too, and names both in the message and recovery hint. `series_locked`: The BLS database is temporarily locked for the requested series. `no_data_for_period`: The requested year range is unusable before the request — start_year after end_year, a span of 20 years or more, or end_year without start_year — or BLS returned data for none of the requested series over the range. `calculations_not_supported`: calculations=true was requested for a survey that does not support it. `canvas_unavailable`: The result set exceeds the inline budget and canvas (DuckDB) is not configured. `canvas_registration_failed`: The result set exceeds the inline budget and canvas is configured, but registering the dataframe failed. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `request_rejected`: BLS returned a non-success status with a message matching no known failure mode, both for the request and for its automatic re-issue without catalog metadata — e.g. a rejected combination of request parameters. `series_not_found`: No requested series returned data and at least one SeriesID does not exist. A batch mixing an invalid SeriesID with one BLS has no data for lands here too, and names both in the message and recovery hint. `series_locked`: The BLS database is temporarily locked for the requested series. `no_data_for_period`: The requested year range is unusable before the request — start_year after end_year, a span of 20 years or more, or end_year without start_year — or BLS returned data for none of the requested series over the range. `calculations_not_supported`: calculations=true was requested for a survey that does not support it. `canvas_unavailable`: The result set exceeds the inline budget and canvas (DuckDB) is not configured. `canvas_registration_failed`: The result set exceeds the inline budget and canvas is configured, but registering the dataframe failed. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance for agents — names any SeriesID that returned zero observations, reports a resolved end_year the 20-year window capped, and reports the bls_dataframe_describe then bls_dataframe_query workflow when results spill to canvas. Absent when every requested series returned data over the window as asked and it all fit inline."New value: +"Guidance for agents — names any SeriesID that returned zero observations with its reason (including a failed live fallback's reason and recovery for a SeriesID the local observation mirror does not hold), names mirror-served series that lack requested calculations, reports a resolved end_year the 20-year window capped, and reports the bls_dataframe_describe then bls_dataframe_query workflow when results spill to canvas. Absent when every requested series returned data over the window as asked and it all fit inline."
  5. 1 tool update
    • Changedbls_search_series2 fields changed
      • changedInput schema / properties / survey / description
        Previous value: -"Two-letter LABSTAT survey abbreviation to filter results, case-insensitive (e.g. CU for CPI, CE for CES, LN for CPS, LA for LAUS, JT for JOLTS). Indexed surveys: CU, AP, CE, LN, LA, PC, WP, JT, EC, PR, MP, CW; OE (OEWS) only when the server sets BLS_CATALOG_INCLUDE_OES=true. Omit to search all indexed surveys."New value: +"Two-letter LABSTAT survey abbreviation to filter results, case-insensitive (e.g. CU for CPI, CE for CES, LN for CPS, LA for LAUS, JT for JOLTS). Indexed surveys: CU, AP, CE, LN, LA, PC, WP, JT, EC, PR, MP, CW, CM, CI; OE (OEWS) only when the server sets BLS_CATALOG_INCLUDE_OES=true. Omit to search all indexed surveys."
      • addedOutput schema / properties / series / items / properties / frequency
        Added value: +{
        +  "description": "Publication frequency — \"Monthly\", \"Semi-Annual\", \"Quarterly\", or \"Annual\" — for CU, CW, and LN, which publish one series at several frequencies under the same title. Absent for other surveys.",
        +  "type": "string"
        +}
  6. 2 tool updates
    • Changedbls_list_surveys1 field changed
      • changedInput schema / properties / category / description
        Previous value: -"Optional category filter. One of: prices, employment, wages, productivity, injuries, time_use. Omit to list all surveys."New value: +"Optional category filter. One of: prices, employment, wages, productivity, injuries, time_use. A survey can appear under more than one category (CES under employment and wages). Omit to list all surveys."
    • Changedbls_search_series12 fields changed
      • changedInput schema / properties / area / description
        Previous value: -"State name, MSA name, or FIPS area code to narrow results to a geographic area. Omit for national series."New value: +"State name, MSA name, or FIPS area code to narrow results to a geographic area — a case-insensitive substring of the area name, title, or SeriesID. Omit for national series, which then rank first among equal matches."
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "Number of ranked results to skip, for paging past the first page (default 0). Pass nextOffset from the previous response to get the next page.",
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • changedInput schema / properties / survey / description
        Previous value: -"Two-letter LABSTAT survey abbreviation to filter results (e.g. CU for CPI, CE for CES, LN for CPS, LA for LAUS, JT for JOLTS, OE for OEWS). Omit to search all loaded surveys."New value: +"Two-letter LABSTAT survey abbreviation to filter results, case-insensitive (e.g. CU for CPI, CE for CES, LN for CPS, LA for LAUS, JT for JOLTS). Indexed surveys: CU, AP, CE, LN, LA, PC, WP, JT, EC, PR, MP, CW; OE (OEWS) only when the server sets BLS_CATALOG_INCLUDE_OES=true. Omit to search all indexed surveys."
      • changedOutput schema / anyOf
        Previous value: -[
        -  {
        -    "not": {
        -      "required": [
        -        "error"
        -      ]
        -    },
        -    "required": [
        -      "series",
        -      "totalCount",
        -      "capped",
        -      "catalogSize",
        -      "effectiveQuery",
        -      "limitApplied"
        -    ]
        -  },
        -  {
        -    "required": [
        -      "error"
        -    ]
        -  }
        -]New value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "series",
        +      "totalCount",
        +      "capped",
        +      "catalogSize",
        +      "effectiveQuery",
        +      "limitApplied",
        +      "offsetApplied"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • changedOutput schema / properties / areaFilter / description
        Previous value: -"Area filter applied, if any. Absent when no area filter was passed."New value: +"Area filter applied, trimmed. Absent when no area filter was passed or it was blank."
      • changedOutput schema / properties / capped / description
        Previous value: -"True when the FTS candidate pool reached the internal cap (~1000). totalCount is then a lower bound, not an exact match count. Narrow the query, add survey/area filters, or use a direct SeriesID to get an exact count."New value: +"True when the FTS candidate pool, after the survey/area/seasonal filters, reached the internal cap (~1000). totalCount is then a lower bound and offset paging stops at the pool. Narrow the query, add filters, or use a direct SeriesID to get an exact count."
      • addedOutput schema / properties / nextOffset
        Added value: +{
        +  "description": "Offset of the next page. Present only when truncated is true.",
        +  "type": "number"
        +}
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance when no results matched — e.g. how to broaden the query or remove filters. Absent when results are returned."New value: +"Guidance on the result: the survey is not in the offline index, the offset is past the last result, nothing matched, which offset fetches the next page, or, on the last page of a capped list, that other series may also match. Absent when this page ends an uncapped list with results."
      • addedOutput schema / properties / offsetApplied
        Added value: +{
        +  "description": "Offset in effect (defaults to 0 when omitted).",
        +  "type": "number"
        +}
      • changedOutput schema / properties / surveyFilter / description
        Previous value: -"Survey filter applied, if any. Absent when no survey filter was passed."New value: +"Survey filter applied, trimmed and uppercased. Absent when no survey filter was passed or it was blank."
      • changedOutput schema / properties / totalCount / description
        Previous value: -"Total candidates scored before the limit was applied. A lower bound when capped is true — the catalog index may contain more matching series."New value: +"Total ranked results after every filter (area included), before limit and offset. A lower bound when capped is true — the catalog index may contain more matching series."
      • changedOutput schema / properties / truncated / description
        Previous value: -"True when more candidates matched than the limit returned."New value: +"True when ranked results remain past this page; nextOffset fetches them."
  7. 2 tool updates
    • Changedbls_get_latest1 field changed
      • changedOutput schema / properties / failed / items / properties / error / description
        Previous value: -"Error message. Common values: \"Series does not exist\" (invalid SeriesID — use bls_search_series to find valid IDs), \"No observations returned\" (series exists but has no current data)."New value: +"Error message. Common values: \"Series does not exist\" (invalid SeriesID — use bls_search_series to find valid IDs), \"No observations returned\" (series exists but has no current data). BLS does not always name the series it rejected: an invalid SeriesID sometimes comes back as the generic \"Your request has failed. Please check your input parameters, and try your request again.\", which means the same thing here."
    • Changedbls_get_series6 fields changed
      • changedInput schema / properties / end_year / description
        Previous value: -"End year for the data range (inclusive). Defaults to the current year when omitted."New value: +"End year for the data range (inclusive). Supplying it without start_year is rejected before the request — BLS applies no default start year alongside an explicit end year. Pair it with start_year, or omit both for the API default window."
      • changedInput schema / properties / start_year / description
        Previous value: -"Start year for the data range (inclusive). The BLS API allows up to 20 years per request. Omit for the API default (typically 3–20 years depending on survey)."New value: +"Start year for the data range (inclusive). The BLS API allows up to 20 years per request and requires both bounds or neither: supplying start_year alone resolves end_year to the current year, capped at start_year + 19 so the window stays inside the 20-year limit. Omit both for the API default (typically 3–20 years depending on survey)."
      • changedOutput schema / properties / endYearApplied / description
        Previous value: -"End year in effect, when a range was requested."New value: +"End year applied to the query. Resolved from start_year when end_year was omitted, so it can differ from the requested range; notice names the cap when the 20-year window decided it. Absent when no year range was in effect."
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `request_rejected`: BLS returned a non-success status with a message matching no known failure mode — e.g. a rejected combination of request parameters. `series_not_found`: One or more SeriesIDs do not exist in BLS data. `series_locked`: The BLS database is temporarily locked for the requested series. `no_data_for_period`: No data is available for the requested year range. `calculations_not_supported`: calculations=true was requested for a survey that does not support it. `canvas_unavailable`: The result set exceeds the inline budget and canvas (DuckDB) is not configured. `canvas_registration_failed`: The result set exceeds the inline budget and canvas is configured, but registering the dataframe failed. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `request_rejected`: BLS returned a non-success status with a message matching no known failure mode — e.g. a rejected combination of request parameters. `series_not_found`: No requested series returned data and at least one SeriesID does not exist. A batch mixing an invalid SeriesID with one BLS has no data for lands here too, and names both in the message and recovery hint. `series_locked`: The BLS database is temporarily locked for the requested series. `no_data_for_period`: The requested year range is unusable before the request — start_year after end_year, a span of 20 years or more, or end_year without start_year — or BLS returned data for none of the requested series over the range. `calculations_not_supported`: calculations=true was requested for a survey that does not support it. `canvas_unavailable`: The result set exceeds the inline budget and canvas (DuckDB) is not configured. `canvas_registration_failed`: The result set exceeds the inline budget and canvas is configured, but registering the dataframe failed. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance for agents — names any SeriesID that returned zero observations, and reports the bls_dataframe_describe then bls_dataframe_query workflow when results spill to canvas. Absent when every requested series returned data and it all fit inline."New value: +"Guidance for agents — names any SeriesID that returned zero observations, reports a resolved end_year the 20-year window capped, and reports the bls_dataframe_describe then bls_dataframe_query workflow when results spill to canvas. Absent when every requested series returned data over the window as asked and it all fit inline."
      • changedOutput schema / properties / startYearApplied / description
        Previous value: -"Start year in effect, when a range was requested."New value: +"Start year applied to the query, whether it was served live or from the local observation mirror. Absent when no year range was in effect."
  8. 2 tool updates
    • Changedbls_get_latest3 fields changed
      • addedOutput schema / properties / results / items / properties / latestObservation / properties / available
        Added value: +{
        +  "description": "False when BLS published the \"-\" missing-value sentinel for this period.",
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / results / items / properties / latestObservation / properties / value / description
        Previous value: -"Observation value as a string, matching BLS API output. Parse to float for arithmetic."New value: +"Raw observation value from BLS. The literal \"-\" means unavailable; check available before arithmetic and read footnotes for the reason."
      • changedOutput schema / properties / results / items / properties / latestObservation / required
        Previous value: -[
        -  "year",
        -  "period",
        -  "value"
        -]New value: +[
        +  "year",
        +  "period",
        +  "value",
        +  "available"
        +]
    • Changedbls_get_series11 fields changed
      • changedInput schema / properties / annual_average / description
        Previous value: -"When true, add each year's annual-average row to the observations. An annual average is the mean of that year's real periods, returned as an extra row named \"Annual\" with period M13 (monthly series), Q05 (quarterly) or S03 (semiannual) — not an additional month or quarter, so it must be excluded from any sum or average over observations. Defaults to false, which returns real periods only and is safe to aggregate directly. Independent of start_year/end_year. Surveys that publish no annual averages return the same rows either way; enrichment.annualAverageRows reports how many rows were actually added."New value: +"When true, add each year's annual-average row to the observations. An annual average is the mean of that year's real periods, returned as an extra row named \"Annual\" with period M13 (monthly series), Q05 (quarterly) or S03 (semiannual) — not an additional month or quarter, so it must be excluded from any sum or average over observations. Defaults to false, which returns real periods only; check available before aggregating. Independent of start_year/end_year. Surveys that publish no annual averages return the same rows either way; enrichment.annualAverageRows reports how many rows were actually added."
      • changedOutput schema / anyOf
        Previous value: -[
        -  {
        -    "not": {
        -      "required": [
        -        "error"
        -      ]
        -    },
        -    "required": [
        -      "series",
        -      "spilled",
        -      "totalObservations",
        -      "seriesRequested",
        -      "annualAverageApplied"
        -    ]
        -  },
        -  {
        -    "required": [
        -      "error"
        -    ]
        -  }
        -]New value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "series",
        +      "spilled",
        +      "totalObservations",
        +      "availableObservations",
        +      "unavailableObservations",
        +      "seriesRequested",
        +      "annualAverageApplied"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • changedOutput schema / properties / annualAverageApplied / description
        Previous value: -"Whether annual-average rows were requested. When false, observations hold real periods only and can be summed or averaged directly."New value: +"Whether annual-average rows were requested. When false, observations hold real periods only; filter on available before aggregation."
      • addedOutput schema / properties / availableObservations
        Added value: +{
        +  "description": "Rows with a published numeric value.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / series / items / properties / availableObservationCount
        Added value: +{
        +  "description": "Rows with a published numeric value, excluding the BLS \"-\" sentinel.",
        +  "type": "number"
        +}
      • changedOutput schema / properties / series / items / properties / observationCount / description
        Previous value: -"Total observations for this series. When spilled to canvas, all observations are on the dataframe; inline only shows a preview."New value: +"Total period rows for this series, including unavailable BLS placeholder rows. When spilled to canvas, all rows are on the dataframe; inline only shows a preview."
      • addedOutput schema / properties / series / items / properties / observations / items / properties / available
        Added value: +{
        +  "description": "False when BLS published the \"-\" missing-value sentinel for this period.",
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / series / items / properties / observations / items / properties / value / description
        Previous value: -"Observation value as a string matching BLS output. Parse to float for arithmetic."New value: +"Raw observation value from BLS. The literal \"-\" means unavailable; check available before arithmetic and read footnotes for the reason."
      • changedOutput schema / properties / series / items / properties / observations / items / required
        Previous value: -[
        -  "year",
        -  "period",
        -  "value"
        -]New value: +[
        +  "year",
        +  "period",
        +  "value",
        +  "available"
        +]
      • changedOutput schema / properties / series / items / required
        Previous value: -[
        -  "seriesId",
        -  "observationCount",
        -  "observations"
        -]New value: +[
        +  "seriesId",
        +  "observationCount",
        +  "availableObservationCount",
        +  "observations"
        +]
      • addedOutput schema / properties / unavailableObservations
        Added value: +{
        +  "description": "Rows carrying the BLS \"-\" missing-value sentinel.",
        +  "type": "number"
        +}
  9. 2 tool updates
    • Changedbls_dataframe_describe3 fields changed
      • removedOutput schema / properties / dataframes / items / properties / max_rows
        Removed value: -{
        -  "description": "Materialization cap that produced truncated, when applicable.",
        -  "type": "number"
        -}
      • removedOutput schema / properties / dataframes / items / properties / truncated
        Removed value: -{
        -  "description": "True when the upstream had more rows than were materialized.",
        -  "type": "boolean"
        -}
      • changedOutput schema / properties / dataframes / items / required
        Previous value: -[
        -  "name",
        -  "source_tool",
        -  "query_params",
        -  "created_at",
        -  "expires_at",
        -  "row_count",
        -  "truncated",
        -  "column_schema"
        -]New value: +[
        +  "name",
        +  "source_tool",
        +  "query_params",
        +  "created_at",
        +  "expires_at",
        +  "row_count",
        +  "column_schema"
        +]
    • Changedbls_get_series5 fields changed
      • changedOutput schema / properties / dataset / description
        Previous value: -"Canvas dataframe handle — present when the observation volume exceeded the inline budget. Use bls_dataframe_query with dataset.name to run SQL across the full data."New value: +"Canvas dataframe handle — present when the observation volume exceeded the inline budget. Call bls_dataframe_describe with dataset.name to inspect column_schema, then use that table name in bls_dataframe_query SQL across the full data."
      • changedOutput schema / properties / dataset / properties / name / description
        Previous value: -"Canvas table name (df_XXXXX_XXXXX). Pass to bls_dataframe_query."New value: +"Canvas table name (df_XXXXX_XXXXX). Pass to bls_dataframe_describe first to inspect column_schema, then use it in bls_dataframe_query SQL."
      • removedOutput schema / properties / dataset / properties / truncated
        Removed value: -{
        -  "description": "True when the upstream response had more rows than the canvas materialization cap.",
        -  "type": "boolean"
        -}
      • changedOutput schema / properties / dataset / required
        Previous value: -[
        -  "name",
        -  "row_count",
        -  "expires_at",
        -  "truncated"
        -]New value: +[
        +  "name",
        +  "row_count",
        +  "expires_at"
        +]
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance for agents — names any SeriesID that returned zero observations, and reports when results spilled to canvas and SQL is needed for full access. Absent when every requested series returned data and it all fit inline."New value: +"Guidance for agents — names any SeriesID that returned zero observations, and reports the bls_dataframe_describe then bls_dataframe_query workflow when results spill to canvas. Absent when every requested series returned data and it all fit inline."
  10. 6 tool updates
    • Changedbls_dataframe_describe6 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": [
        +      "dataframes"
        +    ]
        +  },
        +  {
        +    "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: `canvas_unavailable`: The DataCanvas service is not configured for this deployment. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "canvas_unavailable"
        +          ],
        +          "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: -[
        -  "dataframes"
        -]
    • Changedbls_dataframe_query10 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "columns",
        +      "row_count",
        +      "rows"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / cap
        Added value: +{
        +  "description": "The preview or row_limit cap that was applied.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: The DataCanvas service is not configured for this deployment. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "canvas_unavailable"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / properties / row_count / description
        Previous value: -"Total rows the query produced (may exceed rows.length when capped by row_limit)."New value: +"Rows materialized by the query. Exact when register_as is used; otherwise equals row_limit when truncated is true."
      • addedOutput schema / properties / shown
        Added value: +{
        +  "description": "Number of rows returned inline.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "description": "True when the returned rows were capped.",
        +  "type": "boolean"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "columns",
        -  "row_count",
        -  "rows"
        -]
    • Changedbls_get_latest6 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": [
        +      "results",
        +      "succeeded",
        +      "failed"
        +    ]
        +  },
        +  {
        +    "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: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `series_locked`: The BLS database is temporarily locked for the requested series. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "invalid_api_key",
        +            "quota_exceeded",
        +            "series_locked"
        +          ],
        +          "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: -[
        -  "results",
        -  "succeeded",
        -  "failed"
        -]
    • Changedbls_get_series6 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": [
        +      "series",
        +      "spilled",
        +      "totalObservations",
        +      "seriesRequested",
        +      "annualAverageApplied"
        +    ]
        +  },
        +  {
        +    "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: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `quota_exceeded`: The BLS API 500 query/day limit has been reached. `request_rejected`: BLS returned a non-success status with a message matching no known failure mode — e.g. a rejected combination of request parameters. `series_not_found`: One or more SeriesIDs do not exist in BLS data. `series_locked`: The BLS database is temporarily locked for the requested series. `no_data_for_period`: No data is available for the requested year range. `calculations_not_supported`: calculations=true was requested for a survey that does not support it. `canvas_unavailable`: The result set exceeds the inline budget and canvas (DuckDB) is not configured. `canvas_registration_failed`: The result set exceeds the inline budget and canvas is configured, but registering the dataframe failed. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "invalid_api_key",
        +            "quota_exceeded",
        +            "request_rejected",
        +            "series_not_found",
        +            "series_locked",
        +            "no_data_for_period",
        +            "calculations_not_supported",
        +            "canvas_unavailable",
        +            "canvas_registration_failed"
        +          ],
        +          "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: -[
        -  "series",
        -  "spilled",
        -  "totalObservations",
        -  "seriesRequested",
        -  "annualAverageApplied"
        -]
    • Changedbls_list_surveys6 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": [
        +      "surveys",
        +      "total"
        +    ]
        +  },
        +  {
        +    "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: `invalid_api_key`: BLS rejected the configured BLS_API_KEY as invalid. `service_unavailable`: BLS /surveys API is unreachable or returns a non-200 response. `serialization_failure`: BLS /surveys response cannot be parsed (malformed JSON or unexpected schema). Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "invalid_api_key",
        +            "service_unavailable",
        +            "serialization_failure"
        +          ],
        +          "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: -[
        -  "surveys",
        -  "total"
        -]
    • Changedbls_search_series6 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": [
        +      "series",
        +      "totalCount",
        +      "capped",
        +      "catalogSize",
        +      "effectiveQuery",
        +      "limitApplied"
        +    ]
        +  },
        +  {
        +    "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: `catalog_unavailable`: The catalog index failed to load at startup. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "catalog_unavailable"
        +          ],
        +          "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: -[
        -  "series",
        -  "totalCount",
        -  "capped",
        -  "catalogSize",
        -  "effectiveQuery",
        -  "limitApplied"
        -]
  11. 2 tool updates
    • Changedbls_get_series5 fields changed
      • addedInput schema / properties / annual_average
        Added value: +{
        +  "default": false,
        +  "description": "When true, add each year's annual-average row to the observations. An annual average is the mean of that year's real periods, returned as an extra row named \"Annual\" with period M13 (monthly series), Q05 (quarterly) or S03 (semiannual) — not an additional month or quarter, so it must be excluded from any sum or average over observations. Defaults to false, which returns real periods only and is safe to aggregate directly. Independent of start_year/end_year. Surveys that publish no annual averages return the same rows either way; enrichment.annualAverageRows reports how many rows were actually added.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / annualAverageApplied
        Added value: +{
        +  "description": "Whether annual-average rows were requested. When false, observations hold real periods only and can be summed or averaged directly.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / annualAverageRows
        Added value: +{
        +  "description": "How many observations across all series are annual-average rows (period M13/Q05/S03). Present only when annual_average is true; 0 means none of the requested surveys publish annual averages.",
        +  "type": "number"
        +}
      • changedOutput schema / properties / series / items / properties / observations / items / properties / period / description
        Previous value: -"Period code (e.g. M01–M13, Q01–Q05, A01)."New value: +"BLS period code: M01–M12 are months, Q01–Q04 quarters, S01–S02 semiannual halves. M13, Q05 and S03 are not further periods — each is the mean of that year's real observations, named \"Annual\", and appears only when annual_average is true. Exclude them from any sum or average over observations."
      • changedOutput schema / required
        Previous value: -[
        -  "series",
        -  "spilled",
        -  "totalObservations",
        -  "seriesRequested"
        -]New value: +[
        +  "series",
        +  "spilled",
        +  "totalObservations",
        +  "seriesRequested",
        +  "annualAverageApplied"
        +]
    • Changedbls_list_surveys1 field changed
      • changedOutput schema / properties / surveys / items / properties / hasAnnualAverages / description
        Previous value: -"True when the survey publishes annual average observations."New value: +"True when BLS reports that the survey publishes annual average observations. Advisory only: it does not predict whether a given series returns annual-average rows for bls_get_series with annual_average=true — LN, CE, LA and SM report true yet return none. Read annualAverageRows on that response for what actually came back."
  12. 1 tool update
    • Changedbls_get_series3 fields changed
      • changedInput schema / properties / calculations / description
        Previous value: -"When true, request BLS-computed period-over-period calculations. The flag is a single boolean (you cannot select an individual calculation type), but the API returns whichever the survey supports: CPI and PPI return percent change only (the inflation rate), with no error. Only surveys that support neither net nor percent change (e.g. AP average price data) return an error — check bls_list_surveys first. Monthly-cadence series return each supported change type over 1, 3, 6, and 12-month intervals; other cadences return a subset."New value: +"When true, request BLS-computed period-over-period calculations. The flag is a single boolean (you cannot select an individual calculation type), but the API returns whichever the survey supports and omits the rest — CPI and PPI return percent change only (the inflation rate), and a survey that supports neither simply returns its observations without calculation fields. Requesting calculations never fails, so it is always safe to set; consult bls_list_surveys (allowsNetChange / allowsPercentChange) only to predict which fields will come back. Monthly-cadence series return each supported change type over 1, 3, 6, and 12-month intervals; other cadences return a subset."
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance for agents — e.g. when results spilled to canvas and SQL is needed for full access. Absent when all observations fit inline."New value: +"Guidance for agents — names any SeriesID that returned zero observations, and reports when results spilled to canvas and SQL is needed for full access. Absent when every requested series returned data and it all fit inline."
      • changedOutput schema / properties / seriesRequested / description
        Previous value: -"Number of SeriesIDs requested. Compare against the returned series[] length to detect series that returned no data."New value: +"Number of SeriesIDs requested. Do not compare it against series[] length to find empty series — a SeriesID that returned no data is still listed in series[] with observationCount 0. Check observationCount per entry, or read notice, which names every SeriesID that came back empty."
  13. 1 tool update
    • Changedbls_get_series5 fields changed
      • changedInput schema / properties / calculations / description
        Previous value: -"When true, request BLS-computed period-over-period calculations. The flag is a single boolean (you cannot select an individual calculation type), but the API returns whichever the survey supports: CPI and PPI return percent change only (the inflation rate), with no error. Only surveys that support neither net nor percent change (e.g. AP average price data) return an error — check bls_list_surveys first."New value: +"When true, request BLS-computed period-over-period calculations. The flag is a single boolean (you cannot select an individual calculation type), but the API returns whichever the survey supports: CPI and PPI return percent change only (the inflation rate), with no error. Only surveys that support neither net nor percent change (e.g. AP average price data) return an error — check bls_list_surveys first. Monthly-cadence series return each supported change type over 1, 3, 6, and 12-month intervals; other cadences return a subset."
      • addedOutput schema / properties / series / items / properties / observations / items / properties / netChange3Month
        Added value: +{
        +  "description": "3-month net change (when calculations=true).",
        +  "type": "string"
        +}
      • addedOutput schema / properties / series / items / properties / observations / items / properties / netChange6Month
        Added value: +{
        +  "description": "6-month net change (when calculations=true).",
        +  "type": "string"
        +}
      • addedOutput schema / properties / series / items / properties / observations / items / properties / pctChange3Month
        Added value: +{
        +  "description": "3-month percent change (when calculations=true).",
        +  "type": "string"
        +}
      • addedOutput schema / properties / series / items / properties / observations / items / properties / pctChange6Month
        Added value: +{
        +  "description": "6-month percent change (when calculations=true).",
        +  "type": "string"
        +}

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables access to Bureau of Labor Statistics (BLS) economic data including Consumer Price Index, employment statistics, and other labor market indicators. Supports fetching data series, listing available datasets, and retrieving metadata through natural language queries.
    4
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables querying and retrieving official U.S. labor market and price data from the Bureau of Labor Statistics, including unemployment, CPI, PPI, and employment figures, via series search, latest observations, and popular series.
    729 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides access to U.S. labor market data including employment statistics, Consumer Price Index inflation rates, and wage information. Users can query specific time series data or use shortcuts for common economic indicators like unemployment and industry-specific employment.
    3
    -
  • A
    license
    A
    quality
    D
    maintenance
    Provides curated US economic data from Treasury, FRED, BLS, BEA, and other sources through an MCP interface. Enables querying economic series, fetching data with provenance tracking, and accessing cached artifacts.
    9
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.