Find air-quality stations and read pollutant observations from government monitors via OpenAQ v3.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
We haven't yet run this listing's install command through our automated sandbox check. This isn't a red flag β we're steadily working through the catalog.
π‘ Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
Find air-quality monitoring stations, read latest sensor values, and pull historical pollutant series via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://openaq.caseyjhand.com/mcp
openaq-mcp-server wraps the OpenAQ v3 API to expose measured air quality β physical-sensor observations from government reference monitors and research-grade sensors worldwide. It is the ground-truth counterpart to a modeled air-quality grid: where a model gives a concentration anywhere, OpenAQ gives an actual reading from a physical monitor β sparser, unevenly distributed, but real.
Coverage is uneven and honest. An empty result means there is no monitoring there, not that the air is clean β every discovery tool says so, and points to a modeled fallback (open-meteo-mcp-server's air-quality tool) for anywhere-coverage.
Five domain tools cover the workflow β discover stations, read current values, pull history, and resolve the two catalogs (pollutant units, country coverage) β plus two DataCanvas tools for SQL over historical series too large to inline. The data model is location β sensor β parameter; the server hides the sensor layer so you think in stations and parameters, never sensor ids.
| Tool | Description |
|---|---|
openaq_find_locations | Find monitoring stations near a point, in a bounding box, or by country. The required first step β readings and measurements key on the location id this returns. |
openaq_get_readings | Latest measured value for every sensor at a station, each joined with its pollutant and unit. The current-conditions tool. |
openaq_get_measurements | Historical series for one pollutant at one station over a date range, with raw/hourly/daily aggregation. Large ranges spill to a DataCanvas. |
openaq_list_parameters | Catalog of measurable pollutants and their canonical units. The unit-disambiguation reference. |
openaq_list_countries | Catalog of country-level coverage β data span and parameters measured, filterable by parametersId to answer "which countries measure this pollutant?". An availability check before a regional sweep. |
openaq_dataframe_describe | List the tables and columns staged on a DataCanvas so you can write valid SQL. |
openaq_dataframe_query | Run a read-only SELECT over staged measurement series. |
openaq_find_locationsFind air-quality monitoring stations (measured by physical sensors, not modeled) and the parameters each one reports.
coordinates + radius (near-me), bbox (area sweep), or iso country code; at least one is requiredradius is in metres, 1β25000 (the API hard-caps at 25000); larger areas need bbox, which returns no distanceparametersId narrows to stations that measure a given parameter (each returned station still lists all its sensors)limit caps at 100 stations per page; page (1-based) reaches the rest β distance ordering applies within a page, not across pages, so paging is for iso/bbox sweeps rather than near-me searchescoordinates and bbox accept whitespace around the commas β "47.6062, -122.3321" is normalized to its space-free formisMonitor/isMobile, the parameters its sensors measure with units, and the datetimeFirst/datetimeLast data spanopenaq_list_countries, or fall back to the modeled open-meteo air-quality toolopenaq_get_readingsLatest value per sensor at a station β the current-conditions tool.
locationId from openaq_find_locations, or coordinates + parametersId to auto-resolve the nearest station (within 25km) that measures that parameterlocationId, parametersId optionally filters the returned values to one parameter; omit it for all sensorsdatetimeLast β recency varies by station, so "latest" may be minutes or hours oldopenaq_get_measurementsHistorical measurement series for one pollutant at one station over a date range β for trend analysis and "was last week worse than the monthly average?".
locationId and a parametersId and work in stations β the server maps station + parameter to the underlying sensor (v3 series are sensor-scoped), so you get the series for that pollutant at that stationaggregation: raw (every reported value), hourly, or daily β hourly/daily add a per-bucket statistical summary (min, median, max, mean, sd)datetimeFrom/datetimeTo accept a date (YYYY-MM-DD) or full UTC timestamp (YYYY-MM-DDTHH:MM:SSZ); omit for the most recent valuesA multi-month raw series can be thousands of rows β too large to inline without blowing context, and a fixed slice would blind the agent to the rest. When a series exceeds the inline preview (100 rows), openaq_get_measurements stages the pulled rows on a DuckDB-backed DataCanvas and returns:
series, capped at 100 rows) plus rowCount and the totalCount enrichment,truncated: true, canvasId, and a tableName of the form measurements_<sensorId>.The internal pager stops at 5000 rows, so the canvas holds the whole series only when totalCount is at or below that. Above it β or when a page fails partway and the rows already pulled are kept β the response carries a notice saying so and how to reach the rest (shorter date windows, or hourly/daily aggregation).
You then query the full set with the two consumer tools:
| Tool | Use |
|---|---|
openaq_dataframe_describe | List staged tables and their columns (value, datetimeFrom, datetimeTo, min, median, max, avg, sd, percentComplete, flagged) β call this first to write SQL without guessing names. |
openaq_dataframe_query | Run a read-only SELECT for monthly means, exceedance counts, percentiles, or cross-sensor comparisons. |
Pass a prior canvas_id back into openaq_get_measurements to stage a second station's series on the same canvas (as measurements_<otherSensorId>), then JOIN/UNION the two in one query to compare stations.
Requires CANVAS_PROVIDER_TYPE=duckdb. Without it, openaq_get_measurements still returns the truncated preview plus a notice (it does not fail), and the two dataframe tools return a canvas_unavailable error directing you to enable DuckDB. The same holds when the canvas is set to duckdb but cannot start β a missing DuckDB native in a .mcpb bundle, say: openaq_get_measurements returns the preview and names the staging failure in its notice rather than dropping a series it already fetched.
Not available in the .mcpb bundle. The Claude Desktop bundle ships without DuckDB's platform-specific native binding β including it would lock the bundle to the OS it was packed on and push it far past the size registries accept. Leave CANVAS_PROVIDER_TYPE at none there; use the npm, npx, or Docker install for canvas work.
openaq_dataframe_query is read-only by design β writes, DDL, and file/network table functions are rejected; only a single SELECT runs.
No reviews yet β be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/openaq-mcp-server)<a href="https://allmcps.com/mcp/openaq-mcp-server"><img src="https://allmcps.com/api/badge/openaq-mcp-server?style=directory" alt="Openaq MCP Server on AllMCPs" /></a>