Bls Labor Mcp Server

io.github.cyanheads由 GitHub 帳號 cyanheads 發布v0.7.1更新於 Nov 1, 2026

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

已驗證Streamable HTTP可網頁執行金融資料與分析

概覽

AI 產生的概覽

取得美國勞工統計局資料(CPI、失業率、薪資、JOLTS 等),讓助理查找序列並抓取歷史或最新數值。

可以做什麼
  • 列出 BLS 調查計畫及其代碼與計算支援標記
  • 以自然語言、調查、地區或關鍵字搜尋離線序列目錄,解析 SeriesID
  • 批次取得時間序列歷史,可選年份範圍、變動計算與年度平均
  • 取得一個或多個序列的最新一期觀測值
  • 以唯讀 SQL 描述並查詢溢出到畫布的結果表(JOIN、聚合、視窗函式、CTE)
適用情境
當助理需要權威的美國勞動、物價或就業統計(通膨、失業、薪資、職缺),且應先查找正確序列而非猜測識別碼時適用。也適合需要對大批多序列結果做 SQL 分析的場合。
執行需求
可使用公開託管的 Streamable HTTP 端點,或透過 npx(Node.js 24+)或 Bun 在本機執行。BLS_API_KEY 中的免費 BLS API 金鑰為選用:無金鑰每日 25 次請求,有金鑰 500 次。需要連線至 BLS API 與 LABSTAT 檔案的網路;離線目錄於首次執行時建立。
安裝前請注意
BLS_API_KEY 屬於憑證,應以環境變數提供,不要提交進程式庫。請求會計入 BLS 每日配額,bls_get_latest 每個序列消耗一次查詢。資料框工具對暫存表執行 SQL,寫入與系統目錄會被拒絕;啟用後 bls_dataframe_drop 可刪除暫存表。選用的失敗負載記錄可能寫下呼叫參數。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Bls Labor Mcp Server,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。

交給代理程式安裝

把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。

閱讀 https://sourceweft.com/mcp/io.github.cyanheads%2Fbls-labor-mcp-server/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。

檢視代理程式所依據的安裝指南

其他 MCP 客戶端

把它新增到你客戶端的 mcpServers 設定中。

{
  "mcpServers": {
    "bls-labor": {
      "type": "http",
      "url": "https://bls-labor.caseyjhand.com/mcp"
    }
  }
}

README

@cyanheads/bls-labor-mcp-server

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

6 Tools by default · 7 with opt-in drop

Public Hosted Server: https://bls-labor.caseyjhand.com/mcp


Overview

US labor statistics from the Bureau of Labor Statistics: jobs, unemployment, wages, and inflation. Find series in plain language instead of decoding SeriesIDs, pull full history or the latest value, and run SQL over large multi-series results.

Tools

ToolDescription
bls_list_surveysList BLS survey programs (CPI, CPS, CES, JOLTS, PPI, OEWS, …) with codes, descriptions, and calculation-support flags.
bls_search_seriesSearch the BLS series catalog by natural language, survey, area, or keywords to resolve cryptic SeriesIDs.
bls_get_seriesFetch time-series data for 1–50 BLS series by SeriesID, with optional year range and period-over-period calculations.
bls_get_latestReturn the single most recent observation for one or more BLS series.
bls_dataframe_describeList canvas dataframes registered by bls_get_series or bls_dataframe_query — provenance, TTL, row count, column schema. Unavailable when CANVAS_PROVIDER_TYPE=none.
bls_dataframe_queryRun a SELECT against canvas dataframes registered by bls_get_series or an earlier register_as. Supports JOINs, aggregates, window functions, CTEs. Unavailable when CANVAS_PROVIDER_TYPE=none.
bls_dataframe_dropDrop a canvas dataframe by name. Available when BLS_DATAFRAME_DROP_ENABLED=true, unless CANVAS_PROVIDER_TYPE=none; TTL handles cleanup by default.

Capability reference

bls_list_surveys tool

  • Optional category filters survey programs by subject; returns codes, names, and calculation-support flags (allowsNetChange, allowsPercentChange, hasAnnualAverages). Each row's searchCoverage (indexed, composed, or none) says whether bls_search_series reaches the survey, with seriesIndexed for indexed ones.
  • Backed by the BLS surveys API with 30-day process-local caching. Annual-average support is advisory; read bls_get_series's annualAverageRows for the rows actually returned.

