Skip to main content
Glama

Server Details

Find air-quality stations and read pollutant observations from government monitors via OpenAQ v3.

Glama couldn't complete the latest health check. If this server requires authentication, missing or expired test credentials may be the cause. A test profile lets Glama authenticate for health checks and discover tools; it is separate from your personal connections.

If you are the author, claim ownership, then add or update a test profile under Admin → Test Profile.

Status
Unhealthy
Uptime
73.7% over 62 days
Last Tested
Transport
Streamable HTTP
URL
Repository
cyanheads/openaq-mcp-server
GitHub Stars
2
Server Listing
@cyanheads/openaq-mcp-server

TDQS

A4.5/5.0

Scored across 7 tools

Disambiguation5/5

Each tool targets a distinct concern: catalog lookups, station search, current readings, historical measurements, and SQL over staged data. Even the get_readings/get_measurements pair is clearly separated by current vs. historical scope. No two tools are likely to be confused.

Naming Consistency4/5

Most tools follow a clear openaq_verb_noun pattern (openaq_find_locations, openaq_get_measurements, openaq_list_parameters). The two dataframe tools reverse this to openaq_dataframe_describe/query, creating a minor but noticeable inconsistency.

Tool Count5/5

Seven tools is well-scoped for an air-quality data access server. Each tool serves a necessary step in the workflow: discover catalogs, find stations, fetch current or historical data, and analyze large result sets via SQL.

Completeness5/5

