epa-mcp-server

v0.3.3 pre-1.0

Search and retrieve EPA environmental data: facility compliance (ECHO), toxic releases (TRI), Superfund sites, drinking water systems, environmental-justice screening (EJScreen), and real-time air quality (AirNow). STDIO or Streamable HTTP.

epa.caseyjhand.com/mcp
claude mcp add --transport http epa-mcp-server https://epa.caseyjhand.com/mcp
codex mcp add epa-mcp-server --url https://epa.caseyjhand.com/mcp
{
  "mcpServers": {
    "epa-mcp-server": {
      "url": "https://epa.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http epa-mcp-server https://epa.caseyjhand.com/mcp
{
  "mcpServers": {
    "epa-mcp-server": {
      "command": "bunx",
      "args": [
        "mcp-remote",
        "https://epa.caseyjhand.com/mcp"
      ]
    }
  }
}
{
  "mcpServers": {
    "epa-mcp-server": {
      "type": "http",
      "url": "https://epa.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://epa.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

8

epa_search_facilities

open-world

Search EPA-regulated facilities by location, industry program, or compliance status across all environmental programs (CAA, CWA, RCRA, TRI, SDWA). Returns facility name, EPA Registry ID, coordinates, county FIPS code, per-program registration flags, inspection counts, penalty totals, and TRI release totals. Registry IDs returned here feed epa_get_facility and epa_get_tri_releases. Supports proximity search via latitude + longitude + radius_miles. At least one geographic filter (zip_code, state, city, or a complete latitude+longitude+radius_miles triple) is required — unscoped searches time out.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "epa_search_facilities",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "zip_code": {
      "description": "5-digit ZIP code to search within",
      "type": "string"
    },
    "state": {
      "description": "2-letter US state abbreviation (e.g. \"WA\", \"CA\")",
      "type": "string"
    },
    "city": {
      "description": "City name. Pair with state for best results.",
      "type": "string"
    },
    "latitude": {
      "description": "Latitude in decimal degrees. Pair with longitude and radius_miles for proximity search.",
      "type": "number",
      "minimum": -90,
      "maximum": 90
    },
    "longitude": {
      "description": "Longitude in decimal degrees. Pair with latitude and radius_miles for proximity search.",
      "type": "number",
      "minimum": -180,
      "maximum": 180
    },
    "radius_miles": {
      "description": "Search radius in miles around the given latitude/longitude (max 100). Requires latitude and longitude.",
      "type": "number",
      "exclusiveMinimum": 0,
      "maximum": 100
    },
    "active_only": {
      "description": "When true, return only active facilities",
      "type": "boolean"
    },
    "programs": {
      "description": "Restrict results to facilities registered in these environmental programs. CAA=air, CWA=water, RCRA=waste, TRI=toxic releases, SDWA=drinking water.",
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "CAA",
          "CWA",
          "RCRA",
          "TRI",
          "SDWA"
        ]
      }
    },
    "has_violation": {
      "description": "When true, return only facilities with recent significant violations",
      "type": "boolean"
    },
    "limit": {
      "default": 50,
      "description": "Maximum number of facilities to return (1–100)",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "required": [
    "limit"
  ],
  "additionalProperties": false
}
view source ↗

epa_get_facility

open-world

Retrieve a full compliance profile for a single EPA-regulated facility by EPA Registry ID. Returns facility metadata, per-program compliance status, inspection history, formal enforcement actions, penalty totals, and TRI release summary. Use epa_search_facilities to discover Registry IDs. For area-level enforcement discovery use epa_search_violations instead.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "epa_get_facility",
    "arguments": {
      "registry_id": "<registry_id>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "registry_id": {
      "type": "string",
      "minLength": 1,
      "description": "EPA FRS Registry ID for the facility (obtained from epa_search_facilities)"
    }
  },
  "required": [
    "registry_id"
  ],
  "additionalProperties": false
}
view source ↗

epa_search_violations

open-world

Search EPA civil and criminal enforcement cases by state, regulatory program, or date range. Returns case identifier, regulated facility name and Registry ID, programs involved, penalty assessed, settlement date, and case type. Designed for area-level violation discovery — for a single known facility's enforcement history use epa_get_facility instead. At least one of state or zip_code is required.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "epa_search_violations",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "state": {
      "description": "2-letter US state abbreviation to filter cases (e.g. \"TX\", \"CA\")",
      "type": "string"
    },
    "zip_code": {
      "description": "5-digit ZIP code to filter cases near that area",
      "type": "string"
    },
    "program": {
      "description": "Filter by regulatory program: CAA=Clean Air Act, CWA=Clean Water Act, RCRA=hazardous waste, SDWA=drinking water, CERCLA=Superfund, FIFRA=pesticides, TSCA=toxic substances",
      "type": "string",
      "enum": [
        "CAA",
        "CWA",
        "RCRA",
        "SDWA",
        "CERCLA",
        "FIFRA",
        "TSCA"
      ]
    },
    "case_type": {
      "default": "all",
      "description": "Filter by case type: civil (regulatory violations), criminal (willful violations), or all",
      "type": "string",
      "enum": [
        "civil",
        "criminal",
        "all"
      ]
    },
    "date_filed_start": {
      "description": "Start date for case filing date range (ISO 8601: YYYY-MM-DD)",
      "type": "string"
    },
    "date_filed_end": {
      "description": "End date for case filing date range (ISO 8601: YYYY-MM-DD)",
      "type": "string"
    },
    "limit": {
      "default": 50,
      "description": "Maximum number of cases to return (1–100)",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "required": [
    "case_type",
    "limit"
  ],
  "additionalProperties": false
}
view source ↗

epa_get_tri_releases

open-world

Query Toxic Release Inventory annual chemical release data for a specific facility. Returns per-chemical release records with chemical name, total release quantity, and reporting year. TRI data lags ~18 months — the most recent available year is typically 2 years prior to the current calendar year. Obtain facility_id (TRI facility ID) from epa_search_facilities. Use epa_search_tri_releases to identify top emitters across a region.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "epa_get_tri_releases",
    "arguments": {
      "facility_id": "<facility_id>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "facility_id": {
      "type": "string",
      "minLength": 1,
      "description": "TRI facility ID (from the RegistryID field returned by epa_search_facilities)"
    },
    "year": {
      "description": "Reporting year to retrieve. Defaults to all available years. TRI data is typically available through ~2 years prior to the current year.",
      "type": "integer",
      "minimum": 1987,
      "maximum": 2030
    },
    "chemical_name": {
      "description": "Optional filter to restrict results to a specific chemical (partial match, case-insensitive)",
      "type": "string"
    }
  },
  "required": [
    "facility_id"
  ],
  "additionalProperties": false
}
view source ↗

