Skip to main content
Glama

bls-labor-mcp-server

Get BLS Time-Series Data

bls_get_series
Read-only

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.

Input Schema

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

TableJSON Schema
NameRequiredDescriptionDefault
errorNoPresent when the call failed. Absent on success.
noticeNoGuidance 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.
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 requested.
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.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed6 schema 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."
  2. Changed11 schema 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"
      +}
  3. Changed5 schema 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."
  4. Changed6 schema fields changed
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / additionalProperties
      Added value: +false
    • changedOutput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedOutput schema / anyOf
      Added value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "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"
      -]
  5. Changed5 schema 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"
      +]
  6. Changed3 schema 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."
  7. Changed5 schema 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"
      +}
  8. Changed6 schema fields changed
    • changedInput schema / properties / calculations / description
      Previous value: -"When true, request BLS-computed net change and percent change together (cannot request one independently). Not all surveys support this — check bls_list_surveys first. The API returns an error if requested for an unsupported survey."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."
    • addedOutput schema / properties / calculationsApplied
      Added value: +{
      +  "description": "Whether BLS net/percent-change calculations were requested.",
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / endYearApplied
      Added value: +{
      +  "description": "End year in effect, when a range was requested.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / seriesRequested
      Added value: +{
      +  "description": "Number of SeriesIDs requested. Compare against the returned series[] length to detect series that returned no data.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / startYearApplied
      Added value: +{
      +  "description": "Start year in effect, when a range was requested.",
      +  "type": "number"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "series",
      -  "spilled",
      -  "totalObservations"
      -]New value: +[
      +  "series",
      +  "spilled",
      +  "totalObservations",
      +  "seriesRequested"
      +]
  9. Changed3 schema fields changed
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Guidance for agents — e.g. when results spilled to canvas and SQL is needed for full access. Absent when all observations fit inline.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / totalObservations
      Added value: +{
      +  "description": "Total observation rows across all requested series.",
      +  "type": "number"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "series",
      -  "spilled"
      -]New value: +[
      +  "series",
      +  "spilled",
      +  "totalObservations"
      +]
  10. First observed

TDQS

A4.4/5.0
Behavior4/5

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

Annotations include readOnlyHint=true and openWorldHint=true, but the description adds substantial behavioral detail: the API's silent omission of calculations, the '-' missing-value sentinel, the annual average being a mean rather than a period, and the spill-to-dataframe behavior. The description does not contradict the annotations.

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

Conciseness4/5

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

The description is dense but front-loaded with the core function and limits, then covers important behavioral caveats. It is longer than strictly minimal, but each sentence adds value (e.g., sentinel, annual average semantics). It is well-structured but slightly verbose for the technical content, hence a 4.

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 complexity (5 parameters, 100% schema coverage, output schema present, multiple sibling tools), the description covers all critical aspects: request limits, year range rules, calculations behavior, annual average semantics, missing-value handling, and dataframe spill workflow. The presence of output schema and rich schema coverage means the description doesn't need to explain return values, so nothing essential is missing.

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

Parameters3/5

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

Schema coverage is 100%, so the schema already documents all parameters well. The description adds context like the 20-year limit and the annual average's period code (M13, Q05), but it mostly paraphrases the schema. It does not introduce major new meaning beyond the schema, so a baseline of 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 ('Fetch') and resource ('time-series data for 1–50 BLS series'), and clearly distinguishes itself from siblings by mentioning use cases like bls_search_series for resolving concepts and the dataframe tools for spills. The scope and limits are explicit, so an agent knows exactly what this tool does relative to others.

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 provides explicit when-to-use guidance: 'Use bls_search_series first if you need to resolve a concept to a SeriesID', and explains when results spill to a dataframe, directing to bls_dataframe_describe and bls_dataframe_query. It also clarifies when to omit year parameters. Alternatives are named and conditions are given, leaving no ambiguity.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.