Skip to main content
Glama

warn-mcp — US layoff data (WARN Act) as an MCP server

61,428 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?"

Install

Nothing to build and nothing to install into your Python environment — the server is standard library only.

Claude Desktop — one file, no terminal: download warn-mcp.mcpb and drag it onto Claude Desktop's Settings → Extensions window. That bundle is this repo's server plus a manifest; it needs a python3 on your PATH and nothing else. The same file is listed as the installable package for io.github.APProj/warn-mcp in the MCP registry.

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-mcp

No 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" }
  }
}

Related MCP server: treasury-fiscaldata-mcp

Hosted: a URL, no install (ChatGPT / Claude.ai connectors, n8n, any remote client)

If your client wants a remote MCP server rather than a subprocess, point it at:

https://mQpACuIiQcnwK93JY.apify.actor/mcp        (Streamable HTTP)

Same six tools, same daily-rebuilt data, same code as this repo. One honest caveat: the host (Apify) requires the caller's own API token, because it meters the compute to the account that calls it. Create a free Apify account, copy your token, and send it as Authorization: Bearer <your-apify-token>. We charge nothing, we see nothing, and we store nothing about your queries. If your client supports stdio, the .mcpb bundle above needs no token at all and is the better route.

claude mcp add --transport http warn https://mQpACuIiQcnwK93JY.apify.actor/mcp \
  --header "Authorization: Bearer <your-apify-token>"

This endpoint is also listed as the remotes entry for io.github.APProj/warn-mcp in the official MCP registry.

Or run it over HTTP (Streamable HTTP transport)

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/mcp

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

Tools

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

The dataset's own change log: a field-level diff of consecutive daily builds — amended fields (headcounts, dates, locations…), row_absent notices, row_returned ones — each tagged with a mechanically-determined cause_class. Records the observation, not the cause.

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.

Why an MCP server and not just the CSV

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 build against today's and keeps the field-level log — 638 logged changes since 2026-08-31, including 274 notices that stopped appearing. One honest caveat, stated in every response: a logged change can come from the agency amending or withdrawing a notice or from an improvement to this project's parser, and the log does not guess which — cause_class labels only what is mechanically distinguishable (field_populated, field_cleared, format_only, value_changed, unknown).

Caching and network

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, license, attribution

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

The one paid thing

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, or a private RSS feed you point Slack, Discord or Teams at — 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.

Available Tools

6 tools
agency_revisionsAInspect

Change log of the dataset itself: what differed between consecutive daily builds of the WARN notice table, since 2026-08-31. Each change is one of 'amended' (a tracked field of an existing notice changed — employees_affected, effective_date, location, notice_type, company, notice_date), 'row_absent' (a notice stopped appearing) or 'row_returned' (an absent notice came back). A change can come from the state agency amending or withdrawing a notice OR from an improvement to this project's parser; the log records the observation, never the cause, and cause_class labels only what is mechanically distinguishable (field_populated, field_cleared, format_only, value_changed, unknown). Filters combine with AND. Returns matched_changes, by_change_type, by_cause_class, log_covers_from/to, and up to limit changes newest observed_date first, each with id, state, company, notice_date, change_type, cause_class, field, old_value, new_value. Not a search for notices: use search_layoff_notices for notices and employer_layoff_history for one employer's full record.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax changes returned, 1-200 (default 25). matched_changes always reports the full count.
sinceNoEarliest observed_date (the build date on which the change was seen), YYYY-MM-DD. The log starts 2026-08-31; earlier dates return everything.
stateNoTwo-letter state code, e.g. 'CA'.
companyNoEmployer name, matched on WHOLE WORDS (case-insensitive), e.g. 'united airlines'. Every word you give must appear as a complete word in the filed name, so 'ford' will NOT return 'Stanford Health Care'. On 0 hits the response lists similar_company_names to retry with.
change_typeNoExactly one of 'amended', 'row_absent', 'row_returned'. Omit for all three.

TDQS

A4.8/5.0
Behavior5/5

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

