Skip to main content
ClaudeWave
cyanheads avatar
cyanheads

openaq-mcp-server

View on GitHub

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.

MCP ServersOfficial Registry1 stars0 forksTypeScriptApache-2.0Updated today
Install in Claude Code / Claude Desktop
Method: Manual
Claude Code CLI
git clone https://github.com/cyanheads/openaq-mcp-server
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "openaq": {
      "command": "node",
      "args": ["/path/to/openaq-mcp-server/dist/index.js"]
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Clone https://github.com/cyanheads/openaq-mcp-server and follow its README for install instructions.
Use cases

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 &amp; Streamable HTTP.</b>
  <div>7 Tools (2 opt-in) • 2 Resources</div>
  </p>
</div>

<div align="center">

[![npm](https://img.shields.io/npm/v/@cyanheads/openaq-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/openaq-mcp-server) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/openaq-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.29.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![TypeScript](https://img.shields.io/badge/TypeScript-^6.0.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3.11-blueviolet.svg?style=flat-square)](https://bun.sh/)

</div>

<div align="center">

[![Install in Claude Desktop](https://img.shields.io/badge/Install_in-Claude_Desktop-D97757?style=for-the-badge&logo=anthropic&logoColor=white)](https://github.com/cyanheads/openaq-mcp-server/releases/latest/download/openaq-mcp-server.mcpb) [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=openaq-mcp-server&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjeWFuaGVhZHMvb3BlbmFxLW1jcC1zZXJ2ZXIiXSwiZW52Ijp7Ik9QRU5BUV9BUElfS0VZIjoieW91ci1hcGkta2V5In19) [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white)](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)

[![Framework](https://img.shields.io/badge/Built%20on-@cyanheads/mcp--ts--core-67E8F9?style=flat-square)](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)

</div>

---

`openaq-mcp-server` wraps the [OpenAQ v3 API](https://docs.openaq.org/) 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`](https://github.com/cyanheads/open-meteo-mcp-server)'s air-quality tool) for anywhere-coverage.

## Tools

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. 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_locations`

Find air-quality monitoring stations (measured by physical sensors, not modeled) and the parameters each one reports.

- 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)
- Returns each station's id, name, coordinates, distance (when searching by coordinates), country, provider, `isMonitor`/`isMobile`, the parameters its sensors measure 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` air-quality tool

---

### `openaq_get_readings`

Latest value per sensor at a station — the current-conditions tool.

- Pass a `locationId` from `openaq_find_locations`, **or** `coordinates` + `parametersId` to auto-resolve the nearest station (within 25km) that measures that parameter
- The raw OpenAQ latest feed is keyed only by sensor id; this tool **joins** it 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, so "latest" may be minutes or hours old

---

### `openaq_get_measurements`

Historical measurement series for one pollutant at one station over a date range — for trend analysis and "was last week worse than the monthly average?".

- Pass a `locationId` and a `parametersId`; the tool resolves the station's sensor for that parameter internally (v3 series are sensor-scoped, but you think in stations)
- `aggregation`: `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 values
- Values carry their unit; the server **never converts** between µg/m³, ppm, and ppb (the conversion is gas- and temperature-dependent)
- **Large ranges spill to a DataCanvas** — see below

### DataCanvas spill workflow

A 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 **full** set on a DuckDB-backed DataCanvas and returns:

- a preview (`series`, capped at 100 rows) plus `rowCount` and the `totalCount` enrichment,
- `truncated: true`, `canvasId`, and a `tableName` of the form `measurements_<sensorId>`.

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.

`openaq_dataframe_query` is read-only by design — a four-layer SQL gate rejects writes, DDL, and file/network table functions; only a single `SELECT` runs.

## Resources and prompts

| Type | Name | Description |
|:---|:---|:---|
| Resource | `openaq://location/{locationId}` | Location metadata for a known location id — name, coordinates, country, provider, sensors (each with parameter + unit), and data span. |
| Resource | `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. There are no prompts: this is a data-lookup domain with no recurring analysis template that earns one (a WHO-guideline health snapshot is a cross-server workflow, not localized here).

## Features

Built on [`@cyanheads/mcp-ts-core`](https://www.npmjs.com/package/@cyanheads/mcp-ts-core):

- Declarative tool and resource definitions — single file per primitive, framework handles registration and validation
- Unified error handling — handlers throw, framework catches, classifies, and formats
- Typed error contracts per tool — each network tool declares `reason`/`code`/`when`/`recovery`, so failures carry a concrete next move
- Pluggable auth (`none`, `jwt`, `oauth`) and structured, request-scoped logging with optional OpenTelemetry tracing
- STDIO and Streamable HTTP transports from one codebase

OpenAQ-specific:

- Single typed client over the OpenAQ v3 REST API with `X-API-Key` auth, retry with rate-limit-calibrated backoff, and OpenAQ-specific error classification (clean-JSON 404 → `NotFound`; the Python-repr 422 body → `ValidationError`; the plain
ai-agentsair-qualitycyanheadsenvironmentmcpmcp-servermodel-context-protocolopenaqpollutiontypescript

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 1 GitHub stars and was last updated today.

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?

+

cyanheads/openaq-mcp-server has not been audited yet by our security agent. Review the original repository on GitHub before using it in production.

Who maintains cyanheads/openaq-mcp-server?

+

cyanheads/openaq-mcp-server is maintained by cyanheads. The last recorded GitHub activity is from today, with 0 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.

Featured on ClaudeWave: cyanheads/openaq-mcp-server
[![Featured on ClaudeWave](https://claudewave.com/api/badge/cyanheads-openaq-mcp-server)](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

openaq-mcp-server alternatives