# io.github.cyanheads/fema-mcp-server

> Query FEMA disaster declarations, public assistance grants, housing aid, and NFIP claims.

- name: io.github.cyanheads/fema-mcp-server
- version: 0.4.1
- connection class: R0 (autonomous)
- trust: 94/100
- quality: 70/100 (needs work)
- owner: not claimed
- descriptor: https://api.protogrid.dev/v1/servers/io.github.cyanheads%2Ffema-mcp-server
- tools: https://api.protogrid.dev/v1/servers/io.github.cyanheads%2Ffema-mcp-server/tools

**An agent can connect right now, no human step.** Remote endpoint, no authentication, reachable on the last probe.

## Connection (mcpServers)

```json
{
  "mcpServers": {
    "fema-mcp-server": {
      "type": "http",
      "url": "https://fema.caseyjhand.com/mcp"
    }
  }
}
```


## Trust

- hygiene: 100
- liveness: 100
- freshness: 100
- provenance: 80
- drivers: +repository +namespace-matches-repo +reachable +uptime-99% +updated-2d-ago
- Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed.

## Quality 70/100 (needs work)

### protocol: 88 (weight 25)

- pass `protocol.modern`: supports 2026-07-28 (server/discover)
- pass `protocol.stateless`: answers without a session
- pass `protocol.transport`: streamable HTTP
- warn `protocol.list_ttl`: tools/list declares ttlMs 0, so clients re-fetch it on every use

### authorization: n/a (weight 15)

- n/a `auth.prm`, `auth.as_metadata`, `auth.cimd`: no remote uses OAuth
- n/a `auth.secret_in_url`: no templated URL

### tool hygiene: 79 (weight 30)

- pass `tools.descriptions`: every tool has a description
- warn `tools.description_length`: 1 tools have descriptions over 1,024 characters, which crowds the context
- pass `tools.schemas`: every tool has an object input schema
- pass `tools.annotations`: 8 of 8 tools declare readOnlyHint or destructiveHint
- fail `tools.directory_hints`: no tool declares all four of readOnlyHint, destructiveHint, idempotentHint and openWorldHint; missing: fema_search_disasters (destructiveHint, idempotentHint); fema_dataframe_query (destructiveHint); fema_dataframe_describe (destructiveHint); …
- pass `tools.token_cost`: about 4,263 tokens to load every tool
- pass `tools.api_dump`: tools are not a one-to-one API dump

### stability: 25 (weight 15)

- warn `stability.changes`: 16 tool changes in 30 days
- fail `stability.rug_pull`: 1 tools kept their name but changed most of their description in 30 days; review before trusting them

### dependencies: n/a (weight 15)

- n/a `deps.known_vulns`, `deps.mcp_sdk_version`, `deps.resolvable`: deps.dev does not know @cyanheads/fema-mcp-server@0.4.1, @cyanheads/fema-mcp-server@0.4.1

- tools: 8, about 4,263 tokens to load them all
- tool set hash: 0cb838402ab10ab7255f4fd85402d9c5
- tools last changed: 2026-10-19T02:11:07.209Z
- badge: [![protogrid quality](https://protogrid.dev/badge/io.github.cyanheads/fema-mcp-server.svg)](https://protogrid.dev/servers/io.github.cyanheads/fema-mcp-server)
- Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed.

### Tool changes

- 2026-10-19 `fema_search_nfip` changed (outputSchema)
- 2026-10-19 `fema_get_housing_assistance` changed (outputSchema)
- 2026-10-19 `fema_get_public_assistance` changed (outputSchema)
- 2026-10-19 `fema_get_disaster` changed (description, outputSchema)
  - before: Fetch all designated-area rows for a specific FEMA disaster by disaster number (e.g., 4781). Returns every county/municipality designated under the declaration along with programs activated, incident period, and state info. Use fema_search_disasters to find disaster numbers. The returned disaster_number chains to fema_get_public_assistance and fema_get_housing_assistance.
  - after: Fetch up to 1,000 designated-area rows for a specific FEMA disaster by disaster number (e.g., 4781). Discloses partial area and program coverage when more rows exist. Returns counties/municipalities along with programs observed, incident period, and state info. Use fema_search_disasters to find disaster numbers. The returned disaster_number chains to fema_get_public_assistance and fema_get_housing_assistance.
- 2026-10-19 `fema_search_disasters` changed (outputSchema)
- 2026-10-16 `fema_query_dataset` changed (description, inputSchema, outputSchema)
  - before: Generic OData query against any dataset in the OpenFEMA dataset catalog — the escape hatch for datasets the convenience tools do not cover (e.g., NfipPolicies, IndividualAssistanceHousingRegistrantsLargeDisasters, FemaWebDeclarationAreas, PublicAssistanceApplicants). Accepts raw OData filter, select, orderby, and pagination parameters. For NfipPolicies, use propertyState (not state) for the state and reportedZipCode for the ZIP code — it has no countyCode; always include a ZIP filter to avoid timeout. The dataset name must match the exact OpenFEMA entity name (case-sensitive, e.g., NfipClaims). Names missing from the catalog return an unknown_dataset error; a listed dataset OpenFEMA does not serve through the API returns dataset_not_served.
  - after: Generic OData query against any dataset in the OpenFEMA dataset catalog — the escape hatch for datasets the convenience tools do not cover (e.g., NfipPolicies, IndividualAssistanceHousingRegistrantsLargeDisasters, FemaWebDeclarationAreas, PublicAssistanceApplicants). Accepts raw OData filter, select, orderby, and pagination parameters. For NfipPolicies, use propertyState (not state) for the state and reportedZipCode for the ZIP code — it has no countyCode; always include a ZIP filter to avoid timeout. The dataset name must match the exact OpenFEMA entity name (case-sensitive, e.g., NfipClaims). Names missing from the catalog return an unknown_dataset error; a listed dataset OpenFEMA does not serve through the API, or a retired version, returns dataset_not_served. A page holds at most 100,000 characters of records; when records remain past it, next_offset is the offset to continue from.
- 2026-10-16 `fema_dataframe_query` changed (description, inputSchema, outputSchema)
  - before: Run a read-only SQL SELECT against a DataCanvas table staged by fema_search_nfip. Enables aggregation, GROUP BY, SUM/COUNT, time-series, and filtered analysis over the full NFIP claims result without re-fetching from the API. Call fema_dataframe_describe first to get the exact table name and column names needed for valid SQL. Only SELECT statements are allowed — DDL, DML, COPY, and file-reading functions are blocked.
  - after: Run a read-only SQL SELECT against a DataCanvas table staged by fema_search_nfip. Enables aggregation, GROUP BY, SUM/COUNT, time-series, and filtered analysis over the full NFIP claims result without re-fetching from the API. Call fema_dataframe_describe first to get the exact table name and column names needed for valid SQL. Only SELECT statements are allowed — DDL, DML, COPY, and file-reading functions are blocked. A response holds at most 100,000 characters of rows; when it holds fewer rows than the query returned, truncated and shown are set and the notice says how to page with OFFSET.
- 2026-10-16 `fema_search_nfip` changed (description, inputSchema, outputSchema)
  - before: Search National Flood Insurance Program (NFIP) claims data by state, county, ZIP code, and year range. Returns the matching claim count and claim records — amounts paid on building and contents, damage estimates, flood zones, cause and occupancy codes, and loss dates — newest loss first. state is required — the full NFIP dataset is 2.7 million rows; unfiltered access is prohibited. Page the inline claims with limit and offset; a page holds at most 100,000 characters of claims. When DataCanvas is enabled (CANVAS_PROVIDER_TYPE=duckdb) and the match exceeds that inline budget, a call at offset 0 stages the match (up to 50,000 claims) on a canvas: inspect the staged table with fema_dataframe_describe, then aggregate it with SQL via fema_dataframe_query.
  - after: Search National Flood Insurance Program (NFIP) claims data by state, county, ZIP code, and year range. Returns the matching claim count and claim records — amounts paid on building and contents, damage estimates, flood zones, cause and occupancy codes, and loss dates — newest loss first. state is required — the full NFIP dataset is 2.7 million rows; unfiltered access is prohibited. Page the inline claims with limit and offset; a page holds at most 100,000 characters of claims, and while claims remain past it, next_offset is the offset to continue from. When DataCanvas is enabled (CANVAS_PROVIDER_TYPE=duckdb) and the match exceeds that inline budget, a call at offset 0 stages the match (up to 50,000 claims) on a canvas: inspect the staged table with fema_dataframe_describe, then aggregate it with SQL via fema_dataframe_query.
- 2026-10-16 `fema_get_housing_assistance` changed (description, inputSchema, outputSchema) **meaning changed**
  - before: Retrieve Individual Assistance (IA) housing data for a disaster by disaster number. Returns owner and/or renter breakdowns by county and ZIP code — valid registrations, total approved IHP amounts, repair/rental amounts, and inspection data. Use type to select owners, renters, or both (default). Use disaster_number from fema_search_disasters.
  - after: Retrieve Individual Assistance (IA) housing data for a disaster by disaster number. Returns owner and/or renter records aggregated by county, city, and ZIP code — valid registrations, total approved IHP amounts, repair/rental/other-needs amounts, and inspection counts (owners also carry inspected damage in USD). Narrow with state, county, or zip_code; owners_count, renters_count, and offset then count the filtered records. Use type to select owners, renters, or both (default). A page holds at most 100,000 characters of records, owners and renters cut at the same row count so one offset continues both; when records remain past it, next_offset is the offset to continue from. Use disaster_number from fema_search_disasters.
- 2026-10-16 `fema_get_public_assistance` changed (description, inputSchema, outputSchema)
  - before: Retrieve Public Assistance (PA) funded project records for a disaster or state — shows where federal recovery money was obligated. Returns applicant, damage category, project size and status, federal share obligated, and total obligated amounts. Either disaster_number or state must be provided. Use disaster_number (from fema_search_disasters) to scope to a single declaration, or state to browse all PA projects for a state. PA projects are created only when the PA program is declared (pa_declared: true on the disaster).
  - after: Retrieve Public Assistance (PA) funded project records for a disaster or state — shows where federal recovery money was obligated. Returns applicant, damage category, project size and status, federal share obligated, and total obligated amounts. Either disaster_number or state must be provided. Use disaster_number (from fema_search_disasters) to scope to a single declaration, or state to browse all PA projects for a state. PA projects are created only when the PA program is declared (pa_declared: true on the disaster). A page holds at most 100,000 characters of projects; when projects remain past it, next_offset is the offset to continue from.

Full history: https://api.protogrid.dev/v1/servers/io.github.cyanheads%2Ffema-mcp-server/changes

## Dependencies

- npm @cyanheads/fema-mcp-server@0.4.1: unknown
- npm @cyanheads/fema-mcp-server@0.4.1: unknown

Dependency graphs from deps.dev; advisories from OSV.dev, including the GitHub Advisory Database and the PyPI Advisory Database; all CC BY 4.0.

## Remotes

- https://fema.caseyjhand.com/mcp (streamable-http, auth none, reachable true, uptime30d 0.99159664)

## Packages

- npm @cyanheads/fema-mcp-server@0.4.1
- npm @cyanheads/fema-mcp-server@0.4.1

## Tools (8)

- `fema_dataframe_describe`: List tables and column schemas on a DataCanvas staged by fema_search_nfip. Call this before fema_dataframe_query to discover the exact table name, column names, and DuckDB data types needed to write valid SQL. Row count reflects what was actually staged — check truncated in the fema_search_nfip response to know whether the canvas holds the full matching set.
- `fema_dataframe_query`: Run a read-only SQL SELECT against a DataCanvas table staged by fema_search_nfip. Enables aggregation, GROUP BY, SUM/COUNT, time-series, and filtered analysis over the full NFIP claims result without re-fetching from the API. Call fema_dataframe_describe first to get the exact table name and column names needed for valid SQL. Only SELECT statements are allowed — DDL, DML, COPY, and file-reading functions are blocked. A response holds at most 100,000 characters of rows; when it holds fewer rows than the query returned, truncated and shown are set and the notice says how to page with OFFSET.
- `fema_get_disaster`: Fetch up to 1,000 designated-area rows for a specific FEMA disaster by disaster number (e.g., 4781). Discloses partial area and program coverage when more rows exist. Returns counties/municipalities along with programs observed, incident period, and state info. Use fema_search_disasters to find disaster numbers. The returned disaster_number chains to fema_get_public_assistance and fema_get_housing_assistance.
- `fema_get_housing_assistance`: Retrieve Individual Assistance (IA) housing data for a disaster by disaster number. Returns owner and/or renter records aggregated by county, city, and ZIP code — valid registrations, total approved IHP amounts, repair/rental/other-needs amounts, and inspection counts (owners also carry inspected damage in USD). Narrow with state, county, or zip_code; owners_count, renters_count, and offset then count the filtered records. Use type to select owners, renters, or both (default). A page holds at most 100,000 characters of records, owners and renters cut at the same row count so one offset continues both; when records remain past it, next_offset is the offset to continue from. Use disaster_number from fema_search_disasters.
- `fema_get_public_assistance`: Retrieve Public Assistance (PA) funded project records for a disaster or state — shows where federal recovery money was obligated. Returns applicant, damage category, project size and status, federal share obligated, and total obligated amounts. Either disaster_number or state must be provided. Use disaster_number (from fema_search_disasters) to scope to a single declaration, or state to browse all PA projects for a state. PA projects are created only when the PA program is declared (pa_declared: true on the disaster). A page holds at most 100,000 characters of projects; when projects remain past it, next_offset is the offset to continue from.
- `fema_query_dataset`: Generic OData query against any dataset in the OpenFEMA dataset catalog — the escape hatch for datasets the convenience tools do not cover (e.g., NfipPolicies, IndividualAssistanceHousingRegistrantsLargeDisasters, FemaWebDeclarationAreas, PublicAssistanceApplicants). Accepts raw OData filter, select, orderby, and pagination parameters. For NfipPolicies, use propertyState (not state) for the state and reportedZipCode for the ZIP code — it has no countyCode; always include a ZIP filter to avoid timeout. The dataset name must match the exact OpenFEMA entity name (case-sensitive, e.g., NfipClaims). Names missing from the catalog return an unknown_dataset error; a listed dataset OpenFEMA does not serve through the API, or a retired version, returns dataset_not_served. A page holds at most 100,000 characters of records; when records remain past it, next_offset is the offset to continue from.
- `fema_search_disasters`: Search federal disaster declarations by state, incident type, declaration type, date range, and county. Returns deduplicated declaration-level summaries — each disaster number appears once with a designated_area_count showing how many counties/municipalities were designated. The disaster number is the chain key for fema_get_disaster, fema_get_public_assistance, and fema_get_housing_assistance. Use declaration_type to filter: DR (major disaster, most common), EM (emergency), FM (fire management). Date filters apply to the declaration date. Use fema_get_disaster to retrieve all designated-area rows for a specific declaration. county selects the declarations that designated a matching area; their area counts and program flags still describe the whole declaration, and matched_areas lists the matching areas with their own program flags. A search reads the most recent 10,000 designated-area rows; when more match, it returns the declarations dated after the day that window ends, sets truncated, and its notice names the date_to that continues with older declarations. A page holds at most 100,000 characters of declarations; when declarations remain past it, next_offset is the offset to continue from.
- `fema_search_nfip`: Search National Flood Insurance Program (NFIP) claims data by state, county, ZIP code, and year range. Returns the matching claim count and claim records — amounts paid on building and contents, damage estimates, flood zones, cause and occupancy codes, and loss dates — newest loss first. state is required — the full NFIP dataset is 2.7 million rows; unfiltered access is prohibited. Page the inline claims with limit and offset; a page holds at most 100,000 characters of claims, and while claims remain past it, next_offset is the offset to continue from. When DataCanvas is enabled (CANVAS_PROVIDER_TYPE=duckdb) and the match exceeds that inline budget, a call at offset 0 stages the match (up to 50,000 claims) on a canvas: inspect the staged table with fema_dataframe_describe, then aggregate it with SQL via fema_dataframe_query.
