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 58 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

TDQS

A4.4/5.0

Scored across 6 tools

Disambiguation4/5

Most tools have clearly distinct roles: survey discovery, series search, series retrieval, latest-value convenience, and dataframe inspection/querying. The only mild overlap is between bls_get_latest and bls_get_series, but their descriptions clearly separate 'latest single observation' from 'full time-series fetch'.

Naming Consistency3/5

Most tools follow a bls_<verb>_<noun> pattern (get_series, list_surveys, search_series), but the two dataframe tools use bls_dataframe_<verb> (describe, query), placing the noun before the verb. The mixed convention is readable but not fully consistent.

Tool Count5/5

Six tools form a well-scoped toolkit covering discovery, retrieval, and local analysis of BLS data. Each tool has a clear purpose, and the count aligns well with the server's domain without feeling bloated or thin.

Completeness5/5

The toolset covers the full workflow: discovering surveys, resolving SeriesIDs, fetching raw series, retrieving latest values, and querying materialized dataframes. The dataframe tools also address context-window spillover, making the surface feel complete for BLS labor data analysis.

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. Requires CANVAS_PROVIDER_TYPE=duckdb.

ParametersJSON Schema
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

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

TDQS

A4.2/5.0
Behavior4/5

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

Beyond annotations (readOnlyHint, idempotentHint), the description discloses two extra behavioral traits: 'Lazy-sweeps expired tables before responding' and 'Requires CANVAS_PROVIDER_TYPE=duckdb'. These are valuable side-effect and environment requirements an agent cannot infer from annotations alone, significantly improving transparency.

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: first sentence states the core function, second gives usage guidance, third discloses side effects and requirements. Information is front-loaded, no filler or redundancy, and every sentence earns its place.

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

Completeness4/5

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

With a rich output schema and a well-documented parameter, the description covers purpose, usage timing, environmental prerequisite, and a side effect. It does not explicitly clarify that it is not for data retrieval, but the usage note about writing SQL implies this. Overall, the description supplies the key operational context an agent needs to choose and invoke the tool correctly.

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

Parameters3/5

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

Input schema already fully documents the single optional 'name' parameter, including examples of valid values (df_XXXXX_XXXXX names, register_as names) and behavior when omitted. The description adds no new parameter-level meaning; with 100% schema coverage, 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?

The description states a specific verb ('List') and resource ('canvas dataframes'), and enumerates the provenance from specific sibling tools (bls_get_series, bls_dataframe_query). It clarifies the tool's metadata-focused role, distinguishing it from query tools like bls_dataframe_query, and lists output fields (TTL, row count, column schema), making the purpose unambiguous.

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 advises 'Use before writing SQL to confirm column names and types,' giving a clear when-to-use context. It does not provide explicit when-not-to-use or alternative routing, but the mention of materialized dataframes and the read-only metadata focus strongly implies this is for inspection, not querying, which is adequate differentiation among siblings.

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. Requires CANVAS_PROVIDER_TYPE=duckdb.

ParametersJSON Schema
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. Defaults to row_limit. Set lower (e.g. 50) when chaining via register_as and only a sample is needed immediately.
row_limitNoHard cap on rows materialized in the response (default 1000, max 10000). 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

ParametersJSON 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.
noticeNoGuidance 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.
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 for the newly registered dataframe, when applicable.
registered_asNoSet when register_as was supplied and the result was materialized.

TDQS

A5/5.0
Behavior5/5

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

Annotations already declare readOnlyHint and idempotentHint, but the description goes further by listing rejected operations (writes, DDL, DROP, COPY, PRAGMA, ATTACH, external-file table functions), denied system catalogs, zero BLS quota consumption, and the fresh TTL behavior for register_as. No contradiction with annotations.

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

Conciseness5/5

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

The description is a single well-structured paragraph that front-loads the core purpose, then covers limitations, prerequisites, and optional features. Every sentence carries information; there is no filler or redundancy.

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

Completeness5/5

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

Given the complexity (SQL engine, multiple constraints), the description covers prerequisites, supported SQL features, rejected operations, system catalog denial, quota implications, and chaining via register_as. Since an output schema exists, return format is not required. Nothing essential is missing.

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

Parameters5/5

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

Schema coverage is 100% and each parameter has a description, but the tool description adds significant extra context: sql includes an example and explains referencing dataframes, preview clarifies defaulting to row_limit and suggests lowering for chaining, row_limit explains the hard cap and on-canvas persistence, and register_as explains TTL and chaining benefits. This enriches meaning beyond 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?