With no annotations, the description carries the full behavioral burden, and it excels. It discloses that the log records observations, never causes, explains what cause_class can and cannot distinguish, states the log's start date, and specifies the exact return shape and ordering. This is far richer than the typical read-only tool description.

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 and every sentence earns its place, but it is a single ~200-word paragraph with no visual structure. It front-loads the core purpose and saves sibling routing for the end, but bullet points or short paragraphs would improve scannability without losing content.

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?

For a read-only log query with no output schema, the description covers the full return contract (matched_changes, by_change_type, by_cause_class, log_covers_from/to, per-change fields), the meaning of each change type, filter semantics, and alternative tools. Nothing an agent needs to call it correctly 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 coverage is 100%, so the baseline is 3. The description adds cross-parameter semantics not in any single schema field: 'Filters combine with AND', 'up to `limit` changes newest observed_date first', and the conceptual distinction between matched_changes count and returned items. That extra context justifies a 4.

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 opens by defining the tool as the dataset's own change log and enumerates the exact change types ('amended', 'row_absent', 'row_returned'). It closes with explicit sibling differentiation: 'use search_layoff_notices for notices and employer_layoff_history for one employer's full record.' This makes the purpose concrete and instantly distinguishable from all five sibling tools.

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 gives explicit when-not guidance and names the alternatives: 'Not a search for notices: use search_layoff_notices for notices and employer_layoff_history for one employer's full record.' It also clarifies filter combination ('Filters combine with AND'), default limit behavior, and ordering, leaving no ambiguity about when to invoke this tool.

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

dataset_statusAInspect

Freshness and coverage of the dataset itself: when it was last rebuilt, which states are flagged stale, the license, and the raw endpoints. Call this before quoting a number so you can attribute it correctly.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior3/5

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

No annotations are provided, so the description must disclose behavioral traits. It lists the content (freshness, stale states, license, raw endpoints) but does not explicitly state whether this is a read-only, non-mutating operation, nor does it mention any costs, latency, or side effects. While 'status' implies safety, the description carries only partial burden—it lacks explicit reassurance or caveats. With no annotations, a 3 is appropriate.

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?

Two concise sentences with no fluff. The first sentence front-loads the core content, naming the specific data points. The second adds a practical usage hint. Every word earns its place, and the description is appropriately sized for a simple status tool.

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?

This tool has no output schema, so the description must explain what is returned. It lists the key categories: rebuilt time, stale states, license, and raw endpoints. It also gives a usage scenario ('before quoting a number') to help the agent understand when it adds value. For a zero-parameter metadata tool, this is complete—nothing an agent needs to know to call it correctly 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?

The input schema has zero parameters, so the description is the sole source of semantic meaning. It clearly explains that the tool provides dataset-level metadata rather than taking inputs, and it lists the categories of information returned. This fully compensates for the empty schema, matching the baseline of 4 for a no-parameter tool.

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 clearly states the tool provides 'Freshness and coverage of the dataset itself' and enumerates specific aspects (last rebuilt, stale states, license, raw endpoints). This is a specific noun phrase that distinguishes it from sibling tools like search_layoff_notices or state_layoff_totals, which operate on record-level data. No ambiguity about what the tool returns.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use context: 'Call this before quoting a number so you can attribute it correctly.' This tells the agent the appropriate timing for invocation. It does not mention alternatives or exclusions, but for a metadata tool that is mainly a pre-call context check, this is sufficient. Siblings are clearly about data retrieval, so no conflict.

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

employer_layoff_historyAInspect

Every WARN notice one employer has filed, in any covered state, back to 1988: notice count, total workers affected, states, first and latest activity. Returns employers_matched, employers (up to 10 distinct canonical names, most workers affected first) and notices_for_best_match (up to limit notices of the top employer, newest notice_date first). For a date- or state-bounded question use search_layoff_notices.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax individual notices returned, 1-200 (default 25).
companyYesEmployer name, matched on WHOLE WORDS (case-insensitive), e.g. 'united airlines'. Every word you give must appear as a complete word in the filed name, so 'ford' will NOT return 'Stanford Health Care'. On 0 hits the response lists similar_company_names to retry with.