epa_search_tri_releases

open-world

Search Toxic Release Inventory data across facilities in a state or county for a given reporting year. Returns facility name, TRI ID, chemical name, and release quantity. Use to identify top polluters in an area or build an environmental exposure profile. Use epa_get_tri_releases for detailed release records for a single facility. TRI data lags ~18 months from the current calendar year.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "epa_search_tri_releases",
    "arguments": {
      "state": "<state>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "state": {
      "type": "string",
      "minLength": 2,
      "maxLength": 2,
      "description": "2-letter US state abbreviation (required, e.g. \"WA\", \"TX\")"
    },
    "county": {
      "description": "County name to narrow results within the state (partial match)",
      "type": "string"
    },
    "year": {
      "description": "Reporting year. Defaults to all available years in the state. TRI data lags ~18 months.",
      "type": "integer",
      "minimum": 1987,
      "maximum": 2030
    },
    "chemical_name": {
      "description": "Optional filter to restrict results to a specific chemical (partial match, case-insensitive)",
      "type": "string"
    },
    "limit": {
      "default": 50,
      "description": "Maximum number of release records to return (1–200)",
      "type": "integer",
      "minimum": 1,
      "maximum": 200
    }
  },
  "required": [
    "state",
    "limit"
  ],
  "additionalProperties": false
}
view source ↗

epa_search_superfund

open-world

