openair-3-mcp-oss
Allows data fetched from an Airtable MCP to be imported and analyzed using openair's air quality visualization and analysis tools.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@openair-3-mcp-ossLoad sample_hourly.csv and create a calendar plot of pm25"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
openair-3-mcp-server-oss
The server — run on any machine with R (your laptop, lab VM, or cloud). MCP clients connect via stdio (local) or HTTP (local 127.0.0.1 or remote host via mcp-remote).
Give your AI agent the ability to analyse air quality — import public networks, load CSV exports, and produce publication-grade openair charts from chat.
Pair with the client plugin for your IDE: openair-3-mcp-client-plugin-oss (Claude, Cursor, Codex, VS Code).
Not affiliated with openair-project maintainers.
45 tools — 37 R-backed plots/imports/stats + 8 Python pipeline tools (CSV, Excel, upload, prepare, health, docs)
2 transports — stdio (IDE and R on the same machine) or HTTP (localhost or remote via
mcp-remote)Agent skills — plugin manuals + workflows (
skills/)Self-hosted — you choose where R runs; the default path is local on your own machine
Architecture
flowchart LR
subgraph localSetup ["Local (stdio) — IDE and R on the same machine"]
IDE_L["IDE + client-plugin"]
S_L["server-oss + R"]
IDE_L -- ".mcp.json (stdio)" --> S_L
end
subgraph remoteSetup ["Remote (HTTP) — server on another host"]
IDE_R["IDE + client-plugin"]
Proxy["mcp-remote"]
S_R["server-oss + R"]
IDE_R -- ".mcp.json" --> Proxy -- "HTTPS + token" --> S_R
endclient-plugin on your MCP client · server-oss + R on the host you choose · use stdio when both are on the same machine, HTTP + mcp-remote when the server is elsewhere (including 127.0.0.1).
Choose your setup
Local | Remote | |
R location | Same machine as the IDE | Another host (VM, cloud, lab server) |
Run server |
|
|
Client MCP | stdio (spawn Python) or |
|
CSV paths | Paths on your disk |
|
Node.js on client | Only if using HTTP + | Yes ( |
Remote MCP (VS Code, Cursor, etc.): load_series_from_excel(path="data/felisa.xlsx") only works if that file is on the server host. Example paths in docs are not bundled. For chat smoke use the plugin fixture — vscode-chat-felisa.md.
Server run commands are in Running the server; client .mcp.json wiring lives in the client plugin README.
vs R console / openair GUI
This project | R console + openair | |
Natural-language workflows | Yes (via MCP client) | Manual scripting |
PNG charts in chat | Yes (inline MCP image blocks) | Save files locally |
Public network import |
| Same R functions, manual |
CSV / IoT exports |
| Read + reshape by hand |
Tool discovery for agents | MCP tool list + skill | Docs + memory |
Open source server | MIT | MIT (openair 3.x) |
Self-hosted | Yes | Yes |
Quick start
git clone https://github.com/miguel-escribano/openair-3-mcp-server-oss
cd openair-3-mcp-server-oss
python -m venv .venv
# Windows: .venv\Scripts\activate
# Unix: source .venv/bin/activate
pip install -e .
cp .env.example .env
python check_integrations.pyInstall R packages on the same machine:
install.packages(c("openair", "jsonlite"), repos = "https://cloud.r-project.org")
# optional: legendry only adds the cor_plot dendrogram — everything else works without it
install.packages("legendry", repos = "https://cloud.r-project.org")Run HTTP MCP (same machine or remote host; IDE connects via mcp-remote):
fastmcp run server.py:mcp --transport http --port 8001Run stdio (IDE and R on the same machine — no mcp-remote, no separate HTTP process):
fastmcp run server.py:mcp --transport stdioThen install the client plugin and wire MCP — local stdio, localhost HTTP, or remote URL.
Getting your data in
Your data | Where it lives | What to use |
Excel / CSV | Server disk |
|
Excel / CSV | User PC (remote MCP) |
|
UK / EU public networks | Fetched by R |
|
ADMS / AURN CSV on server | Server disk path |
|
Another MCP (API, database, spreadsheet, …) | Upstream MCP |
|
Another MCP: fetch/query runs on the upstream MCP (Postgres read MCP, REST API MCP, Airtable MCP, etc.). Pass its export JSON to prepare_series_for_openair. The export must include series_v1 or a compatible parameters[].data bucket layout — see export_bridge.py and schemas/series.v1.json. Do not build series arrays in the client.
Related MCP server: mcp-airq-cloud
Data pipeline
flowchart TB
agent["Agent / chat — orchestrates the pipeline"]
subgraph in ["Data in (deterministic tools)"]
disk["load_series_from_*"]
export["export_local_series.py"]
net["import_*"]
mcp["json_exports"]
end
v1["SeriesV1"]
prep["prepare_series_for_openair"]
df["R data.frame"]
plot["openair plot"]
png["PNG"]
agent --> disk & export & net & mcp
disk --> v1
export --> v1
net --> v1
mcp --> prep
agent --> prep --> df --> plot --> png
v1 --> prepThe agent orchestrates every step. Calculation (parse, align, plot) stays on the server — no LLM-invented JSON or date parsing in the client.
Ingest — disk load, client export script, public import, or JSON from another MCP → SeriesV1
prepare — align timestamps, granularity, timezone, gaps
R — build
data.frame(date, …)then callopenair::timePlot(etc.)Return — PNG (+ short text summary)
Typical flows
CSV (global / sensor export)
Wide table: datetime column + pollutant columns. Skip metadata (battery, lat, …) with optional columns.
load_series_from_csv— path on server disk (ISO or EU day-first dates, e.g.23/06/2026 00:00h)prepare_series_for_openair— setseries_namewhen multiple pollutants;timezone/timezone_namefor local exportsOne plot tool —
time_plot,calendar_plot, …
Sample files in fixtures/ are for pytest and check_integrations.py only (ingest/date-format smoke). They are not Copilot chat datasets.
Golden-path acceptance: plugin repo tests/ + felisa_munarriz.json. Walkthrough: csv-calendar-plot.md (server-disk CSV flow).
Excel (regional / government exports)
Same pipeline with load_series_from_excel — .xlsx on server disk only. Handles Spanish-style Fecha/hora and duplicate-hour dedupe.
Setup | Path |
Remote MCP + file on your PC |
|
VS Code smoke (no Excel) | Plugin |
File on server host |
|
Walkthrough: local-excel-spain.md. There is no bundled data/felisa.xlsx.
Local file on your PC (remote MCP)
If the MCP server runs elsewhere, paths on your laptop are invisible to load_series_from_*.
Preferred: run scripts/export_local_series.py on your machine (pip install -e . from this repo — no R required). Read the JSON and call prepare_series_for_openair(data=…) on the remote MCP. See the client ingest-local-export skill.
Alternatives: copy the file to server disk, use local stdio MCP, or load_series_from_upload (base64, max 1 MB raw). See the client ingest-local skill.
Public network (UK / EU)
import_aurn/import_europe/import_ukaqprepare_series_for_openairPlot tool
Walkthrough: aurn-time-plot.md.
Another MCP (API, database, spreadsheet, …)
Configure a second MCP in your client (REST API, Postgres, Airtable, custom sensor API, etc.).
Call the upstream tool that returns hourly/time-series JSON.
prepare_series_for_openair(json_exports=[export])— optionalseries_name,parameter,granularity,timezone_name.Plot tool.
The upstream MCP owns fetch and query; this server owns alignment and openair plots.
Optional live smoke: OPENAIR_SMOKE_NETWORK=1 python check_integrations.py
Available tools
Plot and import tools are auto-discovered from r/scripts/*.R manifest headers at startup.
Pipeline (Python)
Tool | Description |
| Parse a wide CSV on server disk into SeriesV1. EU/ES date formats; optional |
| Parse |
| Parse CSV or xlsx from base64 upload. Default limit 1 MB raw; override with |
| Align timestamps, granularity, timezone; optional |
| Server liveness check. |
| R + openair version and install status. |
| Index of openair functions exposed as MCP tools. |
| R help text for a named openair function. |
Data import (R)
Tool | Description |
| UK Automatic Urban and Rural Network (AURN). Requires internet. |
| CERC ADMS files on server disk ( |
| UK AURN hourly CSV export on server disk. |
| UK Air Pollution Networks (AQE, SAQN, WAQN, NI, local). |
| European monitoring networks via openair (data until Feb 2024). |
| Site metadata — codes, names, coordinates, available pollutants. |
| Pre-calculated HYSPLIT 96-hour back trajectories. |
Time series plots (R)
Tool | Description |
| One or more pollutant time series. |
| Multi-panel overview: averaged time series + data completeness. |
| Calendar view — day-of-week and seasonal patterns. |
| Diurnal, weekday, and monthly patterns with uncertainty. |
| Mean and confidence intervals by time dimension. |
| Stacked proportional contributions over time (wind-aware input). |
| Heat map of concentration by two time dimensions. |
| GAM smooth trend with confidence intervals. |
| Non-parametric Theil–Sen trend and significance. |
| Scatter between two pollutants. |
| Correlation matrix (≥2 series). |
| Model evaluation — predicted vs observed quantiles. |
| Model evaluation — Taylor diagram (obs + models). |
Polar / wind (R)
Requires wind speed (ws) and direction (wd) in prepared data.
Tool | Description |
| Bivariate polar plot — concentration vs wind (source ID). |
| Polar annulus with a third variable (season, hour, …). |
| Difference between two time periods on the same pollutant. |
| Wind frequency polar with optional pollutant stats. |
| K-means clustering of polar plots (intensive). |
| Pollution rose by direction and speed. |
| Percentile rose by wind direction. |
| Classic wind rose. |
Trajectory (R)
Tool | Description |
| Back-trajectory line plot (TrajSeriesV1). |
| Gridded concentration heat map from trajectory frequency. |
| K-means clustering of back trajectories. |
Stats & transforms (R)
Tool | Description |
| Summary stats — mean, median, percentiles, capture %. |
| Model evaluation — FAC2, MB, RMSE, r (model series first, observed second). |
| Percentile values as JSON. |
| Resample to another resolution (returns SeriesV1). |
| Rolling mean (returns SeriesV1). |
| Rolling quantile (returns SeriesV1). |
Plot tools return [text, image] MCP blocks so clients can show the chart inline. Stats tools return structured JSON.
Prerequisite: R 4.1+ with openair 3.x (ggplot2 backend) on the server host. Run
health_rafter install.
Running the server
Pick a transport based on where your IDE runs relative to R:
HTTP (R on your laptop at 127.0.0.1, or a remote host):
fastmcp run server.py:mcp --transport http --port 8001stdio (IDE and R on the same machine — no HTTP port, no mcp-remote):
fastmcp run server.py:mcp --transport stdioThat is all this repo handles. Connecting an IDE to the running server is the client plugin's job — copy its .mcp.json.example and choose stdio, localhost HTTP, or a remote URL (+ token). See the client plugin → Installation detail and .mcp.json.example. Node.js 18+ is needed on the client only for HTTP + mcp-remote.
Server configuration
Copy .env.example → .env:
Variable | Purpose |
| Path to |
| Default R subprocess timeout |
| Where PNGs are written (default |
|
|
| HTTP port (default |
R only needs to run on the server — not on every IDE client.
Development
git clone https://github.com/miguel-escribano/openair-3-mcp-server-oss
cd openair-3-mcp-server-oss
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env
python check_integrations.py
pytestProject structure
server.py # FastMCP entry — tool registration
openair_mcp/
├── prepare.py # prepare_series_for_openair
├── export_bridge.py # json_exports merge / SeriesV1
├── r_bridge.py # R subprocess + manifest discovery
├── contracts.py # Pydantic SeriesV1, WindSeriesV1, …
└── utils.py # CSV → SeriesV1
r/
├── scripts/ # One .R file = one MCP tool (MANIFEST header)
└── common/ # Shared R helpers
schemas/ # JSON Schema for series contracts
fixtures/ # Tiny CSV samples for pytest / check_integrations (not chat fixtures)
tests/ # Python unit tests (pre-deploy — not plot acceptance)
check_integrations.py # Smoke suite (Python always; R when available)Add a new tool: drop an R script in r/scripts/ with a # MANIFEST: {...} line — no Python edit required.
Testing
Tier | Where | Purpose |
Acceptance | 15-plot harness against deployed MCP — legends, encoding, end-to-end | |
Unit | This repo | Ingest, prepare, encoding, DST — fast, no R plots required for most |
Host smoke |
| Tool registration + R subprocess when R is installed |
After deploy, run the plugin harness — see tests/README.md. Full checklist: docs/VALIDATION.md.
Tech stack
Python 3.11+ — MCP server, CSV pipeline, contracts
FastMCP 3.x — MCP protocol
Pydantic — SeriesV1 / request validation
R + openair 3.x — Plots, imports, statistics (openair MIT on CRAN)
jsonlite — R JSON bridge
Use cases
Researcher with AURN data — “Import Marylebone Road PM2.5 for 2023 and calendar plot it”
IoT / indoor CSV — Load hourly export from disk → time plot or diurnal pattern
Source apportionment hint — Polar plot when wind columns exist
Trend reporting — Theil–Sen or smooth trend for long series
Multi-pollutant screening — Correlation matrix across prepared series
Ex-GUI habit — Same openair charts you know, alongside your usual R workflow — from Claude / Cursor / Codex when chat fits
Roadmap
Feature | What it unlocks | Status |
CSV | Global / sensor exports without custom glue | Done (v0.1.0) |
Excel | Regional | Done (v0.1.0) |
Upload | Remote MCP + file on user PC (base64, ≤ 1 MB) | Done (v0.1.0) |
| Agent-run local export → | Done (v0.1.0) |
UK/EU | Public network path familiar to openair users | Done (v0.1.0) |
Meteo when CSV has no wind | Planned | |
Leaflet maps in chat | Later (if demand) | |
Met normalisation | Advanced (later) |
Optional: JSON from other MCPs
prepare_series_for_openair(json_exports=[…]) accepts generic time-series JSON (series_v1 or bucketed parameters). Standalone use needs only CSV or import_*.
Scope
This binomio provides charts and data access through MCP, powered by openair on R. It does not include interpretation, compliance advice, or health guidance — those belong in your own reporting workflow.
For methodology, see the openair book. Teams that pair generative AI with air-quality data often add a controlled knowledge base for narrative beyond plots; that layer is separate from this chart stack.
Release v0.1.0 — initial public release of the binomio. CSV/Excel/upload ingest with optional lat/lon (meta for future worldmet), public-network imports (AURN, EU, …), the full openair plot/stats surface. Golden-path Felisa fixture + harness live in the client plugin (tests/fixtures/felisa_munarriz.json). Pair with the client plugin at the same release. Feedback welcome via issues or the landing repo.
Third-party and attribution
See also NOTICE.md for openair MIT text and deploy-time third-party listing.
This project is not affiliated with openair-project. If you use it — commercial or not — please attribute the parts you rely on.
openair (software)
Charts and statistics are produced by the openair R package (MIT). In papers, reports, or published figures, cite:
Carslaw, D. C. and K. Ropkins (2012). openair — an R package for air quality data analysis. Environmental Modelling & Software, 27–28, 52–61. doi:10.1016/j.envsoft.2011.09.008
BibTeX and updates: openair citation. In R: citation("openair").
Public air-quality data
import_aurn, import_europe, and related tools fetch third-party datasets, not data shipped with this repo. You must follow each provider’s licence when you publish or redistribute results.
Source | Typical requirement |
UK networks (AURN, etc.) | Open Government Licence. Attribute Defra / uk-air.defra.gov.uk. |
European networks | Respect source terms; openair notes EU import availability (see |
Your CSV | Your responsibility only. |
Example UK data attribution (OGL):
© Crown copyright Defra via uk-air.defra.gov.uk, licensed under the Open Government Licence.
This MCP wrapper (optional)
openair-3-mcp-server-oss and openair-3-mcp-client-plugin-oss are MIT. You do not need our permission for non-commercial or commercial use. If this MCP binomio was part of your workflow and you publish methods, a brief mention or link to the GitHub repos is appreciated — but the scientific citation above is openair, not this wrapper.
License
MIT — see LICENSE. See Third-party and attribution for openair and data sources.
This server cannot be deployed
Maintenance
Related MCP Connectors
Air Quality MCP — wraps air-quality-api.open-meteo.com (free, no auth)
OpenAQ MCP — wraps OpenAQ v2 API (free, no auth required)
OpenWeather MCP — wraps the OpenWeatherMap API (openweathermap.org)
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP Server for global weather, forecasts, air quality, and climate data using Open-Meteo, no API key required.MIT
- AlicenseNot gradedqualityBmaintenanceMCP server for the air-Q Cloud API, enabling remote retrieval of air quality sensor data and historical analysis through read-only tools like listing devices, fetching readings, and exporting charts or data.Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables querying of official Netherlands air quality data from the RIVM Luchtmeetnet API via MCP tools.1 npmMIT
- FlicenseNot gradedqualityBmaintenanceMCP server for querying Seoul's official air quality data, including real-time and hourly measurements by district. Enables AI assistants to answer questions about fine dust and air pollution using public data from Seoul Open Data Plaza.-