bls_search_series tool

  • Search by text or SeriesID, with optional survey, area, and seasonal_adjustment; blank filters are omitted. area takes a USPS or 2-digit FIPS state code; a 3-, 4-, 5-, or 7-digit CSA, CPI area, county or CBSA, or state + place code; otherwise a substring of area, title, or SeriesID (all-digit values outside those lengths add a notice). limit defaults to 10 and requests above 50 clamp to 50 with notice, with offset pagination. Exact SeriesIDs rank first, then series matching every query word, with any place the query names in full ahead of the rest; at equal score, current series rank first, then national ones, then the JOLTS aggregate.
  • Returns decoded SeriesIDs, titles, frequency, and independently optional startYear, endYear, and endPeriod coverage (for example, 1982–2005 Q04). Coverage describes the catalog snapshot, not continuous observations. Follow nextOffset while truncated is true; capped: true makes totalCount a lower bound, and paging stops at the FTS candidate pool.
  • Searches the offline LABSTAT index without using API quota; OE/OEWS is opt-in through BLS_CATALOG_INCLUDE_OES. Under survey: "OE" without those rows, it composes OEWS SeriesIDs from the OE code tables, up to 50 per search; each is marked composed: true and is unconfirmed until bls_get_series returns data for it. Unindexed surveys remain fetchable by SeriesID.

bls_get_series tool

  • Fetch up to 25 SeriesIDs without an API key or 50 with one per call, with a start_year/end_year window of up to 20 years, optional calculations, and annual_average. A start alone resolves the end to the current year capped at start + 19; an end alone is rejected. One batch consumes one API query; calculations depend on survey support (CPI/PPI return percent change only).
  • Returns local-catalog titles when available and optional BLS measure metadata, and observations with available; preserves the raw - missing-value sentinel, and keeps valid series in mixed batches. Enrichment reports the applied year window, calculations actually returned, annual-summary rows, and any upstream reductions or advisories.
  • SeriesIDs are trimmed, uppercased, and deduplicated before the cap; unprocessedSeriesIds lists the exact ordered remainder without automatic extra batches. Omitted year bounds use BLS's three-calendar-year default, subject to coverage.
  • Large results spill to dataset.name. With CANVAS_PROVIDER_TYPE=none, all fetched observations return inline.

bls_get_latest tool

  • Fetch the latest observation for up to 50 SeriesIDs (recommended ≤10). IDs are trimmed, uppercased, and deduplicated before the cap; unprocessedSeriesIds lists the exact ordered remainder. Each processed ID consumes one API query; use bls_get_series for a more efficient multi-series batch.
  • Returns successful results[] beside per-series failed[] entries. latestObservation.available distinguishes a published value from BLS's missing-value sentinel.

bls_dataframe_describe tool

  • Optional name describes one registered dataframe; omit it to list active dataframes for the tenant. Unavailable when CANVAS_PROVIDER_TYPE=none.
  • Returns source tool, query params, row count, TTL (created_at/expires_at, fixed at table creation), and column_schema; BLS columns are nullable. Registered-query types outside the canvas set (DECIMAL, HUGEINT, SMALLINT, lists) report as VARCHAR. Expired entries are removed when their canvas drop succeeds.

bls_dataframe_query tool

  • Run one SELECT against registered tables, with JOINs, aggregates, window functions, or CTEs. row_limit defaults to 1000; larger values clamp to 10000, and preview clamps to the applied row limit with requested/applied notices. Zero preview remains valid; writes, external-file reads, and system catalogs are denied.
  • Engine-setting functions (current_setting, current_schema, current_schemas, in_search_path) and query_table are denied. Unqualified current_schema keyword or column references are also denied; qualify a real column with its table alias (for example, t.current_schema). query() accepts one plain SQL string literal, checked recursively up to four levels; computed SQL strings are rejected. Reference staged tables directly for analysis.
  • Returns rows without consuming BLS API quota. Optional register_as stages the result with a fresh TTL for chained analysis. Unavailable when CANVAS_PROVIDER_TYPE=none.

bls_dataframe_drop tool

  • Required name identifies the dataframe to drop. Available only with BLS_DATAFRAME_DROP_ENABLED=true, and never with CANVAS_PROVIDER_TYPE=none; TTL handles cleanup by default.
  • Returns dropped: false for a missing table. A failed drop returns retryable canvas_drop_failed and leaves the dataframe registered.

Features

Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.

BLS-specific:

  • BLS API v2 client with retry/backoff and daily quota tracking
  • Offline series catalog search against LABSTAT flat files, indexed as an on-disk SQLite/FTS5 store — zero API quota for discovery; the OES/OEWS wage survey (~6M series) is opt-in via BLS_CATALOG_INCLUDE_OES
  • Typed error contracts for BLS-specific failure modes — quota exhaustion, locked database, calculations not supported
  • Period-over-period net/percent-change calculations via BLS's own server-side flag, consistent with BLS's published numbers
  • DataCanvas spillover (DuckDB, on by default) for large multi-series result sets — schema discovery and SQL access without re-querying the API