The description states a specific action ('Run a single-statement SELECT against the canvas dataframes') and clearly identifies the resource (dataframes registered by bls_get_series or register_as). It distinguishes itself from sibling bls_dataframe_describe (which lists dataframes) and bls_get_series (which fetches series), so an agent can differentiate without opening schemas.

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

Usage Guidelines5/5

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

It explicitly directs the agent to use bls_dataframe_describe for listing available dataframes, and references bls_get_series as the source of registered dataframes. It also states a prerequisite (CANVAS_PROVIDER_TYPE=duckdb) and clarifies that writes and system catalogs are rejected, giving clear when-to-use and when-not-to-use guidance.

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 one or more BLS series. Use for "what is X right now" questions — the current unemployment rate, the latest CPI reading, etc. Each series consumes one API query against the 500/day limit; for the current value of many series, bls_get_series with a 1-year window is more quota-efficient (one query for up to 50 series). Recommended limit: 10 series; maximum: 50.

ParametersJSON Schema
NameRequiredDescriptionDefault
series_idsYesOne or more BLS SeriesIDs (1–50). Each consumes one daily API query. Use bls_search_series to resolve concepts to SeriesIDs. Recommended: ≤10 series.

Output Schema

ParametersJSON 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 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.
resultsNoSuccessfully fetched series with their latest observations. Series that failed appear in failed[] instead.
succeededNoNumber of series with a successfully fetched observation.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, openWorldHint, and idempotentHint, so the safety profile is covered. The description adds value by disclosing quota consumption ('Each series consumes one API query against the 500/day limit') and performance limits ('Recommended limit: 10 series; maximum: 50'), which are not in the annotations. No contradictions.

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

Conciseness5/5

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

The description is compact yet information-dense. It leads with the core action, then gives usage context, quota implications, and limits—all in four sentences without redundancy. Every sentence earns its place.

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

Completeness5/5

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

Given the tool's simplicity (one parameter, output schema present) and annotations covering read-only/idempotent behavior, the description covers all needed aspects: purpose, usage, quota, alternatives, and limits. There is nothing an agent needs to know that 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?

The schema already provides 100% coverage for the single parameter series_ids, including details about range, quota, and how to resolve SeriesIDs. The description repeats this information but does not add any new meaning beyond the schema. Thus 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?

The description clearly states the tool's function: 'Return the single most recent observation for one or more BLS series.' It also provides concrete use cases ('what is X right now' questions) and explicitly differentiates from the sibling bls_get_series, making it unambiguous which tool to select for this purpose.

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?

The description gives explicit guidance on when to use this tool ('Use for "what is X right now" questions') and when to prefer an alternative ('for the current value of many series, bls_get_series with a 1-year window is more quota-efficient'). It also sets recommended and maximum limits, leaving no ambiguity about appropriate usage.

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-only
Inspect

Fetch time-series data for 1–50 BLS series by SeriesID in a single API request (one query against the 500/day limit). Supports optional year range (up to 20 years per request) and BLS-computed period-over-period calculations (net change and percent change; a survey returns whichever it supports and silently omits the rest — CPI and PPI return percent change only, the inflation rate). BLS can publish a '-' missing-value sentinel; check observation.available before arithmetic. Set annual_average to add each year's annual-average row, which is that year's mean rather than an additional period. When the total observation count would exceed the inline context budget, results spill to a canvas dataframe and the response includes a dataset.name handle. Call bls_dataframe_describe with that name to inspect the dataframe schema, then use the name in bls_dataframe_query SQL. Use bls_search_series first if you need to resolve a concept to a SeriesID.

ParametersJSON Schema
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_idsYesOne or more BLS SeriesIDs (1–50). The entire batch counts as one API query. Use bls_search_series to resolve concepts to SeriesIDs.
start_yearNoStart 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).
calculationsNoWhen 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.
annual_averageNoWhen 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.

Output Schema

ParametersJSON 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), 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.
calculationsAppliedNoWhether 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.
annualAverageAppliedNoWhether annual-average rows were requested. When false, observations hold real periods only; filter on available before aggregation.
availableObservationsNoRows with a published numeric value.
unavailableObservationsNoRows carrying the BLS "-" missing-value sentinel.

TDQS

A5/5.0
Behavior5/5

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

Beyond the readOnlyHint and openWorldHint annotations, the description discloses important quirks: surveys silently omit unsupported calculation fields, BLS may return '-' missing values and 'check observation.available', results spill to a canvas dataframe when too large, and annual averages are extra rows not real periods. None of this contradicts the annotations, and it materially informs safe invocation and interpretation.

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

Conciseness5/5

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