TDQS

A4.7/5.0
Behavior5/5

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

With no annotations, the description carries the full behavioral burden and does so thoroughly. It discloses return structure (employers_matched, employers, notices_for_best_match), ordering rules (most workers affected first, newest notice_date first), matching semantics (whole-word, case-insensitive), and the similar_company_names fallback on zero hits. This gives the agent actionable expectations before invoking.

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?

Three sentences pack a high density of useful information: scope, return fields, ordering, fallback behavior, and routing guidance. The most important scoping statement is front-loaded, and no sentence is wasted.

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 no output schema, the description still fully explains the response shape, ordering, and failure handling. It covers the main edge case (0 hits), the matching rule, and the key routing alternative. An agent has enough context to call this tool appropriately and interpret its results correctly.

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 description coverage is 100%, so the baseline is 3; the schema already documents company matching and limit behavior. The description adds marginal value by explaining how limit affects notices_for_best_match, but this is mostly redundant with the schema's 'Max individual notices returned' wording. No additional parameter nuance is needed.

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 clearly defines the tool as returning the complete WARN notice history for a single employer, including counts, affected workers, states, and activity dates. It distinguishes itself from siblings by explicitly scoping to employer-level history and naming search_layoff_notices as the alternative for date- or state-bounded queries.

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?

State explicitly: 'For a date- or state-bounded question use search_layoff_notices.' This tells the agent when this tool is appropriate (employer-focused, all-time histories) and when to route elsewhere. The employer-centric framing in the first sentence further reinforces the intended use case.

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

latest_layoff_noticesAInspect

The rolling feed of newly published WARN notices (the last ~14 days as the agencies posted them), newest notice_date first, optionally one state. Use this for 'what layoffs were announced recently'. Returns count_in_window plus up to limit notices in the same row shape as search_layoff_notices; for older dates or an employer filter use search_layoff_notices instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax notices returned, 1-200 (default 25).
stateNoTwo-letter state code to filter to.

TDQS

A4.2/5.0
Behavior3/5

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

No annotations are provided, so the description carries the burden. It discloses the rolling 14-day window, the newest-first ordering, the count_in_window return field, and the row shape shared with search_layoff_notices. It does not mention pagination, rate limits, or whether state is required, but the schema already marks state optional. The description adds meaningful behavioral context beyond the schema.

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?

Two sentences, front-loaded with the core behavior (rolling feed, 14-day window, ordering), then the routing instruction. Every clause earns its place; no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only list tool with two optional parameters and no output schema, the description covers the key context: time window, ordering, optional state filter, return shape, and the sibling to use for other cases. It doesn't describe the exact fields of a notice, but the row shape is referenced as identical to search_layoff_notices, which is sufficient for an agent to know what to expect.

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 description coverage is 100%, so the baseline is 3. The description adds context that limit controls the number of notices returned and state filters the feed, but it doesn't add details beyond the schema's own parameter descriptions. It does clarify that limit is capped at 200 and default 25, which is already in the schema.

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 clearly states the tool's function: a rolling feed of newly published WARN notices, sorted by notice_date descending, with optional state filtering. It explicitly distinguishes itself from search_layoff_notices by noting the date window and lack of employer filter, so an agent can select it correctly.

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 says when to use this tool ('what layoffs were announced recently') and when to use the alternative ('for older dates or an employer filter use search_layoff_notices instead'). This is a clear when/when-not routing instruction.

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

search_layoff_noticesAInspect

