Labor Market Intelligence
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Labor Market IntelligenceCompare the employment outlook for registered nurses and software engineers"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Labor Market Intelligence — Remote MCP Server
A read-only remote MCP server exposing U.S. Bureau of Labor Statistics (BLS) and FRED (Federal Reserve Bank of St. Louis) data to Claude as a custom connector — for career and labor-market research: employment trends, unemployment, job openings, hires, quits, wages, occupational outlook, and industry comparisons.
Runs on Cloudflare Workers. Cost: $0/month on Cloudflare's free tier.
Built incrementally against a fully verified implementation plan — every BLS and FRED endpoint, series ID, and data-shape quirk referenced in this codebase was confirmed against the live APIs (not assumed from documentation alone) before being implemented.
Status
All 10 implementation checkpoints complete and live-verified against the deployed Cloudflare Worker. 89 unit tests, clean typecheck, all 16 tools confirmed working against real BLS/FRED data.
Connecting to Claude
In Claude, go to Settings → Connectors → Add custom connector.
Remote MCP server URL:
https://<your-worker>.<your-subdomain>.workers.dev/mcp/<MCP_PATH_TOKEN>— treat this URL as a credential; the token is the only thing authorizing access.OAuth Client ID / Secret: leave both blank. This server is authless — the secret path is the credential, and Claude supports authless remote MCP servers natively.
Transport: Streamable HTTP (SSE is the legacy fallback).
Tools (16)
Low-level source tools — thin, faithful passthrough to BLS/FRED
Tool | What it does |
| Full-text search over FRED series |
| Fetch observations for a known FRED series ID |
| Fetch only the most recent FRED observation |
| Fetch up to 50 BLS series over up to a 20-year span; |
| List all 70 BLS survey program abbreviations |
| List BLS's "most requested" series (not universal — returns nothing for EP/JOLTS/OR) |
| Search ~13 curated headline indicators (unemployment, JOLTS metrics, payrolls, etc.) for their BLS/FRED IDs |
| Search ~1,113 SOC occupation titles for their BLS Employment Projections series ID |
Research tools — composed, higher-level analysis
Tool | What it does |
| Change and CAGR for one BLS/FRED series over a date range |
| Compare 2-10 BLS/FRED series (can mix sources) side by side |
| Snapshot: unemployment, payrolls, openings, hires, quits, layoffs — each with 1mo/12mo change |
| Long-run BLS Employment Projections outlook for a whole industry |
| Full BLS Employment Projections outlook for one occupation (employment, openings, median wage) |
| Compare 2-20 occupations' outlook in a single batched BLS call |
| Trend/CAGR for an aggregate wage measure (default: average hourly earnings) |
| Connectivity check; uses no BLS/FRED quota |
Every tool is annotated readOnlyHint: true and enforced by an automated test
(test/unit/server.test.ts) — no tool can mutate state, and none accepts a
caller-supplied URL to fetch.
What each source actually provides
Verified against the live APIs, not assumed from documentation:
FRED provides broad macro context (GDP, rates, recession indicators), unit transforms, and a real full-text series search. It also republishes many BLS series (UNRATE, PAYEMS, JOLTS metrics) with a clean uniform cadence.
BLS is authoritative for anything occupational: Employment Projections (
EP, outlook/openings/wage) and OEWS (OE, current wages) exist only on the BLS side — FRED does not carry the National Employment Matrix.OEWS has no history via the API — every series returns exactly one reference year, confirmed by requesting a 10-year range and getting nine "No Data Available" messages plus one datapoint. Occupational wage trends are not retrievable from this API; use
get_occupation_outlookfor a current-year median wage snapshot instead.Employment Projections is not a time series — one base year + one projection year (currently ~10 years out), updated at most twice a year.
Annual openings figures include replacement demand (workers exiting or transferring out), not just net employment growth — a common misreading.
No official BLS series-search API exists.
search_indicatorsandsearch_occupationsare backed by a catalog derived from BLS's own flat files and cross-validated during the build (seescripts/build-catalog.ts), not hand-typed or guessed.
Attribution
Every BLS-derived response carries the retrieval timestamp and the exact disclaimer required by BLS's Terms of Service: "BLS.gov cannot vouch for the data or analyses derived from these data after the data have been retrieved from BLS.gov." FRED-derived responses carry their own source attribution.
Anything this server computes (percent change, CAGR, month-over-month deltas)
is returned under a separate computedByServer field, explicitly labeled as
server-calculated — never presented as an official BLS or FRED statistic.
Tool instructions direct Claude to preserve both when answering.
Security model
Read-only. No tool mutates state or accepts a caller-supplied URL.
Secret-path authentication. The endpoint is
/mcp/<256-bit token>. Claude's connector UI accepts a URL but not custom headers, so the credential lives in the path. Comparison is constant-time over SHA-256 digests; every failure (wrong token, missing token, unknown route) returns an identical 404 — no oracle for guessing.Inbound rate limiting. ~60 requests/minute per IP (
cf-connecting-ip, set by Cloudflare and unspoofable by the client), checked before auth so a flood can't spend CPU on token comparison. Backed by Workers KV; fails open (allows) if KV isn't bound.Outbound BLS budget guard. A circuit breaker defaulting to 450 of BLS's 500/day registered-key quota — exhausting it fails the call before any network request, protecting the real quota from a runaway loop.
Secrets never leave the server.
BLS_API_KEY,FRED_API_KEY, andMCP_PATH_TOKENlive only as Workers secrets — never returned in a tool response, never logged.src/lib/logging.tsredacts known secret values and anyapi_key=/registrationkey=pattern from every log record; this is asserted by unit tests, not just intended.Known limitation: Cloudflare's own platform request logs (and
wrangler tail) record the full request URL, including the path token — this is outside application code's control. Don't share raw log output publicly; rotate the token (wrangler secret put MCP_PATH_TOKEN, then re-paste the new URL into Claude) if you ever do.
Caching
Workers KV, two-tier: a "fresh" entry per the TTL table below, plus a 35-day
"stale backup" written alongside every success. If a live call fails or the
BLS budget is exhausted, the stale backup is served instead of failing
outright — flagged explicitly in the response's limitations field so
Claude never presents stale data as current without saying so.
Data | TTL | Why |
Employment Projections / OEWS | 30 days | Updated at most twice a year |
BLS surveys / popular-series lists | 7 days | Near-static |
FRED search | 24 hours | Stable |
Monthly series (CES/CPS/JOLTS) | 6 hours | Monthly releases |
| 1 hour | Freshness matters most here |
Cache keys are derived only from the tool name and its arguments — never from environment or secrets — so no key material can leak into a cache key.
Project structure
src/
index.ts Worker entry: routing, auth, rate limiting
server.ts MCP server construction + tool registration
env.ts Env typing + secret names
errors.ts Typed error hierarchy (network/timeout/429/5xx/BLS-200-with-error-body)
sources/
http.ts Shared fetch: timeout, retry/backoff
bls.ts BLS v2 client
fred.ts FRED client
catalog/
occupations.json 1,113 SOC occupations -> EP series ID (build-generated, validated)
industries.json 423 EP industries -> series ID (build-generated, validated)
indicators.ts ~13 curated headline indicators (individually live-verified)
search.ts Shared token-matching + relevance-ranking search
tools/
source/ Thin passthrough tools
research/ Composed analysis tools
lib/
cache.ts Workers KV two-tier cache
ratelimit.ts BLS daily budget guard + inbound per-IP limiter
envelope.ts Response envelope: citations, timestamps, disclaimers
stats.ts Deterministic trend math
logging.ts Structured logs with secret redaction
scripts/
build-catalog.ts Regenerates + validates the occupation/industry catalog
test/
unit/ Mocked, run on every `npm test`
live/ Real API calls, opt-in via `npm run test:live`Local development
npm install
cp .dev.vars.example .dev.vars # fill in real keys for local testing
npx wrangler dev --port 8787
npm test # unit suite (mocked, no network)
npm run typecheck
npm run build:catalog # regenerate the occupation/industry catalog from BLS's own flat filesTo verify against real BLS/FRED data locally (never commits or logs the keys):
BLS_API_KEY=your_key FRED_API_KEY=your_key npm run test:liveDeployment
npx wrangler login
npx wrangler kv namespace create CACHE # one-time; paste the resulting id into wrangler.toml
npx wrangler secret put BLS_API_KEY
npx wrangler secret put FRED_API_KEY
npx wrangler secret put MCP_PATH_TOKEN # generate with: openssl rand -hex 32
npx wrangler deploy
curl https://<your-worker>.<your-subdomain>.workers.dev/healthSecrets and the KV binding persist across wrangler deploy — you only set
them once, not on every deploy.
Known limitations
Employment Projections and OEWS are single-reference-year snapshots, not time series — every research tool explicitly detects and reports this (
trend: nullwith an explanatory limitation) rather than fabricating a trend from one datapoint.No verified crosswalk exists between BLS Employment Projections' industry codes and BLS's monthly CES industry employment series (different classification schemes) —
analyze_industry_employmentcovers long-run outlook only; pair it withfred_search_series+analyze_labor_market_trendfor current monthly industry employment.SOC occupation codes change between Employment Projections vintages — comparing an occupation across catalog rebuilds separated by a vintage change is not reliable.
The inbound rate limiter is a best-effort fixed-window counter (a read-then-write race can under-count by a request or two under heavy concurrency) — an accepted tradeoff for a low-volume personal connector, not a precision guarantee.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Fetch US Bureau of Labor Statistics data — CPI, unemployment, wages, JOLTS, and more via MCP.
Macro data for AI agents: GDP, inflation, unemployment and more (World Bank, US BLS). No keys.
SEC EDGAR, CFPB complaints, and BLS employment data. 4 tools.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/harperbrian/labor-market-intelligence-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server