The description is long but dense, and each sentence adds operational value: batching semantics, missing-value sentinels, spill behavior, annual-average caveats, and sibling routing. The most important usage constraint is front-loaded in the first sentence, and parameter-specific details are organized in the schema descriptions. Nothing feels like 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?

Given the five parameters, the output schema, the sibling tools, and the BLS API's quirks, the description covers everything an agent needs: limits, defaults, error prone edge cases, calculation behavior, spill handling, and how to inspect results. The presence of an output schema means return-value details don't need to be repeated, and the description appropriately focuses on invocation semantics.

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

Parameters5/5

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

Although schema coverage is 100%, the description adds substantial meaning beyond the schema. For example, it explains that annual_average rows use period codes M13/Q05/S03 and must be excluded from sums, that start_year alone resolves end_year to the current year capped at start_year+19, and that the calculations flag returns survey-specific fields. These details are essential for correct parameter use.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Fetch time-series data for 1–50 BLS series by SeriesID in a single API request.' It also immediately distinguishes the tool from siblings by noting the query-limit behavior and directing concept resolution to bls_search_series. This leaves no ambiguity about what the tool does or how it differs from nearby tools.

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?

The description gives explicit when-to-use guidance: use bls_search_series first to resolve concepts to SeriesIDs, use bls_dataframe_describe to inspect spilled dataframe results, and consult bls_list_surveys only to predict which calculation fields will come back. It also explains when not to rely on those alternatives, such as noting that requesting calculations never fails. This is strong routing and exclusion guidance.

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; bls_search_series covers only the surveys in its offline index, and series in the others are fetched by SeriesID with bls_get_series. Optional category filter narrows results to prices, employment, wages, productivity, injuries, or time_use surveys.

ParametersJSON Schema
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

ParametersJSON 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.5/5.0
Behavior4/5

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

Annotations already carry readOnlyHint=true and idempotentHint=true, so the description's job is lighter. It adds useful context about the nature of the data (metadata about calculation support and annual averages) and clarifies that the tool is a discovery step with optional filtering. No extra behaviors are disclosed, but given the annotations, this is adequate.

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

Conciseness5/5

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

The description is two sentences with zero redundancy. The core purpose is front-loaded, the usage guidance is embedded, and the category filter is mentioned last. Every sentence earns its place with 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?

For a simple list/discovery tool with one optional parameter and an existing output schema, the description covers purpose, usage context, and relationship to siblings. Nothing critical is missing—an agent can safely call it without needing additional information.

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%; the category parameter is already fully explained in the schema (enum values, that a survey can appear under multiple categories). The description merely repeats the enum list, adding no new meaning. Baseline 3 is appropriate because the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List') and resource ('BLS survey programs') with details about what is included (abbreviation codes, full names, metadata). It distinguishes itself from siblings by explicitly contrasting coverage with bls_search_series and bls_get_series, so an agent can tell exactly which tool fits.

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?

The description gives explicit when-to-use guidance: 'Use to discover which survey covers a topic before calling bls_search_series.' It also explains the limitation of bls_search_series (offline index) and the alternative for other series (bls_get_series), making the decision path unambiguous.

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; OE only when the server sets BLS_CATALOG_INCLUDE_OES=true); series in other surveys are fetched by SeriesID with bls_get_series. Area filter accepts state names, MSA names, or FIPS area codes.

ParametersJSON Schema
NameRequiredDescriptionDefault
areaNoState 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.
limitNoMaximum number of results to return (1–50, default 10).
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, 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.
seasonal_adjustmentNoWhen true, return only seasonally adjusted series. When false, return only not-seasonally-adjusted. Omit to return both.

Output Schema

ParametersJSON 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). 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.
noticeNoGuidance 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.
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.7/5.0
Behavior5/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, and the description adds meaningful behavioral detail: it operates offline against an index, consumes no API quota, only covers listed indexed surveys, and includes OE only when the server sets BLS_CATALOG_INCLUDE_OES=true. This is additive and consistent with the annotations, with no contradiction.

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

Conciseness5/5

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

The description is dense but not padded: the first sentence front-loads purpose and output, and every subsequent sentence earns its place—usage guidance, offline behavior, supported surveys, and area filtering. The long survey-code list is necessary precision, not redundancy.

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?

The description covers purpose, when to use it, output components, ranking and pagination, offline/no-quota behavior, supported surveys, and the boundary case of non-indexed surveys. Because an output schema exists, return-value details are already covered structurally, so nothing needed for correct invocation is missing.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents every parameter thoroughly, including examples, defaults, limits, and case-insensitivity. The description repeats some parameter semantics, such as the survey-code list and area filter formats, but adds little parameter-level meaning beyond what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Search the BLS series catalog by natural language query, survey code, geographic area, or keywords to resolve cryptic SeriesIDs.' It also distinguishes the tool from bls_get_series by framing it as the pre-lookup step and by describing its output: decoded components, plain-language names, relevance ranking, and pagination.

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?