Search US WARN Act mass-layoff notices across 48 states, 1988 to today, by employer name, state, date range and minimum headcount (filters combine with AND; at least one is required). Returns matched_notices, matched_workers_affected and up to limit notices, newest notice_date first, each with id, state, company, location, employees_affected, notice_date, effective_date, notice_type and first_seen. Read-only, no key. For only the newest ~14 days use latest_layoff_notices; for one employer's whole record use employer_layoff_history.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax notices returned, 1-200 (default 25).
sinceNoEarliest notice_date, YYYY-MM-DD.
stateNoTwo-letter state code, e.g. 'CA'.
untilNoLatest notice_date, YYYY-MM-DD.
companyNoEmployer name, matched on WHOLE WORDS (case-insensitive), e.g. 'united airlines'. Every word you give must appear as a complete word in the filed name, so 'ford' will NOT return 'Stanford Health Care'. On 0 hits the response lists similar_company_names to retry with.
min_employeesNoOnly notices affecting at least this many workers.

TDQS

A4.9/5.0
Behavior5/5

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

With no annotations, the description carries the full transparency burden. It discloses read-only behavior, no API key needed, filter combination semantics, mandatory filter requirement, sort order (newest notice_date first), and the exact response contract including matched counts and per-notice fields.

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?

Every sentence earns its place: scope and filters, response format, safety/access traits, and sibling routing. Dense but not bloated, with the most decision-relevant information front-loaded.

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 six optional parameters and no output schema, the description fully compensates by specifying the return shape, sorting, count semantics, and read-only nature. Nothing an agent needs to invoke or interpret results correctly 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 coverage is 100%, so the schema already documents each parameter. The description adds valuable cross-parameter semantics: filters combine with AND, at least one is required, and limit caps returned notices. This goes beyond what individual parameter descriptions provide.

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?

States a specific verb (Search), precise resource (US WARN Act mass-layoff notices), scope (48 states, 1988–today), and the available filter dimensions. It also differentiates from siblings by explicitly naming latest_layoff_notices and employer_layoff_history as alternatives.

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?

Provides explicit routing guidance: 'For only the newest ~14 days use latest_layoff_notices; for one employer's whole record use employer_layoff_history.' It also states when to use this tool via filter requirements: at least one filter is required and filters combine with AND.

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

state_layoff_totalsAInspect

Monthly WARN notice counts and workers affected. With no state, returns a national leaderboard by state in series (grouped_by=state, most workers affected first); with a state, the month-by-month series for it (grouped_by=month, oldest first). Optionally restrict to one four-digit year. totals carries overall notices and workers for the selection; notices without a published headcount count 0 workers. Aggregates only — use search_layoff_notices for the notices.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearNoFour-digit year, e.g. '2026'.
stateNoTwo-letter state code.

TDQS

A4.7/5.0
Behavior4/5

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

With no annotations provided, the description carries the full burden. It discloses that the tool returns only aggregates, that notices without headcount count as 0 workers, and that ordering differs by mode. It does not explicitly state read-only or no side effects, but 'Aggregates only' implies a safe query operation. A 4 reflects this strong coverage with minor omissions (e.g., no mention of rate limits or response size).

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?

Four sentences, each earning its place. The core purpose is front-loaded, conditional behavior is neatly summarized, and the constrast with search_layoff_notices is left for last without bloat. No redundant wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description explains the return structure at a semantic level: series grouping and ordering, totals object, and counting conventions. It does not name exact output fields (e.g., 'notices', 'workers') but that is easily inferable. Slightly more detail on the exact JSON shape would make it fully complete, hence 4.

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

Parameters5/5

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

