Skip to main content
Glama

bls-labor-mcp-server

Search BLS Series

bls_search_series
Read-only

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

Input Schema

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

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

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed12 schema 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."
  2. 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",
      +      "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"
      -]
  3. Changed7 schema 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"
      +]
  4. Changed9 schema 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"
      +]
  5. Changed6 schema fields changed
    • addedOutput schema / properties / areaFilter
      Added value: +{
      +  "description": "Area filter applied, if any. Absent when no area filter was passed.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / effectiveQuery
      Added value: +{
      +  "description": "Query string as the server received and searched on. Confirms interpretation for self-correction.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / limitApplied
      Added value: +{
      +  "description": "Result limit in effect (defaults to 10 when omitted).",
      +  "type": "number"
      +}
    • addedOutput schema / properties / seasonalFilter
      Added value: +{
      +  "description": "Seasonal-adjustment filter applied, if any. Absent when not passed.",
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / surveyFilter
      Added value: +{
      +  "description": "Survey filter applied, if any. Absent when no survey filter was passed.",
      +  "type": "string"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "series",
      -  "totalFound",
      -  "catalogSize"
      -]New value: +[
      +  "series",
      +  "totalFound",
      +  "catalogSize",
      +  "effectiveQuery",
      +  "limitApplied"
      +]
  6. Changed5 schema fields changed
    • changedOutput schema / properties / catalogSize / description
      Previous value: -"Total series in the loaded catalog index. Used to distinguish an empty-result search from a failed catalog load."New value: +"Total series in the loaded catalog index. Distinguishes an empty-result search from a failed catalog load."
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Guidance when no results matched — e.g. how to broaden the query or remove filters. Absent when results are returned.",
      +  "type": "string"
      +}
    • removedOutput schema / properties / total
      Removed value: -{
      -  "description": "Total matches in the catalog before the limit was applied.",
      -  "type": "number"
      -}
    • addedOutput schema / properties / totalFound
      Added value: +{
      +  "description": "Total matches in the catalog before the limit was applied.",
      +  "type": "number"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "series",
      -  "total",
      -  "catalogSize"
      -]New value: +[
      +  "series",
      +  "totalFound",
      +  "catalogSize"
      +]
  7. First observed

TDQS

A4.9/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, so the safety profile is covered. The description adds valuable behavioral details: it operates offline against an index of major surveys, returns results ranked by relevance, pages with limit and offset, and has a conditional behavior (OE survey only when the server sets BLS_CATALOG_INCLUDE_OES=true). These go beyond the annotations and schema, giving the agent a full picture of the tool's behavior.

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 well-structured and front-loaded with the core purpose, followed by usage guidance and then specifics like offline operation and survey codes. Every sentence adds value—no filler or redundancy. It is appropriately sized for a tool with six parameters and a rich behavior profile.

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 (6 params, output schema, annotations), the description is remarkably complete. It covers purpose, usage differentiation, offline operation, survey codes, conditional inclusion, area filter semantics, and paging. Since an output schema exists, the absence of detailed return format is acceptable. Nothing an agent needs to correctly invoke the tool is missing.

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

Parameters4/5

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

Schema description coverage is 100%, so the schema already documents all parameters. The description adds a few extra nuances not in the schema, such as the survey code list and the OE conditional, and notes that the query also accepts a SeriesID for exact lookup. It also mentions that omitting the area filter lets national series rank first. These are helpful but not extensive, so a 4 is appropriate (above the baseline 3 for full schema coverage).

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 (search) and resource (BLS series catalog), explains the purpose (resolving cryptic SeriesIDs), and explicitly differentiates from the sibling bls_get_series by saying 'Use this before bls_get_series when you have a concept but not a SeriesID.' It also details what it returns (decoded components, plain-language names, ranked and paged). This is clear and distinct.

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 explicitly instructs when to use this tool versus bls_get_series, noting that series not in the indexed surveys should be fetched by SeriesID with bls_get_series. It also highlights the offline operation and no API quota consumed, which is a practical advantage. This leaves no ambiguity about the appropriate context.

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.