Find air-quality monitoring stations and read measured pollutant observations (PM2.5, PM10, O3, NO2, SO2, CO, and more) from government monitors worldwide via the OpenAQ v3 API, with DataCanvas SQL over historical series.
- ✓Open-source license (Apache-2.0)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
git clone https://github.com/cyanheads/openaq-mcp-server{
"mcpServers": {
"openaq": {
"command": "node",
"args": ["/path/to/openaq-mcp-server/dist/index.js"]
}
}
}MCP Servers overview
<div align="center">
<h1>@cyanheads/openaq-mcp-server</h1>
<p><b>Find air-quality monitoring stations, read latest sensor values, and pull historical pollutant series via MCP. STDIO or Streamable HTTP.</b>
<div>7 Tools (2 opt-in) • 2 Resources</div>
</p>
</div>
<div align="center">
[](https://www.npmjs.com/package/@cyanheads/openaq-mcp-server) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/openaq-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.typescriptlang.org/) [](https://bun.sh/)
</div>
<div align="center">
[](https://github.com/cyanheads/openaq-mcp-server/releases/latest/download/openaq-mcp-server.mcpb) [](https://cursor.com/en/install-mcp?name=openaq-mcp-server&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjeWFuaGVhZHMvb3BlbmFxLW1jcC1zZXJ2ZXIiXSwiZW52Ijp7Ik9QRU5BUV9BUElfS0VZIjoieW91ci1hcGkta2V5In19) [](https://vscode.dev/redirect?url=vscode:mcp/install?%7B%22name%22%3A%22openaq-mcp-server%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40cyanheads%2Fopenaq-mcp-server%22%5D%2C%22env%22%3A%7B%22OPENAQ_API_KEY%22%3A%22your-api-key%22%7D%7D)
[](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)
</div>
<div align="center">
**Public Hosted Server:** [https://openaq.caseyjhand.com/mcp](https://openaq.caseyjhand.com/mcp)
</div>
---
## Overview
Measured air quality from the OpenAQ v3 API — physical-sensor observations from government reference monitors and research-grade sensors worldwide. Find monitoring stations, read current values, and pull historical pollutant series from any MCP client. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
### Tools
| 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, 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`. 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. |
### Resources
| Resource | Description |
|:---|:---|
| `openaq://location/{locationId}` | Location metadata for a known location id — name, coordinates, country, provider, sensors (each with parameter + unit), and data span. |
| `openaq://parameters` | Full pollutant + unit catalog (same data as `openaq_list_parameters`). |
All resource data is also reachable via tools — both resources mirror tool output, so tool-only MCP clients lose nothing.
## Capability reference
### `openaq_find_locations` <sub>tool</sub>
- Three search scopes — `coordinates` + `radius` (near-me), `bbox` (area sweep), or `iso` country code; at least one is required
- `radius` is in metres, 1–25000 (the API hard-caps at 25000); larger areas need `bbox`, which returns no distance
- `parametersId` 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 further pages — distance ordering applies within a page, not across pages
- Returns each station's id, name, coordinates, distance (coordinate search only), country, provider, `isMonitor`/`isMobile`, its parameters with units, and the `datetimeFirst`/`datetimeLast` data span
- Empty result means no coverage, not clean air — widen the radius, check `openaq_list_countries`, or fall back to the modeled `open-meteo-mcp-server` air-quality tool
---
### `openaq_get_readings` <sub>tool</sub>
- Pass a `locationId` from `openaq_find_locations`, or `coordinates` + `parametersId` to auto-resolve the nearest station (within 25km) that measures that parameter
- Joins the latest feed (keyed only by sensor id) against the station's sensor → parameter → unit map, so every value carries its pollutant and unit
- With `locationId`, `parametersId` optionally filters the returned values to one parameter; omit it for all sensors
- Each value carries its UTC and local timestamp plus the station's `datetimeLast` — recency varies by station
---
### `openaq_get_measurements` <sub>tool</sub>
- Pass a `locationId` and `parametersId`; the server resolves the underlying sensor internally (v3 series are sensor-scoped)
- `aggregation`: `raw` (every reported value), `hourly`, or `daily` — rollups add a per-bucket min/median/max/mean/sd
- `datetimeFrom`/`datetimeTo` accept a date (`YYYY-MM-DD`) or full UTC timestamp; omit either for the most recent values or "up to now"
- Values carry their unit; the server never converts between µg/m³, ppm, and ppb
- Internal paging caps at 5000 rows; past the 100-row inline preview, pulled rows stage on a DataCanvas (`canvasId` + `tableName`) when `CANVAS_PROVIDER_TYPE=duckdb` — without it, the response still returns the truncated preview plus a notice
- Pass a prior `canvas_id` to stage a second station's series on the same canvas, for cross-station `JOIN`/`UNION` queries
---
### `openaq_list_parameters` <sub>tool</sub>
- Optional `query` filters the ~44-parameter catalog by code, display name, or description (case-insensitive); `pollutantsOnly` excludes meteorological/particle-count channels (temperature, humidity, wind, pressure)
- The unit-disambiguation reference — the same pollutant appears under multiple ids for different units (e.g. CO is id 4 in µg/m³, id 8 in ppm, id 102 in ppb)
- Returns each parameter's id, code, display name, canonical unit, and a one-line description
---
### `openaq_list_countries` <sub>tool</sub>
- Optional `query` matches a two-letter input as an exact ISO 3166-1 alpha-2 code, longer input as a substring of code or name; `parametersId` filters to countries measuring that parameter anywhere
- Returns each country's id, ISO code, name, `datetimeFirst`/`datetimeLast` data span, and the parameters measured anywhere within it
- The availability check before a regional `openaq_find_locations` sweep — answers "which countries have NO2 monitoring?"
---
### `openaq_dataframe_describe` <sub>tool</sub>
- Takes a `canvas_id` from a prior `openaq_get_measurements` spill
- Returns each staged `measurements_<sensorId>` table with its row count and column names
- Throws `canvas_unavailable` when `CANVAS_PROVIDER_TYPE` is not `duckdb`
---
### `openaq_dataframe_query` <sub>tool</sub>
- Takes a `canvas_id` and a read-only SQL `SELECT` against the staged measurement tables
- Writes, DDL, and file/network table functions are rejected — only a single `SELECT` runs
- Throws `canvas_unavailable` when DuckDB is off, or `missing_table` when the SQL references a table not staged on that canvas
---
### `openaq://location/{locationId}` <sub>resource</sub>
- Returns name, locality, timezone, country, provider, `isMonitor`/`isMobile`, coordinates, sensors (each with parameter id/name/unit), and the `datetimeFirst`/`datetimeLast` span
- `locationId` comes from `openaq_find_locations`
- Cached 5 minutes — station metadata is near-static, but `datetimeLast` advances as measurements land
---
### `openaq://parameters` <sub>resource</sub>
- Mirrors `openaq_list_parameters` with no query or filter — the full catalog
- Cached 1 hour — the catalog changes only when OpenAQ adds a parameter
## DataCanvas spill workflow
A multi-month `raw` series can be thousands of rows — too large to inline without blowing context. When `openaq_get_measurements` spills, query the staged table 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 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. |
- Requires `CANVAS_PROVIDER_TYPE=duckdb`. Without it — or when a configured canvas fails to start — `openaq_get_measurements` still returns the truncated preview plus a notice rather than dropping data already fetched.
- Not available in the `.mcpb` bundle — the Claude Desktop bundle ships without DuckDB's platform-specific native binding, since bundling it would lock the bundle to the OS it was packed on. Use the npm, `npx`, or Docker install for canvas work.
What people ask about openaq-mcp-server
What is cyanheads/openaq-mcp-server?
+
cyanheads/openaq-mcp-server is mcp servers for the Claude AI ecosystem. Find air-quality monitoring stations and read measured pollutant observations (PM2.5, PM10, O3, NO2, SO2, CO, and more) from government monitors worldwide via the OpenAQ v3 API, with DataCanvas SQL over historical series. It has 2 GitHub stars and its last recorded update is dated 2026-09-20.
How do I install openaq-mcp-server?
+
You can install openaq-mcp-server by cloning the repository (https://github.com/cyanheads/openaq-mcp-server) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is cyanheads/openaq-mcp-server safe to use?
+
Our security agent has analyzed cyanheads/openaq-mcp-server and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains cyanheads/openaq-mcp-server?
+
cyanheads/openaq-mcp-server is maintained by cyanheads. The last recorded GitHub activity is dated 2026-09-20, with 13 open issues.
Are there alternatives to openaq-mcp-server?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy openaq-mcp-server to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/cyanheads-openaq-mcp-server)<a href="https://claudewave.com/repo/cyanheads-openaq-mcp-server"><img src="https://claudewave.com/api/badge/cyanheads-openaq-mcp-server" alt="Featured on ClaudeWave: cyanheads/openaq-mcp-server" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ
The fastest path to AI-powered full stack observability, even for lean teams.