The surface covers the full read-only data lifecycle: parameter/country catalogs, station discovery, current observations, historical time series, and large-data analysis. There are no obvious dead ends or missing core operations for the domain.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updates
    • Changedopenaq_find_locations14 fields changed
      • removedOutput schema / properties / locations / items / properties / coordinates / additionalProperties
        Removed value: -false
      • addedOutput schema / properties / locations / items / properties / coordinates / anyOf
        Added value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "latitude": {
        +        "description": "Station latitude (decimal degrees)",
        +        "type": "number"
        +      },
        +      "longitude": {
        +        "description": "Station longitude (decimal degrees)",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "latitude",
        +      "longitude"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / locations / items / properties / coordinates / description
        Previous value: -"Station location"New value: +"Station location. Null when OpenAQ lists no latitude or no longitude."
      • removedOutput schema / properties / locations / items / properties / coordinates / properties
        Removed value: -{
        -  "latitude": {
        -    "description": "Station latitude (decimal degrees)",
        -    "type": "number"
        -  },
        -  "longitude": {
        -    "description": "Station longitude (decimal degrees)",
        -    "type": "number"
        -  }
        -}
      • removedOutput schema / properties / locations / items / properties / coordinates / required
        Removed value: -[
        -  "latitude",
        -  "longitude"
        -]
      • removedOutput schema / properties / locations / items / properties / coordinates / type
        Removed value: -"object"
      • removedOutput schema / properties / locations / items / properties / country / additionalProperties
        Removed value: -false
      • addedOutput schema / properties / locations / items / properties / country / anyOf
        Added value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "code": {
        +        "description": "OpenAQ country code: ISO 3166-1 alpha-2, or \"-99\" where OpenAQ lists none",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Country name",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "code",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / locations / items / properties / country / description
        Previous value: -"Country the station is in"New value: +"Country the station is in. Null when OpenAQ lists none."
      • removedOutput schema / properties / locations / items / properties / country / properties
        Removed value: -{
        -  "code": {
        -    "description": "OpenAQ country code: ISO 3166-1 alpha-2, or \"-99\" where OpenAQ lists none",
        -    "type": "string"
        -  },
        -  "name": {
        -    "description": "Country name",
        -    "type": "string"
        -  }
        -}
      • removedOutput schema / properties / locations / items / properties / country / required
        Removed value: -[
        -  "code",
        -  "name"
        -]
      • removedOutput schema / properties / locations / items / properties / country / type
        Removed value: -"object"
      • changedOutput schema / properties / locations / items / properties / provider / description
        Previous value: -"Data provider / network (e.g. \"AirNow\", \"OpenAQ LCS\")"New value: +"Data provider / network (e.g. \"AirNow\", \"OpenAQ LCS\"). Null when OpenAQ lists none."
      • changedOutput schema / properties / locations / items / properties / provider / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
    • Changedopenaq_get_measurements17 fields changed
      • changedInput schema / properties / aggregation / description
        Previous value: -"Time bucketing. \"raw\" = every reported value (often hourly at source). \"hourly\"/\"daily\" = server-side rollups with a statistical summary per bucket. Use \"daily\" for multi-month trends to keep the series small; \"raw\" for fine-grained recent analysis."New value: +"Time bucketing. \"raw\" = every reported value (often hourly at source). \"hourly\"/\"daily\" = server-side rollups with a statistical summary per bucket; an hour is labeled by the time it ends, and a day is the station's local calendar day. Use \"daily\" for multi-month trends to keep the series small; \"raw\" for fine-grained recent analysis."
      • changedInput schema / properties / datetimeFrom / description
        Previous value: -"Start of the range, inclusive. Date \"YYYY-MM-DD\" (opens at 00:00:00Z that day) or full UTC \"YYYY-MM-DDTHH:MM:SSZ\". Omit to get the most recent values."New value: +"Start of the range, inclusive. A date \"YYYY-MM-DD\" opens at local midnight of that day in the station's timezone (UTC midnight when OpenAQ lists none); a full UTC \"YYYY-MM-DDTHH:MM:SSZ\" is sent as is. Omit to start from the sensor's earliest data — the series runs oldest first, so on a long-running station an open start fills the row cap with its oldest values; set datetimeFrom to reach recent ones. effectiveRange echoes the instant sent."
      • changedInput schema / properties / datetimeTo / description
        Previous value: -"End of the range, inclusive. Date \"YYYY-MM-DD\" covers that whole day (closes at 23:59:59Z) or full UTC \"YYYY-MM-DDTHH:MM:SSZ\". Must land after datetimeFrom — the two forms mix freely, so \"2026-06-25\" to \"2026-06-25\" is a valid one-day range. Omit for \"up to now\"."New value: +"End of the range, inclusive. A date \"YYYY-MM-DD\" covers that whole station-local day, closing at the next local midnight, so a DST day spans 23 or 25 hours; a full UTC \"YYYY-MM-DDTHH:MM:SSZ\" is sent as is. Must land after datetimeFrom — the two forms mix freely, so \"2026-06-25\" to \"2026-06-25\" is a valid one-day range. Omit for \"up to now\". effectiveRange echoes the instant sent."
      • changedOutput schema / anyOf
        Previous value: -[
        -  {
        -    "not": {
        -      "required": [
        -        "error"
        -      ]
        -    },
        -    "required": [
        -      "location",
        -      "parameter",
        -      "sensorId",
        -      "aggregation",
        -      "series",
        -      "rowCount",
        -      "pulledCount",
        -      "pullComplete",
        -      "totalCount"
        -    ]
        -  },
        -  {
        -    "required": [
        -      "error"
        -    ]
        -  }
        -]New value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "location",
        +      "parameter",
        +      "sensorId",
        +      "aggregation",
        +      "series",
        +      "rowCount",
        +      "pulledCount",
        +      "pullComplete",
        +      "totalCount",
        +      "effectiveRange"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / effectiveRange
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "The range sent to OpenAQ as UTC instants — date-only bounds expanded to the station's local day.",
        +  "properties": {
        +    "datetimeFrom": {
        +      "description": "Lower bound sent to OpenAQ, UTC. Null when datetimeFrom was omitted.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "datetimeTo": {
        +      "description": "Upper bound sent to OpenAQ, UTC. Null when datetimeTo was omitted.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    }
        +  },
        +  "required": [
        +    "datetimeFrom",
        +    "datetimeTo"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `location_not_found`: The locationId does not exist. `parameter_not_at_location`: No sensor at the station measures parametersId (often the wrong unit variant was chosen). `no_data_for_range`: The sensor has no measurements in the requested date range. `invalid_date_range`: The range is empty — once both bounds are expanded to full UTC timestamps, datetimeTo does not land after datetimeFrom. `canvas_not_found`: The supplied canvas_id is unknown or has expired, so the series cannot be staged onto it. `upstream_error`: OpenAQ returned 5xx or an unreadable body on every retry. `rate_limited`: OpenAQ returned 429 — the request budget for this key is exhausted. `upstream_timeout`: OpenAQ did not respond within the request timeout on every retry. `invalid_api_key`: OpenAQ returned 401 — the configured OPENAQ_API_KEY is missing, invalid, or revoked. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `location_not_found`: The locationId does not exist. `parameter_not_at_location`: No sensor at the station measures parametersId (often the wrong unit variant was chosen). `no_data_for_range`: The sensor has no measurements in the requested date range. `invalid_date_range`: The range is empty — once date-only bounds are expanded to the station's local day, datetimeTo does not land after datetimeFrom. `canvas_not_found`: The supplied canvas_id is unknown or has expired, so the series cannot be staged onto it. `upstream_error`: OpenAQ returned 5xx or an unreadable body on every retry. `rate_limited`: OpenAQ returned 429 — the request budget for this key is exhausted. `upstream_timeout`: OpenAQ did not respond within the request timeout on every retry. `invalid_api_key`: OpenAQ returned 401 — the configured OPENAQ_API_KEY is missing, invalid, or revoked. Other values are possible when a failure originates below the handler."
      • addedOutput schema / properties / gapCount
        Added value: +{
        +  "description": "Missing intervals inside an hourly or daily series — a span between buckets that do not touch, or a bucket with a null value, merged where contiguous — counted over every pulled row, not only the preview. 0 when nothing is missing; absent for raw, whose rows follow no fixed cadence.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / gaps
        Added value: +{
        +  "description": "The first 20 missing intervals, oldest first. Omitted when gapCount is 0.",
        +  "items": {
        +    "additionalProperties": false,
        +    "description": "One missing interval",
        +    "properties": {
        +      "datetimeFrom": {
        +        "description": "Start of the missing interval, UTC",
        +        "type": "string"
        +      },
        +      "datetimeTo": {
        +        "description": "End of the missing interval, UTC",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "datetimeFrom",
        +      "datetimeTo"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / location / properties / provider
        Added value: +{
        +  "description": "Network that operates the station — cite it alongside OpenAQ. Null when OpenAQ lists none.",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / location / properties / providerId
        Added value: +{
        +  "description": "Provider id, usable as providersId in openaq_find_locations. Null when OpenAQ lists none.",
        +  "type": [
        +    "number",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / location / properties / timezone
        Added value: +{
        +  "description": "IANA timezone of the station (e.g. \"America/Los_Angeles\"). Daily buckets and date-only bounds follow its calendar days. Null when OpenAQ lists none.",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / location / required
        Previous value: -[
        -  "id",
        -  "name"
        -]New value: +[
        +  "id",
        +  "name",
        +  "provider",
        +  "providerId",
        +  "timezone"
        +]
      • changedOutput schema / properties / notice / description
        Previous value: -"What limited this response or where the rest of it lives — the row cap, a failed page, DataCanvas being unavailable, or the canvas table the series was staged on and the tools that read it."New value: +"What limited this response or where the rest of it lives — the row cap, a failed page, a station with no timezone, an edge bucket clipped by the range, missing intervals, DataCanvas being unavailable, or the canvas table the series was staged on and the tools that read it."
      • changedOutput schema / properties / pullComplete / description
        Previous value: -"True when the pager reached the end of the requested range, so pulledCount is the whole series for it. False when the 5000-row cap or a failed page stopped the pull early — the rows past that point are in neither this response nor the canvas table, and the notice says how to reach them."New value: +"True when pulledCount is the whole series for the requested range. False when the 5000-row cap or a failed page stopped the pull early — the rows past that point are in neither this response nor the canvas table, and the notice says how to reach them."
      • changedOutput schema / properties / pulledCount / description
        Previous value: -"Rows pulled from OpenAQ — the canvas table's row count when canvasId is present. Equals rowCount when the whole series fit inline; larger when series is a preview."New value: +"Rows pulled from OpenAQ, at most 5000 — the canvas table's row count when canvasId is present. Equals rowCount when the whole series fit inline; larger when series is a preview."
      • changedOutput schema / properties / series / description
        Previous value: -"The (possibly previewed) series, newest or oldest first per the API. Every row here is also rendered in the text output. When truncated, this is a preview of pulledCount rows — query canvasId for the rest."New value: +"The (possibly previewed) series in the order OpenAQ returns it (oldest first). An hourly/daily series either skips a missing bucket or returns it with a null value — gapCount and gaps report both. Every row here is also rendered in the text output. When truncated, this is a preview of pulledCount rows — query canvasId for the rest."
      • changedOutput schema / properties / series / items / properties / percentComplete / description
        Previous value: -"Coverage of the bucket (0–100); low values flag gappy data"New value: +"Coverage of the bucket as OpenAQ reports it — observed readings as a percentage of expected ones. Low values flag gappy data. Usually 0–100, but it exceeds 100 when a bucket holds more readings than expected, e.g. 200 on the hour a DST fall-back repeats"
    • Changedopenaq_get_readings10 fields changed
      • removedOutput schema / properties / location / properties / coordinates / additionalProperties
        Removed value: -false
      • addedOutput schema / properties / location / properties / coordinates / anyOf
        Added value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "latitude": {
        +        "description": "Station latitude (decimal degrees)",
        +        "type": "number"
        +      },
        +      "longitude": {
        +        "description": "Station longitude (decimal degrees)",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "latitude",
        +      "longitude"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / location / properties / coordinates / description
        Previous value: -"Station coordinates"New value: +"Station coordinates. Null when OpenAQ lists no latitude or no longitude."
      • removedOutput schema / properties / location / properties / coordinates / properties
        Removed value: -{
        -  "latitude": {
        -    "description": "Station latitude (decimal degrees)",
        -    "type": "number"
        -  },
        -  "longitude": {
        -    "description": "Station longitude (decimal degrees)",
        -    "type": "number"
        -  }
        -}
      • removedOutput schema / properties / location / properties / coordinates / required
        Removed value: -[
        -  "latitude",
        -  "longitude"
        -]
      • removedOutput schema / properties / location / properties / coordinates / type
        Removed value: -"object"
      • addedOutput schema / properties / location / properties / provider
        Added value: +{
        +  "description": "Network that operates the station (e.g. \"AirNow\") — cite it alongside OpenAQ. Null when OpenAQ lists none.",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / location / properties / providerId
        Added value: +{
        +  "description": "Provider id, usable as providersId in openaq_find_locations. Null when OpenAQ lists none.",
        +  "type": [
        +    "number",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / location / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "coordinates",
        -  "timezone",
        -  "distanceMeters",
        -  "datetimeLast"
        -]New value: +[
        +  "id",
        +  "name",
        +  "coordinates",
        +  "provider",
        +  "providerId",
        +  "timezone",
        +  "distanceMeters",
        +  "datetimeLast"
        +]
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance when the station resolved but returned no recent values."New value: +"Set when coordinate resolution compared a full 1,000-station page: more stations may match, so the station returned is the nearest of the first 1,000 OpenAQ lists, not necessarily the nearest overall."
    • Changedopenaq_list_countries1 field changed
      • changedInput schema / properties / query / description
        Previous value: -"Case-insensitive filter over the country catalog by code and name. A two-letter query is treated as an exact ISO 3166-1 alpha-2 code (e.g. \"US\" → United States); longer queries match as substrings (e.g. \"united\", \"germany\"). Omit to page through the whole catalog."New value: +"Case-insensitive filter over the country catalog by code and name. A two-letter query matches an exact ISO 3166-1 alpha-2 code first (e.g. \"US\" → United States) and falls back to substrings when no code matches; longer queries match as substrings (e.g. \"united\", \"germany\"). Omit to page through the whole catalog."
  2. 5 tool updates
    • Changedopenaq_find_locations23 fields changed
      • changedInput schema / properties / bbox / description
        Previous value: -"Bounding box as \"minLon,minLat,maxLon,maxLat\" (west,south,east,north). Alternative to coordinates+radius for area sweeps. Results have no distance field (no center point)."New value: +"Bounding box as \"minLon,minLat,maxLon,maxLat\" (west,south,east,north), with minLon ≤ maxLon and minLat ≤ maxLat. Alternative to coordinates+radius for area sweeps. Results have no distance field (no center point)."
      • changedInput schema / properties / iso / description
        Previous value: -"Restrict to a country by ISO 3166-1 alpha-2 code (e.g. \"US\", \"IN\", \"DE\"). Combine with bbox/coordinates to scope, or use alone for a country-wide list. Discover coverage with openaq_list_countries."New value: +"Restrict to a country by OpenAQ country code: ISO 3166-1 alpha-2 (e.g. \"US\", \"IN\", \"DE\"; either case), or \"-99\" where OpenAQ lists a country with no ISO code. Take codes from openaq_list_countries. Combine with bbox/coordinates to scope, or use alone for a country-wide list."
      • removedInput schema / properties / iso / maxLength
        Removed value: -2
      • removedInput schema / properties / iso / minLength
        Removed value: -2
      • addedInput schema / properties / iso / pattern
        Added value: +"^(?:[A-Za-z]{2}|-99)$"
      • addedInput schema / properties / mobile
        Added value: +{
        +  "description": "Mobility filter: true returns only mobile stations, false only fixed ones. Omit for both.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / monitor
        Added value: +{
        +  "description": "Station class filter: true returns only reference-grade monitors, false only low-cost sensors. Omit for both.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / page / description
        Previous value: -"Which page of results to return (1-based). Default 1. The only way past the 100-station cap: with limit 100, page 2 returns stations 101–200. Distance ordering applies within a page, not across pages, so paging is for iso/bbox sweeps — a near-me coordinates search should stay on page 1."New value: +"Which page of results to return (1-based). Default 1. The only way past the 100-station cap: with limit 100, page 2 returns stations 101–200. Distance ordering applies within a page, not across pages, so paging is for iso/bbox sweeps — a near-me coordinates search should stay on page 1. A page past the last one fails with page_exhausted."
      • addedInput schema / properties / parametersId / exclusiveMinimum
        Added value: +0
      • removedInput schema / properties / parametersId / minimum
        Removed value: --9007199254740991
      • addedInput schema / properties / providersId
        Added value: +{
        +  "description": "Only return stations from this OpenAQ provider (data network) id — read it from a previous result's providerId (e.g. 119 = AirNow).",
        +  "exclusiveMinimum": 0,
        +  "maximum": 9007199254740991,
        +  "type": "integer"
        +}
      • removedInput schema / properties / radius / default
        Removed value: -12000
      • changedInput schema / properties / radius / description
        Previous value: -"Search radius in metres around coordinates (1–25000; the API hard-caps at 25000). Default 12000 (~12km). Only used with coordinates."New value: +"Search radius in metres around coordinates (1–25000; the API hard-caps at 25000). Default 12000 (~12km). Requires coordinates — a radius sent with only bbox or iso is rejected."
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `no_locations_found`: No monitoring stations match the given area or filters. `no_search_scope`: None of coordinates, bbox, or iso was provided. `upstream_error`: OpenAQ returned 5xx or an unreadable body on every retry. `rate_limited`: OpenAQ returned 429 — the request budget for this key is exhausted. `upstream_timeout`: OpenAQ did not respond within the request timeout on every retry. `invalid_api_key`: OpenAQ returned 401 — the configured OPENAQ_API_KEY is missing, invalid, or revoked. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `no_locations_found`: No monitoring stations match the given area or filters. `page_exhausted`: A page past the first returned no stations — the results end before it. `no_search_scope`: None of coordinates, bbox, or iso was provided. `invalid_search_scope`: coordinates and bbox were both provided, or radius was provided without coordinates. `upstream_error`: OpenAQ returned 5xx or an unreadable body on every retry. `rate_limited`: OpenAQ returned 429 — the request budget for this key is exhausted. `upstream_timeout`: OpenAQ did not respond within the request timeout on every retry. `invalid_api_key`: OpenAQ returned 401 — the configured OPENAQ_API_KEY is missing, invalid, or revoked. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / error / properties / data / properties / reason / examples
        Previous value: -[
        -  "no_locations_found",
        -  "no_search_scope",
        -  "upstream_error",
        -  "rate_limited",
        -  "upstream_timeout",
        -  "invalid_api_key"
        -]New value: +[
        +  "no_locations_found",
        +  "page_exhausted",
        +  "no_search_scope",
        +  "invalid_search_scope",
        +  "upstream_error",
        +  "rate_limited",
        +  "upstream_timeout",
        +  "invalid_api_key"
        +]
      • changedOutput schema / properties / locations / description
        Previous value: -"Matching stations. Empty array means no monitoring coverage for the query — NOT clean air. Widen the radius, try openaq_list_countries, or use the modeled open-meteo air-quality tool."New value: +"Matching stations on this page, never empty: a query with no match fails with no_locations_found (no monitoring coverage, NOT clean air), and a page past the last with page_exhausted."
      • changedOutput schema / properties / locations / items / properties / country / properties / code / description
        Previous value: -"ISO 3166-1 alpha-2 country code"New value: +"OpenAQ country code: ISO 3166-1 alpha-2, or \"-99\" where OpenAQ lists none"
      • addedOutput schema / properties / locations / items / properties / providerId
        Added value: +{
        +  "description": "OpenAQ provider id — pass as providersId to restrict a search to this network. Null when OpenAQ lists no provider.",
        +  "type": [
        +    "number",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / locations / items / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "locality",
        -  "country",
        -  "coordinates",
        -  "distanceMeters",
        -  "provider",
        -  "isMonitor",
        -  "isMobile",
        -  "parameters",
        -  "datetimeLast",
        -  "datetimeFirst"
        -]New value: +[
        +  "id",
        +  "name",
        +  "locality",
        +  "country",
        +  "coordinates",
        +  "distanceMeters",
        +  "provider",
        +  "providerId",
        +  "isMonitor",
        +  "isMobile",
        +  "parameters",
        +  "datetimeLast",
        +  "datetimeFirst"
        +]
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance when OpenAQ reports a lower-bound total without the result set hitting the limit."New value: +"Guidance on a full page: the next page to request, or how to narrow the search."
      • changedOutput schema / properties / totalCount / description
        Previous value: -"Total matching stations before the limit. A floor (not an exact count) when totalCountIsLowerBound is true."New value: +"Stations counted through this page: (page − 1) × limit plus the stations returned. Exact on a page that came back short of the limit (the last page); a floor when totalCountIsLowerBound is true."
      • changedOutput schema / properties / totalCountIsLowerBound / description
        Previous value: -"True when OpenAQ reported a lower bound (\">N\"): totalCount is a floor and more stations match than the count shown."New value: +"True when this page came back full: at least totalCount stations match, and the next page may hold more."
      • changedOutput schema / properties / truncated / description
        Previous value: -"True when the station list was capped at the limit."New value: +"True when this page came back full (the limit was reached), so the next page may hold more stations."
    • Changedopenaq_get_measurements4 fields changed
      • addedInput schema / properties / locationId / exclusiveMinimum
        Added value: +0
      • removedInput schema / properties / locationId / minimum
        Removed value: --9007199254740991
      • addedInput schema / properties / parametersId / exclusiveMinimum
        Added value: +0
      • removedInput schema / properties / parametersId / minimum
        Removed value: --9007199254740991
    • Changedopenaq_get_readings4 fields changed
      • addedInput schema / properties / locationId / exclusiveMinimum
        Added value: +0
      • removedInput schema / properties / locationId / minimum
        Removed value: --9007199254740991
      • addedInput schema / properties / parametersId / exclusiveMinimum
        Added value: +0
      • removedInput schema / properties / parametersId / minimum
        Removed value: --9007199254740991
    • Changedopenaq_list_countries11 fields changed
      • addedInput schema / properties / limit
        Added value: +{
        +  "default": 20,
        +  "description": "Max countries to return (1–100). Default 20. Applied after query and parametersId, in OpenAQ catalog order.",
        +  "maximum": 100,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / page
        Added value: +{
        +  "default": 1,
        +  "description": "Which page of the filtered list to return (1-based). Default 1. With limit 20, page 2 returns countries 21–40. A page past the last one returns no countries and a notice naming the last page.",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / parametersId / exclusiveMinimum
        Added value: +0
      • removedInput schema / properties / parametersId / minimum
        Removed value: --9007199254740991
      • changedInput schema / properties / query / description
        Previous value: -"Case-insensitive filter over the bounded country catalog (~153) by code and name. A two-letter query is treated as an exact ISO 3166-1 alpha-2 code (e.g. \"US\" → United States); longer queries match as substrings (e.g. \"united\", \"germany\"). Omit to list all."New value: +"Case-insensitive filter over the country catalog by code and name. A two-letter query is treated as an exact ISO 3166-1 alpha-2 code (e.g. \"US\" → United States); longer queries match as substrings (e.g. \"united\", \"germany\"). Omit to page through the whole catalog."
      • addedOutput schema / properties / cap
        Added value: +{
        +  "description": "The limit that was applied.",
        +  "type": "number"
        +}
      • changedOutput schema / properties / countries / items / properties / code / description
        Previous value: -"ISO 3166-1 alpha-2 code — pass as iso to openaq_find_locations"New value: +"OpenAQ country code: ISO 3166-1 alpha-2, or \"-99\" where OpenAQ has none — pass as iso to openaq_find_locations"
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance when the query matched nothing."New value: +"Guidance when the filters matched nothing, when more pages follow (the next page to request), or when the page is past the last one."
      • addedOutput schema / properties / shown
        Added value: +{
        +  "description": "Number of countries returned on this page.",
        +  "type": "number"
        +}
      • changedOutput schema / properties / totalCount / description
        Previous value: -"Total countries matched after filtering."New value: +"Countries matched after query and parametersId, across every page."
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "description": "True when more matching countries follow on later pages.",
        +  "type": "boolean"
        +}
    • Changedopenaq_list_parameters1 field changed
      • changedInput schema / properties / query / description
        Previous value: -"Case-insensitive filter over the bounded parameter catalog (~44) by code, display name, and description (e.g. \"pm\" for particulates, \"ozone\", \"co\"). Omit to list everything."New value: +"Case-insensitive filter over the bounded parameter catalog by code, display name, and description (e.g. \"pm\" for particulates, \"ozone\", \"co\"). Omit to list everything."
  3. 3 tool updates
    • Changedopenaq_dataframe_describe1 field changed
      • changedInput schema / properties / canvas_id / description
        Previous value: -"DataCanvas id returned by openaq_get_measurements when a series spilled."New value: +"DataCanvas id returned by openaq_get_measurements — minted when a series overflowed the inline preview, or the canvas_id you passed it."
    • Changedopenaq_dataframe_query5 fields changed
      • changedInput schema / properties / canvas_id / description
        Previous value: -"DataCanvas id returned by openaq_get_measurements when a series spilled."New value: +"DataCanvas id returned by openaq_get_measurements — minted when a series overflowed the inline preview, or the canvas_id you passed it."
      • addedOutput schema / properties / notice
        Added value: +{
        +  "description": "How to reach the rest of the result when the row cap cut it short.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / rowCount / description
        Previous value: -"Full result count before the row cap."New value: +"Rows returned in this response, always equal to rows.length. It is the cap (200) when truncated is set, not the size of the full result."
      • changedOutput schema / properties / rows / description
        Previous value: -"Result rows (capped at the canvas row limit)."New value: +"Result rows, at most 200. Every row here is also rendered in the text output — the two surfaces carry the same set."
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "description": "True when the query matched more than 200 rows and the response was cut to the cap. Absent when the whole result fit. Page through the rest with ORDER BY plus LIMIT/OFFSET in your own SQL.",
        +  "type": "boolean"
        +}
    • Changedopenaq_get_measurements12 fields changed
      • changedInput schema / properties / canvas_id / description
        Previous value: -"DataCanvas id from a prior openaq_get_measurements call, to reuse the same canvas (e.g. to compare two stations' series side by side). Omit to start fresh; the response returns a new canvas_id when the series spills."New value: +"DataCanvas id from a prior openaq_get_measurements call, to put this series on the same canvas (e.g. to compare two stations' series side by side). Supplying it stages the series whatever its size. Reuse stages one table per sensor, so a second sensor adds a table while the same sensor overwrites its earlier series — the response says so when that happens. Omit to start fresh; the response returns a new canvas_id when the series overflows the inline preview."
      • changedInput schema / properties / limit / description
        Previous value: -"Max rows per page from the API (1–1000). Default 1000. The tool pages internally up to the spill threshold."New value: +"Max rows per page from the API (1–1000). Default 1000. The tool pages internally up to the 5000-row pull ceiling."
      • changedOutput schema / anyOf
        Previous value: -[
        -  {
        -    "not": {
        -      "required": [
        -        "error"
        -      ]
        -    },
        -    "required": [
        -      "location",
        -      "parameter",
        -      "sensorId",
        -      "aggregation",
        -      "series",
        -      "rowCount",
        -      "totalCount"
        -    ]
        -  },
        -  {
        -    "required": [
        -      "error"
        -    ]
        -  }
        -]New value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "location",
        +      "parameter",
        +      "sensorId",
        +      "aggregation",
        +      "series",
        +      "rowCount",
        +      "pulledCount",
        +      "pullComplete",
        +      "totalCount"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • changedOutput schema / properties / canvasId / description
        Previous value: -"DataCanvas id holding the pulled series. Query with openaq_dataframe_query. The pull stops at 5000 rows, so this is the whole series only when totalCount is at or below that — read the notice, which says so when the cap or a failed page cut the pull short."New value: +"DataCanvas id holding the staged series — pulledCount rows of it. Call openaq_dataframe_describe on this id for the table's columns, then openaq_dataframe_query to run SQL. Present whenever staging succeeded, which includes a series that fit inline on a canvas_id you supplied."
      • changedOutput schema / properties / notice / description
        Previous value: -"What limited this response, when something did — the row cap, a failed page, or DataCanvas being unavailable — plus how to reach the rest."New value: +"What limited this response or where the rest of it lives — the row cap, a failed page, DataCanvas being unavailable, or the canvas table the series was staged on and the tools that read it."
      • addedOutput schema / properties / pullComplete
        Added value: +{
        +  "description": "True when the pager reached the end of the requested range, so pulledCount is the whole series for it. False when the 5000-row cap or a failed page stopped the pull early — the rows past that point are in neither this response nor the canvas table, and the notice says how to reach them.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / pulledCount
        Added value: +{
        +  "description": "Rows pulled from OpenAQ — the canvas table's row count when canvasId is present. Equals rowCount when the whole series fit inline; larger when series is a preview.",
        +  "type": "number"
        +}
      • changedOutput schema / properties / series / description
        Previous value: -"The (possibly previewed) series, newest or oldest first per the API. When truncated, this is a preview — query canvasId for the rows staged there."New value: +"The (possibly previewed) series, newest or oldest first per the API. Every row here is also rendered in the text output. When truncated, this is a preview of pulledCount rows — query canvasId for the rest."
      • changedOutput schema / properties / tableName / description
        Previous value: -"Canvas table name for the staged series (e.g. \"measurements_1701\"). Reference it in SQL."New value: +"Canvas table holding the staged series (e.g. \"measurements_1701\"). openaq_dataframe_describe lists its columns; reference this name in openaq_dataframe_query SQL. One table per sensor, so re-staging the same sensor on this canvas overwrites it."
      • changedOutput schema / properties / totalCount / description
        Previous value: -"Total rows in the full series."New value: +"Rows in the full series for this range. A floor rather than an exact count when totalCountIsLowerBound is set; never below pulledCount."
      • addedOutput schema / properties / totalCountIsLowerBound
        Added value: +{
        +  "description": "Set when totalCount is only a floor: the pull stopped early and OpenAQ reported the range total as \">N\" instead of an exact number, so more rows exist than totalCount states. Absent when the count is exact.",
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / truncated / description
        Previous value: -"True when the series exceeded the inline limit, so series is a preview and the pulled rows were staged on canvasId. Absent/false when everything fit inline. It says nothing about whether the pull itself was complete — compare rowCount and totalCount, and read the notice."New value: +"True when the series exceeded the inline limit, so series is a preview of the pulled rows. Absent/false when every pulled row is inline. It describes the preview only — canvasId reports whether the rows were staged, and pullComplete whether the pull itself finished."
  4. 7 tool updates
    • Changedopenaq_dataframe_describe1 field changed
      • addedInput schema / properties / canvas_id / pattern
        Added value: +"^[A-Za-z0-9_-]{10}$"
    • Changedopenaq_dataframe_query1 field changed
      • addedInput schema / properties / canvas_id / pattern
        Added value: +"^[A-Za-z0-9_-]{10}$"
    • Changedopenaq_find_locations6 fields changed
      • removedOutput schema / properties / locations / items / properties / distanceMeters / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / locations / items / properties / distanceMeters / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / locations / items / properties / locality / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / locations / items / properties / locality / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / locations / items / properties / parameters / items / properties / displayName / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / locations / items / properties / parameters / items / properties / displayName / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changedopenaq_get_measurements9 fields changed
      • changedInput schema / properties / canvas_id / description
        Previous value: -"DataCanvas id from a prior call to reuse the same canvas (e.g. to compare two stations' series side by side). Omit to start fresh; the response returns a new canvas_id when the series spills."New value: +"DataCanvas id from a prior openaq_get_measurements call, to reuse the same canvas (e.g. to compare two stations' series side by side). Omit to start fresh; the response returns a new canvas_id when the series spills."
      • addedInput schema / properties / canvas_id / pattern
        Added value: +"^[A-Za-z0-9_-]{10}$"
      • removedOutput schema / properties / parameter / properties / displayName / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / parameter / properties / displayName / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / series / items / properties / percentComplete / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / series / items / properties / percentComplete / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • changedOutput schema / properties / series / items / properties / summary / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "avg": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Mean reading in the bucket"
        -      },
        -      "max": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Maximum reading in the bucket"
        -      },
        -      "median": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Median reading in the bucket"
        -      },
        -      "min": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Minimum reading in the bucket"
        -      },
        -      "sd": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Standard deviation — null when only one reading in the bucket"
        -      }
        -    },
        -    "required": [
        -      "min",
        -      "median",
        -      "max",
        -      "avg",
        -      "sd"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "avg": {
        +        "description": "Mean reading in the bucket",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "max": {
        +        "description": "Maximum reading in the bucket",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "median": {
        +        "description": "Median reading in the bucket",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "min": {
        +        "description": "Minimum reading in the bucket",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "sd": {
        +        "description": "Standard deviation — null when only one reading in the bucket",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      }
        +    },
        +    "required": [
        +      "min",
        +      "median",
        +      "max",
        +      "avg",
        +      "sd"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / properties / series / items / properties / value / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / series / items / properties / value / type
        Added value: +[
        +  "number",
        +  "null"
        +]
    • Changedopenaq_get_readings6 fields changed
      • removedOutput schema / properties / location / properties / distanceMeters / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / location / properties / distanceMeters / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / location / properties / timezone / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / location / properties / timezone / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / readings / items / properties / parameter / properties / displayName / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / readings / items / properties / parameter / properties / displayName / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changedopenaq_list_countries4 fields changed
      • removedOutput schema / properties / countries / items / properties / datetimeFirst / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / countries / items / properties / datetimeFirst / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / countries / items / properties / datetimeLast / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / countries / items / properties / datetimeLast / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changedopenaq_list_parameters4 fields changed
      • removedOutput schema / properties / parameters / items / properties / description / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / parameters / items / properties / description / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / parameters / items / properties / displayName / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / parameters / items / properties / displayName / type
        Added value: +[
        +  "string",
        +  "null"
        +]
  5. 7 tool updates
    • Changedopenaq_dataframe_describe6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "tables"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: DataCanvas is not enabled (CANVAS_PROVIDER_TYPE is not duckdb). `canvas_not_found`: The canvas_id is unknown or its canvas has expired. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "canvas_unavailable",
        +            "canvas_not_found"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "tables"
        -]
    • Changedopenaq_dataframe_query6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "rows",
        +      "rowCount"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `canvas_unavailable`: DataCanvas is not enabled (CANVAS_PROVIDER_TYPE is not duckdb). `canvas_not_found`: The canvas_id is unknown or its canvas has expired. `missing_table`: The SQL references a table that is not staged on this canvas (dropped, expired, or misspelled). Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "canvas_unavailable",
        +            "canvas_not_found",
        +            "missing_table"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "rows",
        -  "rowCount"
        -]
    • Changedopenaq_find_locations6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "locations",
        +      "totalCount"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `no_locations_found`: No monitoring stations match the given area or filters. `no_search_scope`: None of coordinates, bbox, or iso was provided. `upstream_error`: OpenAQ returned 5xx or an unreadable body on every retry. `rate_limited`: OpenAQ returned 429 — the request budget for this key is exhausted. `upstream_timeout`: OpenAQ did not respond within the request timeout on every retry. `invalid_api_key`: OpenAQ returned 401 — the configured OPENAQ_API_KEY is missing, invalid, or revoked. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "no_locations_found",
        +            "no_search_scope",
        +            "upstream_error",
        +            "rate_limited",
        +            "upstream_timeout",
        +            "invalid_api_key"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "locations",
        -  "totalCount"
        -]
    • Changedopenaq_get_measurements6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "location",
        +      "parameter",
        +      "sensorId",
        +      "aggregation",
        +      "series",
        +      "rowCount",
        +      "totalCount"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `location_not_found`: The locationId does not exist. `parameter_not_at_location`: No sensor at the station measures parametersId (often the wrong unit variant was chosen). `no_data_for_range`: The sensor has no measurements in the requested date range. `invalid_date_range`: The range is empty — once both bounds are expanded to full UTC timestamps, datetimeTo does not land after datetimeFrom. `canvas_not_found`: The supplied canvas_id is unknown or has expired, so the series cannot be staged onto it. `upstream_error`: OpenAQ returned 5xx or an unreadable body on every retry. `rate_limited`: OpenAQ returned 429 — the request budget for this key is exhausted. `upstream_timeout`: OpenAQ did not respond within the request timeout on every retry. `invalid_api_key`: OpenAQ returned 401 — the configured OPENAQ_API_KEY is missing, invalid, or revoked. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "location_not_found",
        +            "parameter_not_at_location",
        +            "no_data_for_range",
        +            "invalid_date_range",
        +            "canvas_not_found",
        +            "upstream_error",
        +            "rate_limited",
        +            "upstream_timeout",
        +            "invalid_api_key"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "location",
        -  "parameter",
        -  "sensorId",
        -  "aggregation",
        -  "series",
        -  "rowCount",
        -  "totalCount"
        -]
    • Changedopenaq_get_readings6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "location",
        +      "readings"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `location_not_found`: The locationId does not exist (API returns {\"detail\":\"Location not found\"}). `parameter_not_at_location`: No sensor at the resolved station measures parametersId (often the wrong unit variant was chosen). `no_station_near_coordinates`: The 25km auto-resolution sweep found no station measuring the requested parametersId. `no_recent_values`: The station has the requested sensors but its latest feed carried no values for them. `invalid_location_scope`: Both locationId and coordinates were provided, or neither was. `missing_coordinates_parameter`: coordinates was provided without parametersId. `upstream_error`: OpenAQ returned 5xx or an unreadable body on every retry. `rate_limited`: OpenAQ returned 429 — the request budget for this key is exhausted. `upstream_timeout`: OpenAQ did not respond within the request timeout on every retry. `invalid_api_key`: OpenAQ returned 401 — the configured OPENAQ_API_KEY is missing, invalid, or revoked. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "location_not_found",
        +            "parameter_not_at_location",
        +            "no_station_near_coordinates",
        +            "no_recent_values",
        +            "invalid_location_scope",
        +            "missing_coordinates_parameter",
        +            "upstream_error",
        +            "rate_limited",
        +            "upstream_timeout",
        +            "invalid_api_key"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "location",
        -  "readings"
        -]
    • Changedopenaq_list_countries6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "countries",
        +      "totalCount"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `upstream_error`: OpenAQ /countries returned 5xx or an unreadable body on every retry. `rate_limited`: OpenAQ returned 429 — the request budget for this key is exhausted. `upstream_timeout`: OpenAQ /countries did not respond within the request timeout on every retry. `invalid_api_key`: OpenAQ returned 401 — the configured OPENAQ_API_KEY is missing, invalid, or revoked. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "upstream_error",
        +            "rate_limited",
        +            "upstream_timeout",
        +            "invalid_api_key"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "countries",
        -  "totalCount"
        -]
    • Changedopenaq_list_parameters6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "parameters",
        +      "totalCount"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `upstream_error`: OpenAQ /parameters returned 5xx or an unreadable body on every retry. `rate_limited`: OpenAQ returned 429 — the request budget for this key is exhausted. `upstream_timeout`: OpenAQ /parameters did not respond within the request timeout on every retry. `invalid_api_key`: OpenAQ returned 401 — the configured OPENAQ_API_KEY is missing, invalid, or revoked. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "upstream_error",
        +            "rate_limited",
        +            "upstream_timeout",
        +            "invalid_api_key"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "parameters",
        -  "totalCount"
        -]
  6. 1 tool update
    • Changedopenaq_get_measurements11 fields changed
      • changedInput schema / properties / datetimeFrom / description
        Previous value: -"Start of the range, inclusive. Date \"YYYY-MM-DD\" or full UTC \"YYYY-MM-DDTHH:MM:SSZ\". Omit to get the most recent values."New value: +"Start of the range, inclusive. Date \"YYYY-MM-DD\" (opens at 00:00:00Z that day) or full UTC \"YYYY-MM-DDTHH:MM:SSZ\". Omit to get the most recent values."
      • changedInput schema / properties / datetimeTo / description
        Previous value: -"End of the range, inclusive. Must be on or after datetimeFrom. Omit for \"up to now\"."New value: +"End of the range, inclusive. Date \"YYYY-MM-DD\" covers that whole day (closes at 23:59:59Z) or full UTC \"YYYY-MM-DDTHH:MM:SSZ\". Must land after datetimeFrom — the two forms mix freely, so \"2026-06-25\" to \"2026-06-25\" is a valid one-day range. Omit for \"up to now\"."
      • changedOutput schema / properties / canvasId / description
        Previous value: -"DataCanvas id holding the full series. Query with openaq_dataframe_query."New value: +"DataCanvas id holding the pulled series. Query with openaq_dataframe_query. The pull stops at 5000 rows, so this is the whole series only when totalCount is at or below that — read the notice, which says so when the cap or a failed page cut the pull short."
      • changedOutput schema / properties / notice / description
        Previous value: -"Degraded-mode hint when the series was truncated but DataCanvas is unavailable."New value: +"What limited this response, when something did — the row cap, a failed page, or DataCanvas being unavailable — plus how to reach the rest."
      • changedOutput schema / properties / series / description
        Previous value: -"The (possibly previewed) series, newest or oldest first per the API. When truncated, this is a preview — query canvasId for the full set."New value: +"The (possibly previewed) series, newest or oldest first per the API. When truncated, this is a preview — query canvasId for the rows staged there."
      • changedOutput schema / properties / series / items / properties / summary / description
        Previous value: -"Per-bucket statistics — present for hourly/daily, null for raw"New value: +"Per-bucket statistics — present for hourly/daily, null for raw. Every field is null in a gap bucket"
      • addedOutput schema / properties / series / items / properties / value / anyOf
        Added value: +[
        +  {
        +    "type": "number"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / series / items / properties / value / description
        Previous value: -"Value for the bucket (the measurement for raw; the bucket aggregate for hourly/daily)"New value: +"Value for the bucket (the measurement for raw; the bucket aggregate for hourly/daily). Null for a gap bucket the sensor reported nothing into — the bucket is kept so the series stays evenly spaced on the time axis"
      • removedOutput schema / properties / series / items / properties / value / type
        Removed value: -"number"
      • changedOutput schema / properties / tableName / description
        Previous value: -"Canvas table name for the full series (e.g. \"measurements_1701\"). Reference it in SQL."New value: +"Canvas table name for the staged series (e.g. \"measurements_1701\"). Reference it in SQL."
      • changedOutput schema / properties / truncated / description
        Previous value: -"True when the series exceeded the inline limit and the full set was staged on canvasId. Absent/false when everything fit inline."New value: +"True when the series exceeded the inline limit, so series is a preview and the pulled rows were staged on canvasId. Absent/false when everything fit inline. It says nothing about whether the pull itself was complete — compare rowCount and totalCount, and read the notice."
  7. 2 tool updates
    • Changedopenaq_find_locations1 field changed
      • addedInput schema / properties / page
        Added value: +{
        +  "default": 1,
        +  "description": "Which page of results to return (1-based). Default 1. The only way past the 100-station cap: with limit 100, page 2 returns stations 101–200. Distance ordering applies within a page, not across pages, so paging is for iso/bbox sweeps — a near-me coordinates search should stay on page 1.",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
    • Changedopenaq_list_countries1 field changed
      • addedInput schema / properties / parametersId
        Added value: +{
        +  "description": "Only return countries that measure this parameter id somewhere (e.g. 2 = PM2.5 µg/m³) — the one-call answer to \"which countries have NO2 monitoring?\". Get ids from openaq_list_parameters; the same pollutant has several ids for different units. Composes with query.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
  8. 3 tool updates
    • Changedopenaq_find_locations3 fields changed
      • addedOutput schema / properties / notice
        Added value: +{
        +  "description": "Guidance when OpenAQ reports a lower-bound total without the result set hitting the limit.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / totalCount / description
        Previous value: -"Total matching stations before the limit."New value: +"Total matching stations before the limit. A floor (not an exact count) when totalCountIsLowerBound is true."
      • addedOutput schema / properties / totalCountIsLowerBound
        Added value: +{
        +  "description": "True when OpenAQ reported a lower bound (\">N\"): totalCount is a floor and more stations match than the count shown.",
        +  "type": "boolean"
        +}
    • Changedopenaq_list_countries1 field changed
      • changedInput schema / properties / query / description
        Previous value: -"Local case-insensitive filter on country code and name (e.g. \"united\", \"IN\", \"germany\"). The list is bounded (~153 countries); omit to list all. Filters the fetched list on our side, not an upstream search."New value: +"Case-insensitive filter over the bounded country catalog (~153) by code and name. A two-letter query is treated as an exact ISO 3166-1 alpha-2 code (e.g. \"US\" → United States); longer queries match as substrings (e.g. \"united\", \"germany\"). Omit to list all."
    • Changedopenaq_list_parameters1 field changed
      • changedInput schema / properties / query / description
        Previous value: -"Local case-insensitive filter on code, display name, and description (e.g. \"pm\" for particulates, \"ozone\", \"co\"). The full catalog is small (~44 entries); omit to list everything. This filters the fetched list on our side — it is not an upstream search."New value: +"Case-insensitive filter over the bounded parameter catalog (~44) by code, display name, and description (e.g. \"pm\" for particulates, \"ozone\", \"co\"). Omit to list everything."
  9. 7 tool updates
    • First observedopenaq_dataframe_describe
    • First observedopenaq_dataframe_query
    • First observedopenaq_find_locations
    • First observedopenaq_get_measurements
    • First observedopenaq_get_readings
    • First observedopenaq_list_countries
    • First observedopenaq_list_parameters

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables querying global air-quality data from the OpenAQ API, including nearest-station readings, station discovery, latest pollutant values, and historical time series for sensors.
    19 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables querying EPA's Air Quality System for regulatory-grade ambient air data, including parameters, sample measurements, annual summaries, and monitor metadata.
    6 npm
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.