fema-nfhl-mcp-server

fema-nfhl-mcp-server

MCP server that queries FEMA's National Flood Hazard Layer (NFHL) for flood zone information, including flood zone codes, Base Flood Elevation, FIRM panel numbers, and identifies LOMRs/LOMAs from provided coordinates, enabling automated flood risk lookups.

Category
Visit Server

README

fema-nfhl-mcp-server

MCP server wrapping FEMA's public National Flood Hazard Layer (NFHL) ArcGIS REST service (https://hazards.fema.gov/arcgis/rest/services/public/NFHL/MapServer) — the same live dataset behind msc.fema.gov, which the Hutton SIR agent's standing doctrine treats as non-fetchable. This server queries the NFHL directly, no API key required for the FEMA side.

Transport: Streamable HTTP (stateless)

This server runs as a small Express HTTP server exposing POST /mcp, using the MCP Streamable HTTP transport in stateless mode — every request gets its own short-lived MCP server + transport instance, connected, used, and torn down. There is no in-memory session state kept between calls. This is deliberate: it makes the server safe to run on a host that spins the process down when idle (e.g. Render's free tier) — there's nothing to lose when the process restarts, because nothing persists between requests anyway.

An earlier version of this server used stdio transport (local-process-only, no network). That version is kept for reference in reference/index_stdio_original.ts.txt but is not part of the deployable build — src/index.ts is now the HTTP entry point, and src/createServer.ts holds the actual tool registration shared by both.

GET /health is also exposed for host health checks and uptime pingers.

Why this exists (Hutton SIR context)

The SIR agent's Field Reference and Setback Routine both carry a standing rule: msc.fema.gov/portal is non-fetchable, so flood zone/BFE/panel lookups always route to a manual coordinate search. This server replaces that manual step with a live tool call — the agent already desk-answers lat/long for every site (topography section), so it can pass those same coordinates straight through.

It does not replace the "carry coordinates with the route" discipline (Quality Rule 8) — the tool output includes the queried coordinates in every result specifically so that discipline still holds even when the lookup succeeds outright.

Tools

fema_flood_zone_lookup

The primary tool. Takes 1–8 labeled points (e.g. site centroid, or all four parcel corners + centroid) and returns, per point: flood zone code, SFHA flag, Base Flood Elevation + datum, FIRM panel number, effective date, and status. Flags a split-zone condition automatically if different points return different zones — the exact case that matters for a site straddling a flood-zone boundary.

fema_identify_layer

Lower-level identify against any NFHL layer(s) at a point — useful for checking Letters of Map Revision (layer 1) or Letters of Map Amendment (layer 34) on a parcel, which the flood-zone tool doesn't surface.

Deploying — Render (recommended, browser-only, free)

This repo includes render.yaml, so Render can configure itself from a Blueprint — you don't have to manually fill in build/start commands.

  1. Push/upload this repo to GitHub (a browser-only, no-git-CLI way to do this is via GitHub's web uploader: new repo → "Add file" → "Upload files").
  2. On render.com, sign up (GitHub login is easiest — no credit card required for the free tier).
  3. New > Blueprint, connect your GitHub account, select this repo. Render will detect render.yaml and pre-fill everything: Node web service, free plan, npm install && npm run build build command, npm start start command, /health health check path.
  4. Click Apply / Deploy. Render will generate a random MCP_API_TOKEN environment variable automatically (see render.yamlgenerateValue: true). Copy that token from the service's Environment tab in the Render dashboard once deployed — you'll need it in step 6.
  5. Your endpoint will be https://<your-service-name>.onrender.com/mcp.
  6. In claude.ai: Customize > Connectors > "+" > Add custom connector. Paste the URL from step 5. Under Advanced settings > Request headers, add:
    Authorization: Bearer <the MCP_API_TOKEN value from step 4>
    
    Click Add.

No auth needed? If you'd rather leave the endpoint fully open (it's a read-only public-data lookup, so the risk is low), delete the MCP_API_TOKEN env var in Render's dashboard after deploy — the server checks for it at request time and runs open if it's unset. See the requireAuth middleware in src/index.ts.

Free-tier cold starts: Render's free instances spin down after 15 minutes idle and take 30–60 seconds to wake on the next request. The first flood-zone lookup after a period of inactivity may be slow or need a retry. Upgrade to Render's Starter plan (~$7/mo) to keep the service always-on if this becomes annoying.

Running locally (only if you have Node.js installed)

npm install
npm run build
PORT=3000 npm start

Then POST http://localhost:3000/mcp with a standard MCP JSON-RPC body, or point the MCP Inspector at http://localhost:3000/mcp for a browser test UI:

npx @modelcontextprotocol/inspector

Then in the Inspector UI, choose "Streamable HTTP" transport and enter the URL above.

No environment variables are required to run it — MCP_API_TOKEN is optional (see above).

Verified so far

  • Server builds clean under strict TypeScript.
  • Real protocol-level test performed: started the compiled server, sent an actual HTTP initialize request and an actual tools/list request to POST /mcp, and got back correct, well-formed MCP responses (both tools present with valid JSON Schemas, matching the descriptions below) — this is a genuine test of the transport wiring, not a mock.
  • GET /health confirmed working over real HTTP.
  • Response parsing (extractFloodZones / extractFirmPanels, including the epoch-ms → ISO date conversion for EFF_DATE) is exercised against a mocked response shaped exactly like the live service's field schema (FLD_ZONE, SFHA_TF, STATIC_BFE, V_DATUM, FIRM_PAN, EFF_DATE, etc.), confirmed against FEMA's own layer metadata for layers 28 (S_Fld_Haz_Ar) and 3 (S_FIRM_Pan).
  • Error handling confirmed to degrade gracefully (clear error message, no crash) on a simulated network failure.

NOT yet verified — do this before relying on it live

The build/test environment used to build this server has no network route to hazards.fema.gov, so the actual live FEMA API call has not been executed or observed. Before trusting this in a real SIR:

  1. Run fema_flood_zone_lookup against a known site (e.g. a parcel you already have a confirmed FIRM panel/zone for from a past live run — Indian River County or Jefferson County both have flood data on file) and diff the tool's output against the confirmed manual result.
  2. Confirm the identify endpoint's exact response shape hasn't drifted from what's documented here — ArcGIS services occasionally change field aliasing or add/retire layers.
  3. Watch for SFHA_TF values other than "T"/"F" (blank has been reported in edge cases) and confirm extractFloodZones handles that gracefully (it currently reports it as null/not-SFHA, worth double-checking against a real blank-value response).
  4. Confirm rate-limit behavior under repeated calls (e.g. 5 points per SIR × multiple SIRs per day) — the public service doesn't publish a documented limit.
  5. Confirm Render's free-tier cold start doesn't exceed claude.ai's MCP request timeout on a cold first call — if it does consistently, upgrade to a paid Render plan.

Known layer IDs (from FEMA's own NFHL MapServer)

ID Layer
0 NFHL Availability
1 LOMRs
3 FIRM Panels (S_FIRM_Pan)
14 Cross-Sections
20 Water Lines
22 Political Jurisdictions
28 Flood Hazard Zones (S_Fld_Haz_Ar)
34 LOMAs

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured