Openair 3 Oss
БесплатноНе проверенMCP server wrapping the openair R package for air quality data analysis, enabling time series loading, statistical summaries, and publication-ready plots like p
Описание
MCP server wrapping the openair R package for air quality data analysis, enabling time series loading, statistical summaries, and publication-ready plots like polar and calendar plots.
README
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
end
client-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 | fastmcp run … --transport stdio or --transport http --port 8001 |
fastmcp run … --transport http --port 8001 on the host (+ reverse proxy optional) |
| Client MCP | stdio (spawn Python) or mcp-remote → http://127.0.0.1:8001/sse |
mcp-remote → https://your-host/…/sse (+ token if enabled) |
| CSV paths | Paths on your disk | export_local_series.py on your PC, or paths on the server disk — not IDE workspace paths |
| Node.js on client | Only if using HTTP + mcp-remote |
Yes (npx mcp-remote) |
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 | import_aurn, import_europe, … |
Same R functions, manual |
| CSV / IoT exports | load_series_from_csv |
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.py
Install 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 8001
Run stdio (IDE and R on the same machine — no mcp-remote, no separate HTTP process):
fastmcp run server.py:mcp --transport stdio
Then 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 | load_series_from_excel / load_series_from_csv |
| Excel / CSV | User PC (remote MCP) | export_local_series.py on the client → prepare_series_for_openair(data=…) — or copy to server disk; load_series_from_upload (base64, ≤ 1 MB) last resort |
| UK / EU public networks | Fetched by R | import_aurn, import_europe, import_ukaq, … |
| ADMS / AURN CSV on server | Server disk path | import_adms, import_aurn_csv |
| Another MCP (API, database, spreadsheet, …) | Upstream MCP | prepare_series_for_openair(json_exports=[…]) → plot |
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.
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 --> prep
The 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 exports- One 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 | export_local_series.py → prepare(data=…) — ingest-local-export skill |
| VS Code smoke (no Excel) | Plugin tests/fixtures/felisa_munarriz.json — vscode-chat-felisa.md |
| File on server host | load_series_from_excel with an absolute path you confirmed |
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_openair- Plot 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 |
|---|---|
load_series_from_csv |
Parse a wide CSV on server disk into SeriesV1. EU/ES date formats; optional columns, timezone, dedupe_timestamps. |
load_series_from_excel |
Parse .xlsx on server disk — same options as CSV (regional air-quality exports). |
load_series_from_upload |
Parse CSV or xlsx from base64 upload. Default limit 1 MB raw; override with OPENAIR_INGEST_MAX_BYTES on the server. Use export_local_series.py instead for larger files. |
prepare_series_for_openair |
Align timestamps, granularity, timezone; optional json_exports from other MCPs. |
ping |
Server liveness check. |
health_r |
R + openair version and install status. |
openair_docs |
Index of openair functions exposed as MCP tools. |
openair_function_help |
R help text for a named openair function. |
Data import (R)
| Tool | Description |
|---|---|
import_aurn |
UK Automatic Urban and Rural Network (AURN). Requires internet. |
import_adms |
CERC ADMS files on server disk (.bgd, .met, .mop, .pst). |
import_aurn_csv |
UK AURN hourly CSV export on server disk. |
import_ukaq |
UK Air Pollution Networks (AQE, SAQN, WAQN, NI, local). |
import_europe |
European monitoring networks via openair (data until Feb 2024). |
import_meta |
Site metadata — codes, names, coordinates, available pollutants. |
import_traj |
Pre-calculated HYSPLIT 96-hour back trajectories. |
Time series plots (R)
| Tool | Description |
|---|---|
time_plot |
One or more pollutant time series. |
summary_plot |
Multi-panel overview: averaged time series + data completeness. |
calendar_plot |
Calendar view — day-of-week and seasonal patterns. |
time_variation |
Diurnal, weekday, and monthly patterns with uncertainty. |
variation_plot |
Mean and confidence intervals by time dimension. |
time_prop |
Stacked proportional contributions over time (wind-aware input). |
trend_level |
Heat map of concentration by two time dimensions. |
smooth_trend |
GAM smooth trend with confidence intervals. |
theil_sen |
Non-parametric Theil–Sen trend and significance. |
scatter_plot |
Scatter between two pollutants. |
cor_plot |
Correlation matrix (≥2 series). |
conditional_quantile |
Model evaluation — predicted vs observed quantiles. |
taylor_diagram |
Model evaluation — Taylor diagram (obs + models). |
Polar / wind (R)
Requires wind speed (ws) and direction (wd) in prepared data.
| Tool | Description |
|---|---|
polar_plot |
Bivariate polar plot — concentration vs wind (source ID). |
polar_annulus |
Polar annulus with a third variable (season, hour, …). |
polar_diff |
Difference between two time periods on the same pollutant. |
polar_freq |
Wind frequency polar with optional pollutant stats. |
polar_cluster |
K-means clustering of polar plots (intensive). |
pollution_rose |
Pollution rose by direction and speed. |
percentile_rose |
Percentile rose by wind direction. |
wind_rose |
Classic wind rose. |
Trajectory (R)
| Tool | Description |
|---|---|
traj_plot |
Back-trajectory line plot (TrajSeriesV1). |
traj_level |
Gridded concentration heat map from trajectory frequency. |
traj_cluster |
K-means clustering of back trajectories. |
Stats & transforms (R)
| Tool | Description |
|---|---|
aq_stats |
Summary stats — mean, median, percentiles, capture %. |
mod_stats |
Model evaluation — FAC2, MB, RMSE, r (model series first, observed second). |
calc_percentile |
Percentile values as JSON. |
time_average |
Resample to another resolution (returns SeriesV1). |
rolling_mean |
Rolling mean (returns SeriesV1). |
rolling_quantile |
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 8001
stdio (IDE and R on the same machine — no HTTP port, no mcp-remote):
fastmcp run server.py:mcp --transport stdio
That 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 |
|---|---|
RSCRIPT_PATH |
Path to Rscript (default Rscript) |
RSCRIPT_TIMEOUT_SEC |
Default R subprocess timeout |
OPENAIR_ARTIFACTS_DIR |
Where PNGs are written (default artifacts/) |
OPENAIR_MCP_TRANSPORT |
http or stdio when using python server.py |
OPENAIR_MCP_PORT |
HTTP port (default 8001) |
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
pytest
Project 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 | Plugin tests/ | 15-plot harness against deployed MCP — legends, encoding, end-to-end |
| Unit | This repo pytest tests/ |
Ingest, prepare, encoding, DST — fast, no R plots required for most |
| Host smoke | check_integrations.py |
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 load_series_from_csv |
Global / sensor exports without custom glue | Done (v0.1.0) |
Excel load_series_from_excel |
Regional .xlsx (ES/EU date formats, dedupe) |
Done (v0.1.0) |
Upload load_series_from_upload |
Remote MCP + file on user PC (base64, ≤ 1 MB) | Done (v0.1.0) |
export_local_series.py |
Agent-run local export → prepare(data=…) (no R on client) |
Done (v0.1.0) |
UK/EU import_* |
Public network path familiar to openair users | Done (v0.1.0) |
| worldmet | Meteo when CSV has no wind | Planned |
| openairmaps | Leaflet maps in chat | Later (if demand) |
| deweather | 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 import_europe docs). |
| 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.
Установка Openair 3 Oss
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/miguel-escribano/openair-3-mcp-server-ossFAQ
Openair 3 Oss MCP бесплатный?
Да, Openair 3 Oss MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Openair 3 Oss?
Нет, Openair 3 Oss работает без API-ключей и переменных окружения.
Openair 3 Oss — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Openair 3 Oss в Claude Desktop, Claude Code или Cursor?
Открой Openair 3 Oss на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Notion
Read and write pages in your workspace
автор: NotionLinear
Issues, cycles, triage — from Claude
автор: LinearGoogle Drive
Search and read your Drive files
автор: Googlemindsdb/mindsdb
Connect and unify data across various platforms and databases with [MindsDB as a single MCP server](https://docs.mindsdb.com/mcp/overview).
автор: mindsdbCompare Openair 3 Oss with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории productivity
