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 Registry2 stars0 forksTypeScriptApache-2.0Updated today
ClaudeWave Trust Score
95/100
Verified
Passed
  • Open-source license (Apache-2.0)
  • Actively maintained (<30d)
  • Clear description
  • Topics declared
  • Documented (README)
Last scanned: 9/21/2026
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 or 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-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.4.0-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>

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

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

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