The description gives explicit usage guidance: 'Use this before bls_get_series when you have a concept but not a SeriesID.' It also states an exclusion—series in non-indexed surveys are fetched by SeriesID with bls_get_series—and adds context that it operates offline with no API quota consumed, helping an agent choose it over an API-backed alternative.

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. 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."
  2. 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"
        +}
  3. 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."
  4. 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."
  5. 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"
        +}
  6. 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."
  7. 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"
        -]
  8. 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."
  9. 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."
  10. 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"
        +}
  11. 1 tool update
    • Changedbls_search_series7 fields changed
      • addedOutput schema / properties / cap
        Added value: +{
        +  "description": "The result limit that capped the returned list.",
        +  "type": "number"
        +}
      • changedOutput schema / properties / capped / description
        Previous value: -"True when the FTS candidate pool reached the internal cap (~1000). totalFound 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 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."
      • addedOutput schema / properties / shown
        Added value: +{
        +  "description": "Number of series returned in this response.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / totalCount
        Added value: +{
        +  "description": "Total candidates scored before the limit was applied. A lower bound when capped is true — the catalog index may contain more matching series.",
        +  "type": "number"
        +}
      • removedOutput schema / properties / totalFound
        Removed value: -{
        -  "description": "Total candidates scored before the limit was applied. A lower bound when capped is true — the catalog index may contain more matching series.",
        -  "type": "number"
        -}
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "description": "True when more candidates matched than the limit returned.",
        +  "type": "boolean"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "series",
        -  "totalFound",
        -  "capped",
        -  "catalogSize",
        -  "effectiveQuery",
        -  "limitApplied"
        -]New value: +[
        +  "series",
        +  "totalCount",
        +  "capped",
        +  "catalogSize",
        +  "effectiveQuery",
        +  "limitApplied"
        +]
  12. 3 tool updates
    • Changedbls_dataframe_query1 field changed
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance when results were capped by row_limit — e.g. to use register_as to persist all rows or increase row_limit. Absent when all rows fit in the response."New 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."
    • Changedbls_get_latest2 fields changed
      • changedOutput schema / properties / results / description
        Previous value: -"Latest observation for each requested series, in request order."New value: +"Successfully fetched series with their latest observations. Series that failed appear in failed[] instead."
      • changedOutput schema / properties / results / items / properties / latestObservation / description
        Previous value: -"Most recent observation. Absent when the series returned no data."New value: +"Most recent observation."
    • Changedbls_search_series9 fields changed
      • addedOutput schema / properties / capped
        Added value: +{
        +  "description": "True when the FTS candidate pool reached the internal cap (~1000). totalFound 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.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / series / items / properties / area
        Added value: +{
        +  "description": "Geographic area name, when decoded.",
        +  "type": "string"
        +}
      • removedOutput schema / properties / series / items / properties / areaName
        Removed value: -{
        -  "description": "Geographic area name, when decoded.",
        -  "type": "string"
        -}
      • addedOutput schema / properties / series / items / properties / item
        Added value: +{
        +  "description": "Item or subject name, when decoded.",
        +  "type": "string"
        +}
      • removedOutput schema / properties / series / items / properties / itemName
        Removed value: -{
        -  "description": "Item or subject name, when decoded.",
        -  "type": "string"
        -}
      • changedOutput schema / properties / series / items / properties / seasonal / description
        Previous value: -"True when seasonally adjusted."New value: +"Seasonality descriptor matching the data-tool form: \"Seasonally Adjusted\" or \"Not Seasonally Adjusted\"."
      • changedOutput schema / properties / series / items / properties / seasonal / type
        Previous value: -"boolean"New value: +"string"
      • changedOutput schema / properties / totalFound / description
        Previous value: -"Total matches in the catalog before the limit was applied."New value: +"Total candidates scored before the limit was applied. A lower bound when capped is true — the catalog index may contain more matching series."
      • changedOutput schema / required
        Previous value: -[
        -  "series",
        -  "totalFound",
        -  "catalogSize",
        -  "effectiveQuery",
        -  "limitApplied"
        -]New value: +[
        +  "series",
        +  "totalFound",
        +  "capped",
        +  "catalogSize",
        +  "effectiveQuery",
        +  "limitApplied"
        +]

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.
    24 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.