61,320 mass-layoff notices · 48 states · 1988 → today · rebuilt every morning · no API key · zero dependencies.
Every US state publishes the layoff notices employers must file under the WARN Act, and every state publishes them differently — a web page here, a pile of PDFs there, a search form somewhere else. WARN Feed scrapes all 48 of them daily and normalizes them into one schema. This is that dataset wired into the Model Context Protocol, so Claude, Cursor, Continue or your own agent can ask questions like:
"Has Starbucks filed any WARN notices this year, and in which states?" "What layoffs were announced in the last two weeks in Texas?" "Which state had the most workers affected in 2026?" "Did any agency quietly change or delete a notice this week?"
Nothing to build and nothing to install into your Python environment — the server is standard library only.
Claude Desktop / Claude Code / anything that reads an mcpServers block:
{
"mcpServers": {
"warn": {
"command": "uvx",
"args": ["--from", "git+https://github.com/APVentureEngine/warn-mcp", "warn-mcp"]
}
}
}Claude Code, one line:
claude mcp add warn -- uvx --from git+https://github.com/APVentureEngine/warn-mcp warn-mcpNo uv? Clone and run it with plain Python:
git clone https://github.com/APVentureEngine/warn-mcp && cd warn-mcp
python3 -m warn_mcp.server --selftest # exercises every tool against live data{
"mcpServers": {
"warn": { "command": "python3", "args": ["-m", "warn_mcp.server"], "cwd": "/path/to/warn-mcp" }
}
}The same six tools, same implementation, spoken over MCP's Streamable HTTP transport instead of stdio — for clients that want a URL rather than a subprocess, and for putting one shared instance behind your own team:
docker build -t warn-mcp . && docker run -p 8080:8080 warn-mcp
# -> http://localhost:8080/mcp (and a short human page at http://localhost:8080/)
claude mcp add --transport http warn http://localhost:8080/mcpNo Docker? python3 http/app.py does the same thing — it is standard library
only, like everything else here. PORT selects the port, /healthz returns
{"ok":true}, and the server is stateless, so you can run as many replicas as
you like behind any load balancer.
It is deliberately keyless: the data underneath is public and read-only, the server keeps no session state and stores nothing about callers. Do not bolt auth onto a public deployment of it and then advertise it as this server.
| Tool | What it answers |
|---|---|
search_layoff_notices |
Employer / state / date-range / minimum-headcount search across the whole archive. Returns matched notice count, total workers affected, and the newest matches. |
latest_layoff_notices |
The rolling ~14-day feed of newly published notices, newest first, optionally one state. |
employer_layoff_history |
One employer's whole WARN record back to 1988 — notices, workers affected, every state it filed in, first and latest activity. |
state_layoff_totals |
Monthly notice counts and workers affected: a national leaderboard by state, or one state's month-by-month series. |
agency_revisions |
What the agencies changed: a field-level diff of consecutive daily snapshots — corrected headcounts, moved dates, and notices the agency stopped publishing. |
dataset_status |
Last rebuild time, states flagged stale, license, and the raw endpoints — call it before quoting a number. |
Every answer carries as_of and source, because a layoff figure with no date
and no attribution is not worth repeating. Where the data is weaker than it
looks, the tool says so in a caveat field rather than letting the model round
it off: headcount is only counted where the agency published one, employer names
are normalized by an auditable rule table rather than a corporate-registry join,
and row_absent in the revision log means the agency stopped publishing a
notice — not that the layoff was cancelled.
The CSV is right there and it is free — take it. This exists for the case where a model needs one specific answer out of a 9 MB file: the tools do the filtering and the arithmetic locally, so an agent spends a few hundred tokens instead of a context window, and it gets the freshness stamp with the answer.
agency_revisions is the part you cannot reconstruct from any single copy of
the data. A state agency editing its own WARN page leaves no changelog, so a
mirror taken today simply is today's truth. WARN Feed diffs yesterday's
snapshot against today's and keeps the field-level log — 616 logged agency
changes so far, including notices that vanished from the official page
entirely.
Tools read the free public WARN Feed endpoints over HTTPS and cache them on disk
(~/.cache/warn-mcp, override with WARN_MCP_CACHE) with ETag revalidation, so
ten tool calls in a row make at most one request per file per hour
(WARN_MCP_TTL, seconds). If the network is down and a cached copy exists, the
cached copy is served and its own as_of tells you how old it is.
There is no key, no signup, no rate limit and no telemetry — this server sends nothing anywhere except plain GETs for public files.
Data is compiled from official state WARN publications and released under
CC BY 4.0 — credit "WARN Feed" and link back. This server's code is MIT.
Not affiliated with any state agency or the US Department of Labor; state
agencies' own postings are the authority and are occasionally revised (see
agency_revisions).
- Dataset repo: https://github.com/APVentureEngine/warn-act-notices
- Raw HTTP API and per-state files: https://approjects-warn-act-notices.static.hf.space/api.html
- Hugging Face: https://huggingface.co/datasets/APProjects/us-warn-act-layoffs-notices-daily
Everything above is free and stays free. If you need to be told — your own list of employers matched against every daily refresh and pushed to a private alert page, a calendar feed, RSS, or a Slack / Discord / Teams webhook — that is WARN Watch, $49/year, with a free 30-day trial and no card. It is the only thing here that costs money.
Bugs, a state we should cover, a tool you want: open an issue.