Agent-friendly output:

  • Provenance — canvas-spilled results carry a dataset.name handle plus row count and expiry; bls_search_series echoes effectiveQuery, catalogSize, and whether the FTS candidate pool was capped
  • Graceful partial failure — bls_get_latest returns per-item failed[] (seriesId + error) alongside successful results[] instead of failing the whole batch; bls_get_series keeps valid series when another SeriesID in the same batch is invalid or empty
  • Discriminated outputs — every observation carries an available boolean for BLS's - missing-value sentinel, so callers branch on a typed field instead of parsing raw values
  • Actionable notices — enrichment.notice explains empty results, canvas spillover, and unavailable data with concrete next steps (e.g. using bls_search_series to verify a SeriesID)

Getting started

Public Hosted Instance

A public instance is available at https://bls-labor.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:

json
{  "mcpServers": {    "bls-labor-mcp-server": {      "type": "streamable-http",      "url": "https://bls-labor.caseyjhand.com/mcp"    }  }}

Self-Hosted / Local

Add the following to your MCP client configuration file. A free BLS API key unlocks 500 queries/day — register at bls.gov/developers. The server works without a key at 25 req/day.

json
{  "mcpServers": {    "bls-labor-mcp-server": {      "type": "stdio",      "command": "bunx",      "args": ["@cyanheads/bls-labor-mcp-server@latest"],      "env": {        "MCP_TRANSPORT_TYPE": "stdio",        "MCP_LOG_LEVEL": "info",        "BLS_API_KEY": "your-key-here"      }    }  }}

Or with npx (no Bun required):

json
{  "mcpServers": {    "bls-labor-mcp-server": {      "type": "stdio",      "command": "npx",      "args": ["-y", "@cyanheads/bls-labor-mcp-server@latest"],      "env": {        "MCP_TRANSPORT_TYPE": "stdio",        "MCP_LOG_LEVEL": "info",        "BLS_API_KEY": "your-key-here"      }    }  }}

Or with Docker:

