Skip to main content
Glama
Nanparam

IQAir MCP Server

by Nanparam

IQAir MCP Server

An MCP server that exposes real-time air-quality data from IQAir — built by reverse-engineering the IQAir website (no official API key required).

It was created for the Jakarta air-quality page (https://www.iqair.com/id/air-quality/indonesia/jakarta/jakarta) but works for any IQAir location.

What it returns

For a location you get:

  • US AQI and the main pollutant

  • Per-pollutant readings: PM2.5, PM10, O₃, SO₂ (AQI + concentration)

  • Weather: temperature, humidity, pressure, wind

  • Reporting station count

  • 7-day and 72-hour forecasts

  • Coordinates / timezone

Tools

Tool

Description

get_jakarta_air_quality(locale="id")

Full Jakarta report (current + forecasts).

get_jakarta_current(locale="id")

Jakarta current conditions only (lighter).

get_jakarta_forecast(locale="id", kind="daily")

Jakarta forecast (daily or hourly).

get_air_quality_by_path(path, locale="en")

Any location, e.g. path="indonesia/west-java/bandung".

path is the segment after /<locale>/air-quality/ in an IQAir URL — country/state/city.

How it works (reverse engineering)

IQAir is a React Router v7 (Remix) app on Vercel. Every air-quality page exposes its loader payload at the same URL with a .data suffix:

GET /id/air-quality/indonesia/jakarta/jakarta.data?_routes=routes%2F%24(locale).air-quality.%24

The response is turbo-stream encoded (an index-referenced pool with deferred promise chunks), decoded by turbo_stream.py.

Anti-bot: the Vercel Security Checkpoint

The site is guarded by Vercel's checkpoint. During reverse engineering we found:

  • Plain requests / httpxHTTP 429 (challenge page).

  • curl_cffi with Chrome TLS impersonation → still 429 (JS/WASM challenge is required, not just a matching TLS fingerprint).

  • Even a valid _vcrcs cookie replayed from a non-browser client → 429 (TLS/JA3 fingerprint is validated).

  • Headless Chromium → checkpoint never clears (headless is detected).

  • Headful Chromium → clears in ~3 s.

So the client (iqair_client.py) drives a headful Chromium with a persistent profile: it solves the checkpoint once, caches the _vcrcs cookie in the profile, and issues the .data fetch from inside the page context so the browser's real TLS stack + solved cookie are used. The window is parked off-screen so it doesn't disturb you.

Setup

cd iqair-mcp
pip install -r requirements.txt
python -m playwright install chromium

A desktop session / display is required (the browser must run headful).

Run

python server.py                    # stdio (for MCP clients)
python server.py --transport sse    # SSE on http://localhost:8000

Register with an MCP client

{
  "mcpServers": {
    "iqair": {
      "command": "python",
      "args": ["C:\\path-to-mcp\\iqair-mcp\\server.py"]
    }
  }
}

Files

  • server.py — FastMCP server exposing the tools.

  • iqair_client.py — browser-backed client (challenge solving + fetch + normalize).

  • turbo_stream.py — decoder for React Router's turbo-stream .data format.

  • requirements.txt — dependencies.

Staying alive across RDP disconnects

The checkpoint forces a headful browser, and an off-screen headful Chromium can lose its rendering surface (and die) when an RDP session disconnects or locks. The server survives this on two levels:

  1. Auto-recovery — if a call hits a "target/browser closed" error, the client tears down the dead browser and relaunches once, transparently.

  2. Watchdog heartbeat — a background thread pings the browser every keepalive_seconds (default 60 s); if it's dead/unresponsive it rebuilds and re-solves the challenge proactively, so a disconnect never leaves a dead browser waiting for the next tool call. Warm calls after a revive return in ~1–2 s with no re-solve.

Additionally, the screensaver/auto-lock was disabled for the current user (HKCU\Control Panel\DesktopScreenSaveActive=0, ScreenSaveTimeOut=0) so a connected session doesn't lock itself out from under the browser. This is per-user and reversible.

Fully headless-of-console setups (keeping a live desktop with nobody connected) require admin rights — either a machine policy MaxDisconnectionTime=0 under HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services, or a tscon-to-console scheduled task. Those aren't applied here (no elevation on this domain account); the watchdog + auto-recovery cover the disconnect case without them.

Notes & limitations

  • First call per session pays a one-time ~3 s browser launch + challenge solve; subsequent calls reuse the warm session.

  • A connected desktop session is still recommended; the watchdog handles brief disconnects/locks by rebuilding, but the machine must have a session to render a headful browser at all.

  • Data is whatever IQAir currently publishes (values update in real time).

  • This relies on IQAir's internal (undocumented) data endpoint; site changes may require updating the route id or decoder.

  • For personal/educational use — respect IQAir's terms of service.

-
license - not tested
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Air Quality MCP — wraps air-quality-api.open-meteo.com (free, no auth)

  • EPA AirNow MCP — official US real-time AQI + forecast (free key)

  • WAQI MCP — World Air Quality Index (free key)

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Nanparam/iqair-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server