get-observations-by-monitoring-site-by-geographic-bounding-box
Retrieve air quality observations from monitoring sites within a specific geographic area. Specify pollutants, data format, and time range to access detailed air quality data.
Instructions
Get observations by monitoring site within a geographic bounding box.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| bbox | Yes | Geographic bounding box of the area of interest in latitude and longitude. The format is a comma separated list minX,minY,maxX,maxY. Example: 122.715607,38.181254,-120.012970,39.022646 | |
| datatype | Yes | Data type to return. Example: C | |
| enddate | No | The end date and time of the data requested. Format: UTC Date or DateTime as end of measurement period. Examples: 2014-01-02T13:00, 2014-01-02T13, or 2014-01-02 | |
| format | Yes | MIME type of the file to be returned. Example: application/json | |
| includerawconcentrations | No | When set to 1, an additional field that contains the raw concentration will be added to the output. Default is 0. | |
| monitortype | No | The type of monitor to be returned. Options include: Permanent Only (0), Mobile Only (1), Permanent and Mobile (2). Example: 0 | |
| parameters | Yes | Comma separated list of pollutant parameters short codes to return data for. Options include: ozone, pm25, pm10, co, no2, so2. Example: ozone,pm25 | |
| startdate | No | The start date and time of the data requested. Format: UTC Date or DateTime as beginning of measurement period. Examples: 2014-01-01T13:00, 2014-01-01T13, or 2014-01-01 | |
| verbose | No | When set to 1, provides additional site information including Site Name, Agency Name, AQS ID, and Full AQS ID. Default is 0. |
Implementation Reference
- The handler function for the MCP tool that calls the AirNow API helper, handles errors, and returns the result as text content.async (params) => { const result = await airnowApi.fetchObservationsByMonitoringSiteByGeographicBoundingBox( params ); if (result === null) { return { content: [ { type: "text", text: "Failed to fetch observations data from AirNow API.", }, ], isError: true, }; } return { content: [ { type: "text", text: result, }, ], }; }
- Zod schema for input parameters including bounding box, parameters, datatype, format, dates, monitor type, verbose, and raw concentrations.{ bbox: z .string() .describe( "Geographic bounding box of the area of interest in latitude and longitude. The format is a comma separated list minX,minY,maxX,maxY. Example: 122.715607,38.181254,-120.012970,39.022646" ), parameters: z .string() .describe( "Comma separated list of pollutant parameters short codes to return data for. Options include: ozone, pm25, pm10, co, no2, so2. Example: ozone,pm25" ), datatype: z .enum(["A", "C", "B"]) .describe("Data type to return. Example: C"), format: z .enum([ "text/csv", "application/json", "application/xml", "application/vnd.google-earth.kml", ]) .describe( "MIME type of the file to be returned. Example: application/json" ), startdate: z .string() .optional() .describe( "The start date and time of the data requested. Format: UTC Date or DateTime as beginning of measurement period. Examples: 2014-01-01T13:00, 2014-01-01T13, or 2014-01-01" ), enddate: z .string() .optional() .describe( "The end date and time of the data requested. Format: UTC Date or DateTime as end of measurement period. Examples: 2014-01-02T13:00, 2014-01-02T13, or 2014-01-02" ), monitortype: z .enum(["0", "1", "2"]) .optional() .describe( "The type of monitor to be returned. Options include: Permanent Only (0), Mobile Only (1), Permanent and Mobile (2). Example: 0" ), verbose: z .enum(["0", "1"]) .optional() .describe( "When set to 1, provides additional site information including Site Name, Agency Name, AQS ID, and Full AQS ID. Default is 0." ), includerawconcentrations: z .enum(["0", "1"]) .optional() .describe( "When set to 1, an additional field that contains the raw concentration will be added to the output. Default is 0." ), },
- The registration function exported from the tool file that registers the tool on the MCP server using server.tool(), including schema and handler.export const registerObservationsByBoundingBox = (server: McpServer): void => { server.tool( "get-observations-by-monitoring-site-by-geographic-bounding-box", "Get observations by monitoring site within a geographic bounding box.", { bbox: z .string() .describe( "Geographic bounding box of the area of interest in latitude and longitude. The format is a comma separated list minX,minY,maxX,maxY. Example: 122.715607,38.181254,-120.012970,39.022646" ), parameters: z .string() .describe( "Comma separated list of pollutant parameters short codes to return data for. Options include: ozone, pm25, pm10, co, no2, so2. Example: ozone,pm25" ), datatype: z .enum(["A", "C", "B"]) .describe("Data type to return. Example: C"), format: z .enum([ "text/csv", "application/json", "application/xml", "application/vnd.google-earth.kml", ]) .describe( "MIME type of the file to be returned. Example: application/json" ), startdate: z .string() .optional() .describe( "The start date and time of the data requested. Format: UTC Date or DateTime as beginning of measurement period. Examples: 2014-01-01T13:00, 2014-01-01T13, or 2014-01-01" ), enddate: z .string() .optional() .describe( "The end date and time of the data requested. Format: UTC Date or DateTime as end of measurement period. Examples: 2014-01-02T13:00, 2014-01-02T13, or 2014-01-02" ), monitortype: z .enum(["0", "1", "2"]) .optional() .describe( "The type of monitor to be returned. Options include: Permanent Only (0), Mobile Only (1), Permanent and Mobile (2). Example: 0" ), verbose: z .enum(["0", "1"]) .optional() .describe( "When set to 1, provides additional site information including Site Name, Agency Name, AQS ID, and Full AQS ID. Default is 0." ), includerawconcentrations: z .enum(["0", "1"]) .optional() .describe( "When set to 1, an additional field that contains the raw concentration will be added to the output. Default is 0." ), }, async (params) => { const result = await airnowApi.fetchObservationsByMonitoringSiteByGeographicBoundingBox( params ); if (result === null) { return { content: [ { type: "text", text: "Failed to fetch observations data from AirNow API.", }, ], isError: true, }; } return { content: [ { type: "text", text: result, }, ], }; } ); };
- src/airnow-api.ts:86-102 (helper)Core helper function that builds the query parameters for the AirNow API endpoint '/aq/data/' and fetches the observations data.export async function fetchObservationsByMonitoringSiteByGeographicBoundingBox(params: Record<string, string>): Promise<string | null> { const endpoint = 'aq/data/'; const queryParams = new URLSearchParams(); queryParams.append('bbox', params.bbox); queryParams.append('parameters', params.parameters); queryParams.append('datatype', params.datatype); queryParams.append('format', params.format); queryParams.append('verbose', params.verbose || '0'); queryParams.append('includerawconcentrations', params.includerawconcentrations || '0'); if (params.startdate && params.enddate) { queryParams.append('startdate', params.startdate); queryParams.append('enddate', params.enddate); } if (params.monitortype) queryParams.append('monitortype', params.monitortype); return airnowGet(endpoint, queryParams); }
- src/tools/index.ts:23-23 (registration)Top-level registration call in the tools index that invokes the tool's registration function on the MCP server.registerObservationsByBoundingBox(server);