json
{  "mcpServers": {    "bls-labor-mcp-server": {      "type": "stdio",      "command": "docker",      "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "-e", "BLS_API_KEY=your-key-here", "ghcr.io/cyanheads/bls-labor-mcp-server:latest"]    }  }}

For Streamable HTTP, set the transport and start the server:

sh
MCP_TRANSPORT_TYPE=http MCP_SESSION_MODE=stateless MCP_HTTP_PORT=3010 BLS_API_KEY=... bun run start:http# Server listens at http://localhost:3010/mcp

Prerequisites

  • Bun v1.4.0 or higher (or Node.js v24+).
  • A free BLS API v2 key — register at bls.gov/developers. Grants 500 queries/day; the server also works without a key at 25 req/day.

Installation

  1. Clone the repository:
sh
git clone https://github.com/cyanheads/bls-labor-mcp-server.git
  1. Navigate into the directory:
sh
cd bls-labor-mcp-server
  1. Install dependencies:
sh
bun install
  1. Configure environment:
sh
cp .env.example .env# edit .env and set BLS_API_KEY

Configuration

All configuration is validated at startup via Zod schemas in src/config/server-config.ts.

VariableDescriptionDefault
BLS_API_KEYBLS v2 API key. Optional — 25 req/day without, 500 req/day with. Register free at bls.gov/developers.—
BLS_BASE_URLBLS API v2 base URL.https://api.bls.gov/publicAPI/v2
BLS_CATALOG_BASE_URLLABSTAT flat-file base URL. Override to point at a local mirror.https://download.bls.gov/pub/time.series
BLS_CATALOG_DB_PATHOn-disk SQLite catalog index — queried on demand and persisted across restarts. Empty uses an in-memory DB (re-harvested each boot). Mount a volume here in containers..cache/bls-catalog.db
BLS_CATALOG_CACHE_TTL_HOURSPer-survey catalog freshness window in hours — a survey re-harvests once its last success is older, and a failed survey's retry backoff is capped at this many hourly checks. Checked at startup and hourly while running.168 (7 days)
BLS_CATALOG_INCLUDE_OESInclude the OES/OEWS wage survey (~6M series / ~1.26 GB; Bun-only; multi-minute first harvest). Off by default — OES series stay fetchable by ID, and search composes them from the small OE code tables.false
BLS_OBSERVATIONS_MIRROR_ENABLEDServe observations from a local SQLite mirror instead of the live API (requires a one-time bootstrap — see below).false
BLS_DATASET_TTL_SECONDSPer-dataframe TTL for canvas-registered tables, in seconds.86400 (24 h)
BLS_DATAFRAME_DROP_ENABLEDExpose bls_dataframe_drop. TTL handles cleanup by default.false
CANVAS_PROVIDER_TYPEDataCanvas provider for tabular spillover of large result sets and the dataframe tools. Set to none to disable them. The Claude Desktop bundle ships without DuckDB and pins none.duckdb
MCP_TRANSPORT_TYPETransport: stdio or http.stdio
MCP_HTTP_PORTHTTP server port.3010
MCP_SESSION_MODESession mode. This server uses stateless; valid schema values are auto, stateful, and stateless. Schema-default auto resolves to stateful.stateless
MCP_AUTH_MODEAuth mode: none, jwt, or oauth.none
MCP_LOG_LEVELLog level (RFC 5424).info
LOGS_DIRDirectory for log files (Node.js only).<project-root>/logs
OTEL_ENABLEDEnable OpenTelemetry instrumentation.false
OTEL_EXPORTER_OTLP_ENDPOINTBase OTLP URL for traces and metrics; signal-specific endpoints override it.—
OTEL_EXPORTER_OTLP_LOGS_ENDPOINTOpt-in OTLP log endpoint. The base URL never enables log export.—
LOG_TOOL_FAILURE_PAYLOADSLog failed-call arguments and results, redacted by key name; secrets in free-form values remain.false
LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTESUTF-8 byte cap per logged failure payload.16384

See .env.example for the full list of optional overrides.

Observation mirror (optional)

For high-volume workloads, an opt-in local mirror serves bls_get_series / bls_get_latest from an embedded SQLite store of the LABSTAT files instead of the BLS API, removing the 500/day quota cap; requests fall back to the live API until it is built. Enable it with BLS_OBSERVATIONS_MIRROR_ENABLED=true, then run the one-time bootstrap: node dist/services/bls-observations/subprocess.js --init. Settings, survey coverage, harvest checkpoint and exit codes, fallback and calculation behavior, and upgrade notes are in docs/observation-mirror.md.

Running the server

Local development

  • Build and run:

    sh
    # One-time buildbun run rebuild
    # Run the built serverbun run start:stdio# orbun run start:http
  • Run checks and tests:

    sh
    bun run devcheck   # Lint, format, typecheck, securitybun run test       # Vitest test suitebun run lint:mcp   # Validate MCP definitions against spec

Docker

sh
docker build -t bls-labor-mcp-server .docker run --rm -e BLS_API_KEY=your-key -e MCP_TRANSPORT_TYPE=http -p 3010:3010 bls-labor-mcp-server

The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/bls-labor-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.

Project structure

DirectoryPurpose
src/index.tscreateApp() entry point — registers tools and initializes services.
src/configServer-specific environment variable parsing and validation with Zod.
src/mcp-server/toolsTool definitions (*.tool.ts).
src/services/bls-apiBLS API v2 service — batch fetch, latest-value GET, surveys metadata.
src/services/bls-catalogLABSTAT flat-file catalog — offline series index and search.
src/services/bls-observationsOptional LABSTAT observation mirror — embedded SQLite store, ingester, and refresh subprocess.
src/services/bls-periodsPeriod-code semantics shared by the API and mirror paths: annual-average codes (M13/Q05/S03) and the live API's period names.
src/services/canvas-bridgeDataCanvas bridge — dataframe registration, SQL gate, lifecycle management.
docs/design.mdFull tool surface specification, service architecture, and error contracts.
docs/observation-mirror.mdObservation mirror setup, coverage, and upgrade notes.
tests/Unit and integration tests mirroring src/.

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic
  • Use ctx.log for request-scoped logging, ctx.state for tenant-scoped storage
  • bls_search_series is the anchor tool — design workflows to call it before the API tools
  • Wrap BLS API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields

Contributing

Issues are welcome. Run checks and tests before submitting:

sh
bun run devcheckbun run test

License

Apache-2.0 — see LICENSE for details.

來源:README.md,提交 caef232

工具

6

bls_list_surveys

List BLS Surveys

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

輸入參數category

bls_search_series

Search BLS Series

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

輸入參數arealimitquery必填offsetsurveyseasonal_adjustment

bls_get_latest

Get Latest BLS Observation

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

輸入參數series_ids必填

bls_get_series

Get BLS Time-Series Data

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

輸入參數end_yearseries_ids必填start_yearcalculationsannual_average

bls_dataframe_describe

Describe BLS Dataframes

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.

輸入參數name

bls_dataframe_query

Query BLS Dataframes

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.

輸入參數sql必填previewrow_limitregister_as

版本歷史

10
  1. v0.7.1最新Nov 1, 2026
  2. v0.7.0Nov 1, 2026
  3. v0.6.0Oct 19, 2026
  4. v0.5.8Oct 11, 2026
  5. v0.5.7Sep 27, 2026
  6. v0.5.6Sep 24, 2026
  7. v0.5.4Sep 24, 2026
  8. v0.5.3Sep 22, 2026
  9. v0.5.2Sep 20, 2026
  10. v0.5.1Sep 16, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通必需25 分
  • 已宣告認證方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分

    請在儲存庫或註冊中心條目中宣告授權條款。