Search Superfund (CERCLA/SEMS) sites by location or NPL listing status. Returns site name, EPA site ID, NPL status (listed/not listed/proposed), cleanup status, coordinates, and county FIPS code. Accepts either state/city/ZIP or latitude+longitude+radius for proximity searches. Use for "are there Superfund sites near X" questions.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "epa_search_superfund",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "state": {
      "description": "2-letter US state abbreviation to filter sites",
      "type": "string"
    },
    "city": {
      "description": "City name (partial match within state)",
      "type": "string"
    },
    "zip_code": {
      "description": "5-digit ZIP code to filter sites",
      "type": "string"
    },
    "latitude": {
      "description": "Latitude for proximity search (use with longitude and radius_miles)",
      "type": "number"
    },
    "longitude": {
      "description": "Longitude for proximity search (use with latitude and radius_miles)",
      "type": "number"
    },
    "radius_miles": {
      "description": "Search radius in miles from the given coordinates. Required when using latitude+longitude.",
      "type": "number",
      "minimum": 0.1,
      "maximum": 500
    },
    "npl_status": {
      "default": "all",
      "description": "Filter by NPL (National Priorities List) status: listed=final NPL, not-listed=not on NPL, proposed=proposed for listing, all=include all",
      "type": "string",
      "enum": [
        "listed",
        "not-listed",
        "proposed",
        "all"
      ]
    },
    "limit": {
      "default": 50,
      "description": "Maximum number of sites to return (1–200)",
      "type": "integer",
      "minimum": 1,
      "maximum": 200
    }
  },
  "required": [
    "npl_status",
    "limit"
  ],
  "additionalProperties": false
}
view source ↗

epa_search_water_systems

open-world

Search drinking water systems (SDWIS) by state or ZIP code. Returns system name, PWSID, population served, primary water source, and active violation status. Use to identify community water systems with current or recent compliance violations. At least one of state or zip_code is required.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "epa_search_water_systems",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "state": {
      "description": "2-letter US state abbreviation (e.g. \"WA\", \"CA\")",
      "type": "string"
    },
    "zip_code": {
      "description": "5-digit ZIP code to search within",
      "type": "string"
    },
    "has_violation": {
      "description": "When true, return only systems with active violations",
      "type": "boolean"
    },
    "pws_type": {
      "description": "Filter by public water system type: community=permanent residences, non-transient=regular non-residents (schools, businesses), transient=occasional users (campgrounds)",
      "type": "string",
      "enum": [
        "community",
        "non-transient",
        "transient"
      ]
    },
    "limit": {
      "default": 50,
      "description": "Maximum number of systems to return (1–200)",
      "type": "integer",
      "minimum": 1,
      "maximum": 200
    }
  },
  "required": [
    "limit"
  ],
  "additionalProperties": false
}
view source ↗

epa_get_ejscreen

open-world

Get EJScreen environmental-justice indicators for a point and surrounding buffer. Returns the 13 EJScreen environmental indicators (PM2.5, ozone, diesel particulate, NO2, lead paint, traffic proximity, Superfund/RMP/hazardous-waste/wastewater proximity, underground storage tanks, drinking-water non-compliance, and RSEI toxic air releases) and 6 demographic indicators (people of color, low income, limited English, less than high school, under 5, over 64), each with national and state percentiles plus EJ Index values, along with the Demographic Index and Supplemental Demographic Index. Data is EJScreen v2.2 (2022) served via the community-maintained EJAM API (api.ejanalysis.com, Public Environmental Data Partners), which rehosts EJScreen after EPA discontinued public access in 2025 — not a live EPA endpoint. Provide latitude, longitude, and a buffer distance (default 1 mile, max 15 miles). Points outside US coverage return a coverage note instead of indicators.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "epa_get_ejscreen",
    "arguments": {
      "latitude": "<latitude>",
      "longitude": "<longitude>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "latitude": {
      "type": "number",
      "minimum": -90,
      "maximum": 90,
      "description": "Latitude in decimal degrees."
    },
    "longitude": {
      "type": "number",
      "minimum": -180,
      "maximum": 180,
      "description": "Longitude in decimal degrees."
    },
    "distance": {
      "default": 1,
      "description": "Buffer radius around the point, in the given unit (default 1). The miles-equivalent must be 15 or less.",
      "type": "number",
      "exclusiveMinimum": 0
    },
    "unit": {
      "default": "miles",
      "description": "Unit for distance. Kilometers are converted to miles (× 0.621371) before the request.",
      "type": "string",
      "enum": [
        "miles",
        "kilometers"
      ]
    }
  },
  "required": [
    "latitude",
    "longitude",
    "distance",
    "unit"
  ],
  "additionalProperties": false
}
view source ↗

Resources

2

Full compliance profile for an EPA-regulated facility by EPA FRS Registry ID. Returns the same data as epa_get_facility.

uri epa://facility/{registry_id} mime application/json

Superfund site record from EPA SEMS by site ID. Returns NPL status, cleanup status, location, and coordinates.

uri epa://superfund/{site_id} mime application/json