Schema coverage is 100%, but the description adds substantial meaning: it explains that year is optional, state changes the grouping behavior, and year restricts to a four-digit year. This goes well beyond the schema's terse type descriptions.

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 opens with 'Monthly WARN notice counts and workers affected' – a specific verb, resource, and data type. It then clearly differentiates two modes of operation (state vs. no state) and explicitly names a sibling tool ('use search_layoff_notices for the notices'), making it easy to distinguish from alternatives.

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 gives explicit when-to-use guidance: aggregates only, and when not to use it (for individual notices, use search_layoff_notices). It also explains the conditional behavior of the two parameters, telling the agent exactly how to get national vs. state-specific results.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.2.4
    • Changedagency_revisions6 fields changed
      • changedInput schema / properties / change_type / description
        Previous value: -"e.g. 'row_absent', 'field_changed', 'row_new'."New value: +"Exactly one of 'amended', 'row_absent', 'row_returned'. Omit for all three."
      • addedInput schema / properties / change_type / enum
        Added value: +[
        +  "amended",
        +  "row_absent",
        +  "row_returned"
        +]
      • changedInput schema / properties / company / description
        Previous value: -"Substring of the employer name."New value: +"Employer name, matched on WHOLE WORDS (case-insensitive), e.g. 'united airlines'. Every word you give must appear as a complete word in the filed name, so 'ford' will NOT return 'Stanford Health Care'. On 0 hits the response lists similar_company_names to retry with."
      • changedInput schema / properties / limit / description
        Previous value: -"Max changes returned, 1-200 (default 25)."New value: +"Max changes returned, 1-200 (default 25). matched_changes always reports the full count."
      • changedInput schema / properties / since / description
        Previous value: -"Earliest observed_date, YYYY-MM-DD."New value: +"Earliest observed_date (the build date on which the change was seen), YYYY-MM-DD. The log starts 2026-08-31; earlier dates return everything."
      • changedInput schema / properties / state / description
        Previous value: -"Two-letter state code."New value: +"Two-letter state code, e.g. 'CA'."
    • Changedemployer_layoff_history1 field changed
      • changedInput schema / properties / company / description
        Previous value: -"Employer name or a substring of it."New value: +"Employer name, matched on WHOLE WORDS (case-insensitive), e.g. 'united airlines'. Every word you give must appear as a complete word in the filed name, so 'ford' will NOT return 'Stanford Health Care'. On 0 hits the response lists similar_company_names to retry with."
    • Changedsearch_layoff_notices1 field changed
      • changedInput schema / properties / company / description
        Previous value: -"Case-insensitive substring of the employer name, e.g. 'united airlines'."New value: +"Employer name, matched on WHOLE WORDS (case-insensitive), e.g. 'united airlines'. Every word you give must appear as a complete word in the filed name, so 'ford' will NOT return 'Stanford Health Care'. On 0 hits the response lists similar_company_names to retry with."
  2. 6 tool updatesv0.1.0
    • First observedagency_revisions
    • First observeddataset_status
    • First observedemployer_layoff_history
    • First observedlatest_layoff_notices
    • First observedsearch_layoff_notices
    • First observedstate_layoff_totals

TDQS

A4.4/5.0

Scored across 6 tools

Disambiguation5/5

Each tool occupies a clearly distinct niche: general search, recent feed, employer history, state aggregates, dataset freshness, and change log. The descriptions explicitly cross-reference the other tools, so an agent can reliably pick the right one without ambiguity.

Naming Consistency4/5

All names use lowercase snake_case and follow a recognizable subject-prefix structure like search_, latest_, employer_, and state_. The only minor deviation is that search_layoff_notices is verb-led while most other names are noun phrases, but the pattern is still predictable.

Tool Count5/5

Six tools is well-scoped for a specialized WARN dataset server. Each tool earns its place by covering a distinct query mode or operational need, with no obvious redundancy or bloat.

Completeness4/5

The read-only domain is well covered: filtered search, recent notices, employer history, state totals, dataset status, and revision tracking are all present. Minor gaps exist, such as no direct lookup by notice id and no explicit pagination beyond `limit`, but agents can usually work around these with the available search and history tools.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Enables users to query U.S. labor statistics, including employment, CPI, and wages, directly from the Bureau of Labor Statistics Public Data API. It provides tools to retrieve real-time economic time series data, browse popular series, and access survey metadata through natural language.
    6
    110 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    Provides access to US Treasury Fiscal Data via a free, no-auth public API. Enables querying government financial data through natural language.
    3 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides access to SEC EDGAR data through natural language, including company filings, financial statements, and company info, without requiring an API key.
    MIT