Wraps five EPA public data APIs into a single MCP interface: ECHO for facility compliance and enforcement actions, TRI for toxic chemical releases, AirNow for real-time air quality readings, CERCLA for Superfund site status, and SDWIS for drinking water violations. You get eight tools that let you search facilities by location or program, pull full compliance profiles with inspection history and penalties, query TRI releases by chemical and medium, check current AQI by ZIP or coordinates, and find Superfund sites or water systems with active violations. The facility search returns Registry IDs and county FIPS codes, which makes it easy to chain lookups or join with Census data. Useful for environmental compliance checks, public health analysis, or building location intelligence into regulatory workflows.
Access EPA environmental data — facility compliance (ECHO), toxic releases (TRI), Superfund sites, drinking water systems, and real-time air quality (AirNow) via MCP. STDIO or Streamable HTTP.
8 tools spanning EPA facility compliance, toxic chemical releases, Superfund cleanup sites, drinking water safety, and real-time air quality:
| Tool | Description |
|---|---|
epa_search_facilities | Search EPA-regulated facilities by location (ZIP, state, city, or latitude/longitude + radius proximity), industry, or compliance status across all environmental programs (CAA, CWA, RCRA, TRI, SDWA). Returns facility name, EPA Registry ID, coordinates, county FIPS, per-program compliance flags, inspection counts, penalty totals, and TRI release totals. |
epa_get_facility | Retrieve a full compliance profile for a single EPA-regulated facility: compliance status per program, inspection dates, formal enforcement actions, penalty amounts, and TRI annual release totals. Aggregates multiple ECHO DFR endpoints in parallel. |
epa_search_violations | Search EPA civil and criminal enforcement cases by state, regulatory program, or date range. Returns case identifier, facility name and Registry ID, programs involved, penalty assessed, settlement date, and case type. |
epa_get_air_quality | Get AQI observations or forecasts for a location. Returns per-pollutant AQI values (PM2.5, ozone, CO, SO2, NO2), AQI category (Good through Hazardous), reporting area name, and observation timestamp. |
epa_get_tri_releases | Query Toxic Release Inventory annual chemical release data for a specific facility by medium (air, water, land, underground injection) and reporting year. |
epa_search_tri_releases | Search Toxic Release Inventory data across facilities in a state or county for a given year. Returns facility name, TRI ID, chemical name, total releases by medium, and facility coordinates. |
epa_search_superfund | Search Superfund (CERCLA/SEMS) sites by location or NPL listing status. Accepts state/city/ZIP or lat/lng + radius for proximity searches. Returns site name, EPA ID, NPL status, cleanup status, and coordinates. |
epa_search_water_systems | Search drinking water systems (SDWIS) by state or ZIP code. Returns system name, PWSID, population served, primary water source, and active violation status. |
epa_search_facilitiesSearch for EPA-regulated facilities with cross-program compliance data.
has_violation flag to surface only non-compliant facilitiesRegistryID (key for epa_get_facility), FacFIPSCode (county FIPS for Census chaining), and coordinatesepa_get_facilityRetrieve a comprehensive compliance profile by EPA Registry ID.
Promise.allSettled — partial data returned even if one upstream endpoint failsepa_search_violationsSearch area-level EPA enforcement cases — distinct from per-facility history in epa_get_facility.
epa_get_facility lookupepa_get_air_qualityGet current AQI observations or daily forecasts from AirNow.
mode: current returns the latest observed AQI per pollutant; mode: forecast returns daily AQI forecasts (requires forecast_date)epa_get_tri_releasesQuery per-chemical release breakdown for a single TRI facility.
epa_search_facilities resultsepa_search_tri_releasesIdentify top polluters in a region via TRI data.
epa_get_tri_releases — use this for area discovery, then drill into a specific facilityepa_search_superfundSearch Superfund (CERCLA/SEMS) sites by location or proximity.
epa_search_water_systemsIdentify drinking water systems with active or recent violations.
has_violation flag surfaces only systems with current violationsCWS), non-transient non-community (NTNCWS), or transient non-community (TNCWS)| Type | Name | Description |
|---|---|---|
| Resource | epa://facility/{registry_id} | Full compliance profile for a facility by EPA Registry ID (same data as epa_get_facility) |
| Resource | epa://superfund/{site_id} | Superfund site record by SEMS site ID |
All resource data is also reachable via tools. Use epa_get_facility and epa_search_superfund for programmatic access in tool-only MCP clients.
Built on @cyanheads/mcp-ts-core:
none, jwt, oauthin-memory, filesystem, Supabase, Cloudflare KV/R2/D1EPA-specific:
epa_ tool surface: ECHO (facility compliance), Envirofacts DMAP (TRI, Superfund, SDWIS), and AirNow (real-time air quality)epa_get_facility — 3–5 upstream calls resolved concurrently with Promise.allSettledtri.tri_facility DDMMSS integers converted to decimal degreesAgent-friendly output:
RegistryID and FacFIPSCode from facility search feed directly into compliance, TRI, and Census API workflowsepa_get_facility returns available program data even when one DFR endpoint is unavailable, with per-section statusAdd the following to your MCP client configuration file. An AirNow API key is optional — set AIRNOW_API_KEY to enable epa_get_air_quality (register free at docs.airnowapi.org); without it the server starts with the other 7 tools. ECHO and DMAP tools work without authentication.
{
"mcpServers": {
"epa-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/epa-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"AIRNOW_API_KEY": "your-airnow-key"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"epa-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/epa-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"AIRNOW_API_KEY": "your-airnow-key"
}
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 AIRNOW_API_KEY=... bun run start:http
# Server listens at http://localhost:3010/mcp
epa_get_air_quality — register free at docs.airnowapi.org/account/request. Without it the server runs the other 7 tools. ECHO and DMAP tools require no API key.git clone https://github.com/cyanheads/epa-mcp-server.git
cd epa-mcp-server
bun install
cp .env.example .env
# optionally set AIRNOW_API_KEY to enable the air quality tool
All configuration is validated at startup via Zod schemas in src/config/. Key environment variables:
| Variable | Description | Default |
|---|---|---|
AIRNOW_API_KEY | Optional. Enables epa_get_air_quality when set; the server runs the other 7 tools without it. Free registration at docs.airnowapi.org. | — |
EPA_ECHO_BASE_URL | ECHO API base URL | https://echodata.epa.gov/echo |
EPA_DMAP_BASE_URL | Envirofacts DMAP API base URL | https://data.epa.gov/dmapservice |
EPA_AIRNOW_BASE_URL | AirNow API base URL | https://www.airnowapi.org/aq |
MCP_TRANSPORT_TYPE | Transport: stdio or http | stdio |
MCP_HTTP_PORT | HTTP server port | 3010 |
MCP_HTTP_ENDPOINT_PATH | HTTP endpoint path | /mcp |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth | none |
MCP_LOG_LEVEL | Log level (RFC 5424) | info |
LOGS_DIR | Directory for log files (Node.js only) | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1 | in-memory |
OTEL_ENABLED | Enable OpenTelemetry tracing and metrics | false |
See .env.example for the full list of optional overrides.
Build and run:
# One-time build
bun run rebuild
# Run the built server
bun run start:stdio
# or
bun run start:http
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against spec
docker build -t epa-mcp-server .
docker run --rm -e AIRNOW_API_KEY=your-key -p 3010:3010 epa-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/epa-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools/resources and inits services. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). Eight tools across ECHO, DMAP, and AirNow. |
src/mcp-server/resources | Resource definitions (*.resource.ts). Facility and Superfund URI handlers. |
src/services/echo | ECHO REST API service layer — facility search, facility detail, enforcement cases. |
src/services/dmap | Envirofacts DMAP service layer — TRI releases, Superfund sites, drinking water systems. |
src/services/airnow | AirNow service layer — current and forecast AQI observations. |
tests/ | Unit and integration tests mirroring src/. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagesrc/mcp-server/*/definitions/index.tsIssues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
AIRNOW_API_KEY*AirNow API key for real-time and forecast air quality data. Free registration at docs.airnowapi.org.
MCP_LOG_LEVELdefault: infoSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
MCP_HTTP_HOSTdefault: 127.0.0.1The hostname for the HTTP server.
MCP_HTTP_PORTdefault: 3010The port to run the HTTP server on.
MCP_HTTP_ENDPOINT_PATHdefault: /mcpThe endpoint path for the MCP server.
MCP_AUTH_MODEdefault: noneAuthentication mode to use: 'none', 'jwt', or 'oauth'.
com.mcparmory/google-sheets
domdomegg/google-sheets-mcp
henilcalagiya/google-sheets-mcp
cct15/war-dashboard-data
moooonad/mcp-google-sheets-full
io.github.br0ski777/csv-to-json