@cyanheads/epa-mcp-server 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/AGENTS.md +13 -10
  2. package/CLAUDE.md +13 -10
  3. package/Dockerfile +108 -37
  4. package/README.md +67 -44
  5. package/changelog/0.3.x/0.3.3.md +34 -0
  6. package/changelog/0.4.x/0.4.0.md +35 -0
  7. package/dist/mcp-server/tools/definitions/get-air-quality.tool.d.ts +23 -9
  8. package/dist/mcp-server/tools/definitions/get-air-quality.tool.d.ts.map +1 -1
  9. package/dist/mcp-server/tools/definitions/get-air-quality.tool.js +166 -98
  10. package/dist/mcp-server/tools/definitions/get-air-quality.tool.js.map +1 -1
  11. package/dist/mcp-server/tools/definitions/get-ejscreen.tool.d.ts.map +1 -1
  12. package/dist/mcp-server/tools/definitions/get-ejscreen.tool.js +1 -1
  13. package/dist/mcp-server/tools/definitions/get-ejscreen.tool.js.map +1 -1
  14. package/dist/mcp-server/tools/definitions/get-facility.tool.d.ts.map +1 -1
  15. package/dist/mcp-server/tools/definitions/get-facility.tool.js +5 -14
  16. package/dist/mcp-server/tools/definitions/get-facility.tool.js.map +1 -1
  17. package/dist/mcp-server/tools/definitions/get-tri-releases.tool.d.ts +2 -1
  18. package/dist/mcp-server/tools/definitions/get-tri-releases.tool.d.ts.map +1 -1
  19. package/dist/mcp-server/tools/definitions/get-tri-releases.tool.js +10 -14
  20. package/dist/mcp-server/tools/definitions/get-tri-releases.tool.js.map +1 -1
  21. package/dist/mcp-server/tools/definitions/index.d.ts +51 -18
  22. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  23. package/dist/mcp-server/tools/definitions/search-facilities.tool.d.ts.map +1 -1
  24. package/dist/mcp-server/tools/definitions/search-facilities.tool.js +9 -16
  25. package/dist/mcp-server/tools/definitions/search-facilities.tool.js.map +1 -1
  26. package/dist/mcp-server/tools/definitions/search-superfund.tool.d.ts.map +1 -1
  27. package/dist/mcp-server/tools/definitions/search-superfund.tool.js +4 -14
  28. package/dist/mcp-server/tools/definitions/search-superfund.tool.js.map +1 -1
  29. package/dist/mcp-server/tools/definitions/search-tri-releases.tool.d.ts +10 -3
  30. package/dist/mcp-server/tools/definitions/search-tri-releases.tool.d.ts.map +1 -1
  31. package/dist/mcp-server/tools/definitions/search-tri-releases.tool.js +50 -10
  32. package/dist/mcp-server/tools/definitions/search-tri-releases.tool.js.map +1 -1
  33. package/dist/mcp-server/tools/definitions/search-violations.tool.d.ts.map +1 -1
  34. package/dist/mcp-server/tools/definitions/search-violations.tool.js +1 -3
  35. package/dist/mcp-server/tools/definitions/search-violations.tool.js.map +1 -1
  36. package/dist/mcp-server/tools/definitions/search-water-systems.tool.d.ts +3 -1
  37. package/dist/mcp-server/tools/definitions/search-water-systems.tool.d.ts.map +1 -1
  38. package/dist/mcp-server/tools/definitions/search-water-systems.tool.js +23 -10
  39. package/dist/mcp-server/tools/definitions/search-water-systems.tool.js.map +1 -1
  40. package/dist/mcp-server/tools/format-lbs.d.ts +14 -0
  41. package/dist/mcp-server/tools/format-lbs.d.ts.map +1 -0
  42. package/dist/mcp-server/tools/format-lbs.js +16 -0
  43. package/dist/mcp-server/tools/format-lbs.js.map +1 -0
  44. package/dist/mcp-server/tools/format-location.d.ts +18 -0
  45. package/dist/mcp-server/tools/format-location.d.ts.map +1 -0
  46. package/dist/mcp-server/tools/format-location.js +26 -0
  47. package/dist/mcp-server/tools/format-location.js.map +1 -0
  48. package/dist/mcp-server/tools/format-tri-release.d.ts +16 -0
  49. package/dist/mcp-server/tools/format-tri-release.d.ts.map +1 -0
  50. package/dist/mcp-server/tools/format-tri-release.js +23 -0
  51. package/dist/mcp-server/tools/format-tri-release.js.map +1 -0
  52. package/dist/services/airnow/airnow-service.d.ts +10 -29
  53. package/dist/services/airnow/airnow-service.d.ts.map +1 -1
  54. package/dist/services/airnow/airnow-service.js +148 -95
  55. package/dist/services/airnow/airnow-service.js.map +1 -1
  56. package/dist/services/airnow/types.d.ts +62 -23
  57. package/dist/services/airnow/types.d.ts.map +1 -1
  58. package/dist/services/airnow/types.js +2 -1
  59. package/dist/services/airnow/types.js.map +1 -1
  60. package/dist/services/dmap/dmap-service.d.ts +41 -2
  61. package/dist/services/dmap/dmap-service.d.ts.map +1 -1
  62. package/dist/services/dmap/dmap-service.js +231 -116
  63. package/dist/services/dmap/dmap-service.js.map +1 -1
  64. package/dist/services/dmap/types.d.ts +17 -4
  65. package/dist/services/dmap/types.d.ts.map +1 -1
  66. package/dist/services/echo/echo-service.d.ts.map +1 -1
  67. package/dist/services/echo/echo-service.js +8 -5
  68. package/dist/services/echo/echo-service.js.map +1 -1
  69. package/dist/services/ejscreen/ejscreen-service.js +1 -1
  70. package/dist/services/ejscreen/ejscreen-service.js.map +1 -1
  71. package/package.json +11 -10
  72. package/server.json +16 -24
@@ -0,0 +1,34 @@
1
+ ---
2
+ summary: "ECHO debug logs use endpoint labels instead of request URLs, with framework recovery and error privacy updates."
3
+ breaking: false
4
+ security: true
5
+ ---
6
+
7
+ # 0.3.3 — 2026-10-07
8
+
9
+ ## Changed
10
+
11
+ - **Domain recovery** uses the framework's declared-hint fill from 0.13.10; redundant forwards are removed and contract tests preserve hints on both MCP result surfaces.
12
+ - **Framework input and errors** adopt 0.13.9's integer-to-string repair and field-path guidance, 0.13.10's error request IDs, 0.13.12's generated IDs and URL-origin redaction, and 0.13.13's removal of framework-added `rootCause` from error envelopes.
13
+ - **Docker builds** use Bun 1.4.2 and a native build-platform dependency stage, cross-installing for amd64/arm64 with framework-range OTel peers and pruning musl-only bindings.
14
+ - **Framework tooling and guides** are synchronized; configuration documents OTLP endpoints and opt-in failed-call payload logging, packaging excludes `.mcpb`, cache, and logs, and CodeQL uploads per-language categories.
15
+ - **ECHO User-Agent** reports the current server version.
16
+
17
+ ## Fixed
18
+
19
+ - **MCP Registry npm entries** launch with `npx`, drop npm-script arguments, and fix `MCP_TRANSPORT_TYPE=http` for the HTTP entry.
20
+
21
+ ## Security
22
+
23
+ - **ECHO debug logs** identify facility and enforcement requests by fixed endpoint labels and query IDs, omitting full configured URL paths and query strings ([#26](https://github.com/cyanheads/epa-mcp-server/issues/26)).
24
+
25
+ ## Dependencies
26
+
27
+ - `@cyanheads/mcp-ts-core` ^0.13.6 → ^0.13.13.
28
+ - Dev: `@biomejs/biome` ^2.5.14 → ^2.5.15.
29
+ - Dev: `@socketsecurity/bun-security-scanner` ^1.1.2 → ^1.1.3.
30
+ - Dev: `@types/node` ^26.6.1 → ^26.6.4.
31
+ - Dev: `ignore` ^7.0.9 → ^7.0.12.
32
+ - Dev: `tsc-alias` ^1.9.5 → ^1.9.7.
33
+ - Dev: `vitest` ^5.0.1 → ^5.0.3.
34
+ - **Bun** 1.4.0 → 1.4.2 in `packageManager` and Docker base images.
@@ -0,0 +1,35 @@
1
+ ---
2
+ summary: "epa_get_air_quality moves to AirNow's 2026 web services (breaking: distance_miles removed, observation coordinates removed, aqi optional); TRI search runs as one DMAP join with a working county filter and opt-in release breakdown; water-system has_violation counts open violations; hosted endpoint at epa.caseyjhand.com."
3
+ breaking: true
4
+ security: false
5
+ agent-notes: |
6
+ Callers of epa_get_air_quality: drop `distance_miles`, stop reading `latitude`/`longitude`, treat `hourObserved` as a string and `aqi` as optional.
7
+ ---
8
+
9
+ # 0.4.0 — 2026-10-08
10
+
11
+ ## Added
12
+
13
+ - **`epa_get_air_quality`** reads `observation/current/ziplatlong/` and `forecast/current/`, returns per-site readings (`siteName`, `siteID`, `reportingAgency`), the agency `discussion`, and an `attribution` credits block ([#30](https://github.com/cyanheads/epa-mcp-server/issues/30)).
14
+ - **`epa_search_tri_releases`** takes opt-in `include_release_breakdown` for air, water, land, and underground-injection releases at the cost of one more upstream request ([#17](https://github.com/cyanheads/epa-mcp-server/issues/17)).
15
+ - **`epa_search_tri_releases`** records carry `countyName`; TRI quantities reported in grams (dioxin and dioxin-like compounds) are converted to pounds and carry `reportedUnit`.
16
+ - **Hosted endpoint** `https://epa.caseyjhand.com/mcp` is listed in `server.json` remotes and the README.
17
+
18
+ ## Changed
19
+
20
+ - **`epa_get_air_quality` (breaking)** removes the `distance_miles` input and the `latitude`/`longitude` output fields, retypes `hourObserved`, and makes `aqi` optional (category-only forecasts omit it). `forecast_date` is optional, filters the issued forecast, and is rejected in current mode.
21
+ - **`epa_search_tri_releases`** is one DMAP join instead of an unbounded facility walk ([#32](https://github.com/cyanheads/epa-mcp-server/issues/32)); the `county` filter matches `county_name` after dropping a trailing County, Parish, or Borough ([#27](https://github.com/cyanheads/epa-mcp-server/issues/27)).
22
+ - **`epa_search_water_systems`** `has_violation` keeps systems with an open violation, in chunked lookups with a scan notice, and works with `zip_code`; `zip_code` is documented as the address of record.
23
+ - **`epa_get_facility`**, **`epa_search_facilities`**, **`epa_search_superfund`** render latitude and longitude independently ([#24](https://github.com/cyanheads/epa-mcp-server/issues/24)) and pound quantities at full precision.
24
+ - **`facility_id`** guidance on `epa_get_tri_releases` points at `epa_search_tri_releases` ([#21](https://github.com/cyanheads/epa-mcp-server/issues/21)).
25
+ - **Tests** assert exact tool sets, error messages, and per-field output across the suite.
26
+
27
+ ## Fixed
28
+
29
+ - **DMAP row ranges** are 1-based and inclusive.
30
+ - **`epa_search_tri_releases`** under-limit searches no longer fail during enrichment.
31
+
32
+ ## Dependencies
33
+
34
+ - `@cyanheads/mcp-ts-core` ^0.13.13 → ^0.13.14 (framework skills synced).
35
+ - `pino-pretty` ^13.1.3 → ^13.2.0.
@@ -1,5 +1,6 @@
1
1
  /**
2
- * @fileoverview Tool for getting AQI observations or forecasts for a location from AirNow.
2
+ * @fileoverview Tool for getting current AQI observations or the issued AQI forecast for a
3
+ * location from AirNow.
3
4
  * @module mcp-server/tools/definitions/get-air-quality.tool
4
5
  */
5
6
  import { z } from '@cyanheads/mcp-ts-core';
@@ -13,34 +14,47 @@ export declare const getAirQualityTool: import("@cyanheads/mcp-ts-core").ToolDef
13
14
  forecast: "forecast";
14
15
  }>>;
15
16
  forecast_date: z.ZodOptional<z.ZodString>;
16
- distance_miles: z.ZodDefault<z.ZodNumber>;
17
17
  }, z.core.$strip>, z.ZodObject<{
18
18
  observations: z.ZodArray<z.ZodObject<{
19
19
  reportingArea: z.ZodOptional<z.ZodString>;
20
+ reportingAreaCode: z.ZodOptional<z.ZodString>;
20
21
  stateCode: z.ZodOptional<z.ZodString>;
21
- latitude: z.ZodOptional<z.ZodNumber>;
22
- longitude: z.ZodOptional<z.ZodNumber>;
23
22
  dateObserved: z.ZodOptional<z.ZodString>;
24
- hourObserved: z.ZodOptional<z.ZodNumber>;
23
+ hourObserved: z.ZodOptional<z.ZodString>;
25
24
  localTimeZone: z.ZodOptional<z.ZodString>;
25
+ discussion: z.ZodOptional<z.ZodString>;
26
26
  readings: z.ZodArray<z.ZodObject<{
27
27
  parameterName: z.ZodString;
28
- aqi: z.ZodNumber;
28
+ aqi: z.ZodOptional<z.ZodNumber>;
29
29
  categoryNumber: z.ZodOptional<z.ZodNumber>;
30
30
  categoryName: z.ZodOptional<z.ZodString>;
31
+ siteName: z.ZodOptional<z.ZodString>;
32
+ siteID: z.ZodOptional<z.ZodString>;
33
+ reportingAgency: z.ZodOptional<z.ZodString>;
34
+ dateIssue: z.ZodOptional<z.ZodString>;
35
+ dateValid: z.ZodOptional<z.ZodString>;
36
+ forecastAgency: z.ZodOptional<z.ZodString>;
37
+ actionDay: z.ZodOptional<z.ZodBoolean>;
31
38
  }, z.core.$strip>>;
32
39
  }, z.core.$strip>>;
33
40
  mode: z.ZodString;
34
41
  message: z.ZodOptional<z.ZodString>;
42
+ attribution: z.ZodString;
35
43
  }, z.core.$strip>, readonly [{
36
44
  readonly reason: "no_location";
37
45
  readonly code: JsonRpcErrorCode.ValidationError;
38
46
  readonly when: "Neither zip_code nor latitude+longitude was provided.";
39
47
  readonly recovery: "Provide either zip_code or both latitude and longitude to identify the location.";
40
48
  }, {
41
- readonly reason: "forecast_date_required";
49
+ readonly reason: "forecast_date_needs_forecast_mode";
42
50
  readonly code: JsonRpcErrorCode.ValidationError;
43
- readonly when: "Mode is \"forecast\" but forecast_date was not provided.";
44
- readonly recovery: "Provide forecast_date as YYYY-MM-DD when using mode=\"forecast\".";
51
+ readonly when: "forecast_date was set while mode is \"current\", where it has no effect.";
52
+ readonly recovery: "Set mode to \"forecast\" to filter by forecast_date, or omit forecast_date.";
53
+ }, {
54
+ readonly reason: "invalid_zip_code";
55
+ readonly code: JsonRpcErrorCode.ValidationError;
56
+ readonly when: "AirNow rejected zip_code as invalid (HTTP 400).";
57
+ readonly recovery: "Check that zip_code is a valid 5-digit US ZIP code, or pass latitude and longitude instead.";
58
+ readonly thrownBy: "service";
45
59
  }], undefined>;
46
60
  //# sourceMappingURL=get-air-quality.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-air-quality.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-air-quality.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAwO5B,CAAC"}
1
+ {"version":3,"file":"get-air-quality.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-air-quality.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AA+BjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA0R5B,CAAC"}
@@ -1,16 +1,35 @@
1
1
  /**
2
- * @fileoverview Tool for getting AQI observations or forecasts for a location from AirNow.
2
+ * @fileoverview Tool for getting current AQI observations or the issued AQI forecast for a
3
+ * location from AirNow.
3
4
  * @module mcp-server/tools/definitions/get-air-quality.tool
4
5
  */
5
6
  import { tool, z } from '@cyanheads/mcp-ts-core';
6
7
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
8
  import { getAirNowService } from '../../../services/airnow/airnow-service.js';
9
+ const AIRNOW_PROGRAM = 'the U.S. EPA AirNow program (www.airnow.gov)';
10
+ const PRELIMINARY_NOTICE = 'AirNow data are preliminary and unverified; do not use them for regulatory, trend, or enforcement decisions.';
11
+ /** Credit line naming the agencies behind the returned readings and the AirNow program. */
12
+ function attributionFor(mode, areas) {
13
+ const agencies = [
14
+ ...new Set(areas.flatMap((area) => area.readings.flatMap((r) => {
15
+ const agency = r.reportingAgency ?? r.forecastAgency;
16
+ return agency ? [agency] : [];
17
+ }))),
18
+ ];
19
+ const list = (items) => new Intl.ListFormat('en', { type: 'conjunction' }).format(items);
20
+ const credit = mode === 'current'
21
+ ? `Data courtesy of ${list([...agencies, AIRNOW_PROGRAM])}.`
22
+ : agencies.length > 0
23
+ ? `Forecasts issued by ${list(agencies)} and distributed by ${AIRNOW_PROGRAM}.`
24
+ : `Forecasts distributed by ${AIRNOW_PROGRAM}.`;
25
+ return `${credit} ${PRELIMINARY_NOTICE}`;
26
+ }
8
27
  export const getAirQualityTool = tool('epa_get_air_quality', {
9
28
  title: 'Get Air Quality Index',
10
- description: 'Get current AQI observations or forecasts for a location from the AirNow API. Returns per-pollutant AQI values (PM2.5, ozone, CO, SO2, NO2), AQI category (Good through Hazardous), reporting area name, and observation timestamp. Provide either zip_code or both latitude and longitude. Set mode to "forecast" and provide forecast_date for next-day projections. Data is preliminary — suitable for awareness and informational use, not regulatory decisions. Responses are cached for ~1 hour.',
29
+ description: "Get current AQI observations or the issued AQI forecast for a US location from the AirNow API. Provide either zip_code or both latitude and longitude. Current mode returns the latest hourly NowCast AQI for each pollutant (PM2.5, ozone, PM10) from the closest monitor within 50 miles, with the monitor site name, site ID, and reporting agency; pollutants in one reporting area can come from different monitors. Forecast mode returns every day the reporting area's agency has issued (typically one to five), each with the AQI category, an action-day flag, and the issue date, plus the agency's forecast discussion when one exists; some agencies forecast a category without an AQI number. In forecast mode, set forecast_date to keep only the forecast valid on that date; current mode rejects it. Data are preliminary — suitable for awareness, not regulatory, trend, or enforcement decisions. Responses are cached for ~1 hour.",
11
30
  annotations: { readOnlyHint: true, openWorldHint: true, idempotentHint: true },
12
31
  input: z.object({
13
- zip_code: z.string().optional().describe('5-digit ZIP code for the location'),
32
+ zip_code: z.string().optional().describe('5-digit US ZIP code for the location'),
14
33
  latitude: z
15
34
  .number()
16
35
  .optional()
@@ -22,18 +41,11 @@ export const getAirQualityTool = tool('epa_get_air_quality', {
22
41
  mode: z
23
42
  .enum(['current', 'forecast'])
24
43
  .default('current')
25
- .describe('Data mode: "current" for latest AQI observations, "forecast" for next-day projections'),
44
+ .describe('Data mode: "current" for the latest hourly observations, "forecast" for every forecast day the reporting area has issued'),
26
45
  forecast_date: z
27
46
  .string()
28
47
  .optional()
29
- .describe('Date for forecast in ISO 8601 format (YYYY-MM-DD). Required when mode is "forecast".'),
30
- distance_miles: z
31
- .number()
32
- .int()
33
- .min(0)
34
- .max(300)
35
- .default(25)
36
- .describe('Search radius in miles for finding reporting stations. Default 25 miles.'),
48
+ .describe('Forecast mode only (rejected in current mode): keep just the forecast valid on this date (YYYY-MM-DD). Omit to get every issued forecast day. When no issued day matches, the result is empty and its message lists the issued dates.'),
37
49
  }),
38
50
  output: z.object({
39
51
  observations: z
@@ -42,48 +54,91 @@ export const getAirQualityTool = tool('epa_get_air_quality', {
42
54
  reportingArea: z
43
55
  .string()
44
56
  .optional()
45
- .describe('Name of the AQI reporting area (e.g. "Seattle-Tacoma-Bellevue, WA")'),
46
- stateCode: z.string().optional().describe('2-letter state code of the reporting area'),
47
- latitude: z.number().optional().describe('Latitude of the reporting area centroid'),
48
- longitude: z.number().optional().describe('Longitude of the reporting area centroid'),
57
+ .describe('Name of the AQI reporting area (e.g. "Seattle-Bellevue-Kent Valley")'),
58
+ reportingAreaCode: z
59
+ .string()
60
+ .optional()
61
+ .describe('AirNow reporting area code (e.g. "wa004"). Forecast mode only.'),
62
+ stateCode: z
63
+ .string()
64
+ .optional()
65
+ .describe('2-letter state code of the reporting area. Forecast mode only.'),
49
66
  dateObserved: z
50
67
  .string()
51
68
  .optional()
52
- .describe('Observation or forecast date (YYYY-MM-DD)'),
69
+ .describe('Observation date (YYYY-MM-DD). Current mode only.'),
53
70
  hourObserved: z
54
- .number()
71
+ .string()
55
72
  .optional()
56
- .describe('Hour of observation (0–23) in local time. Absent for daily forecasts.'),
73
+ .describe('Local hour of the observation as "HH:00". Current mode only.'),
57
74
  localTimeZone: z
58
75
  .string()
59
76
  .optional()
60
- .describe('Local time zone abbreviation (e.g. "PST")'),
77
+ .describe('Local time zone abbreviation for hourObserved (e.g. "PDT"). Current mode only.'),
78
+ discussion: z
79
+ .string()
80
+ .optional()
81
+ .describe("The forecasting agency's discussion for this area, verbatim (may contain HTML). Forecast mode only; omitted when the agency issued none."),
61
82
  readings: z
62
83
  .array(z
63
84
  .object({
64
85
  parameterName: z
65
86
  .string()
66
- .describe('Pollutant name (e.g. "PM2.5", "Ozone", "CO")'),
67
- aqi: z.number().describe('Air Quality Index value for this pollutant'),
87
+ .describe('Pollutant name as AirNow reports it (e.g. "PM2.5", "OZONE", "PM10")'),
88
+ aqi: z
89
+ .number()
90
+ .optional()
91
+ .describe('Air Quality Index value. Omitted when the agency issued only a category (category-only forecast).'),
68
92
  categoryNumber: z
69
93
  .number()
70
94
  .optional()
71
- .describe('AQI category number: 1=Good, 2=Moderate, 3=Unhealthy for Sensitive Groups, 4=Unhealthy, 5=Very Unhealthy, 6=Hazardous'),
95
+ .describe('AQI category number: 1=Good, 2=Moderate, 3=Unhealthy for Sensitive Groups, 4=Unhealthy, 5=Very Unhealthy, 6=Hazardous. Omitted when AirNow reports an unrecognized category.'),
72
96
  categoryName: z
73
97
  .string()
74
98
  .optional()
75
99
  .describe('AQI category name (e.g. "Good", "Moderate", "Unhealthy")'),
100
+ siteName: z
101
+ .string()
102
+ .optional()
103
+ .describe('Monitor site that produced this observation. Current mode only.'),
104
+ siteID: z
105
+ .string()
106
+ .optional()
107
+ .describe('AirNow ID of the monitor site. Current mode only.'),
108
+ reportingAgency: z
109
+ .string()
110
+ .optional()
111
+ .describe('Agency that reported this observation. Current mode only.'),
112
+ dateIssue: z
113
+ .string()
114
+ .optional()
115
+ .describe('Date the forecast was issued (YYYY-MM-DD). Forecast mode only.'),
116
+ dateValid: z
117
+ .string()
118
+ .optional()
119
+ .describe('Date the forecast applies to (YYYY-MM-DD). Forecast mode only.'),
120
+ forecastAgency: z
121
+ .string()
122
+ .optional()
123
+ .describe('Agency that issued the forecast. Forecast mode only.'),
124
+ actionDay: z
125
+ .boolean()
126
+ .optional()
127
+ .describe('True when the agency declared an air quality action day for this date. Forecast mode only.'),
76
128
  })
77
- .describe('AQI reading for a single pollutant parameter'))
78
- .describe('Per-pollutant AQI readings for this reporting area and time'),
129
+ .describe('AQI reading for one pollutant (and, in forecast mode, one valid date)'))
130
+ .describe('Per-pollutant AQI readings for this reporting area'),
79
131
  })
80
- .describe('AQI observation or forecast record for a single reporting area'))
132
+ .describe('AQI readings for one reporting area — per observed hour in current mode, per area across all forecast days in forecast mode'))
81
133
  .describe('AQI observation or forecast records grouped by reporting area'),
82
134
  mode: z.string().describe('Data mode used: "current" or "forecast"'),
83
135
  message: z
84
136
  .string()
85
137
  .optional()
86
- .describe('Recovery hint when no observations are returned — suggests trying a different location or increasing distance_miles. Absent when data is returned.'),
138
+ .describe("Why the result is empty: AirNow's own explanation, the issued forecast dates when forecast_date matched none, or a coverage hint. Absent when data is returned."),
139
+ attribution: z
140
+ .string()
141
+ .describe('Credit to the reporting or forecasting agencies and the U.S. EPA AirNow program, with the preliminary-data notice. Reproduce it when passing this data on.'),
87
142
  }),
88
143
  errors: [
89
144
  {
@@ -93,102 +148,115 @@ export const getAirQualityTool = tool('epa_get_air_quality', {
93
148
  recovery: 'Provide either zip_code or both latitude and longitude to identify the location.',
94
149
  },
95
150
  {
96
- reason: 'forecast_date_required',
151
+ reason: 'forecast_date_needs_forecast_mode',
152
+ code: JsonRpcErrorCode.ValidationError,
153
+ when: 'forecast_date was set while mode is "current", where it has no effect.',
154
+ recovery: 'Set mode to "forecast" to filter by forecast_date, or omit forecast_date.',
155
+ },
156
+ {
157
+ reason: 'invalid_zip_code',
97
158
  code: JsonRpcErrorCode.ValidationError,
98
- when: 'Mode is "forecast" but forecast_date was not provided.',
99
- recovery: 'Provide forecast_date as YYYY-MM-DD when using mode="forecast".',
159
+ when: 'AirNow rejected zip_code as invalid (HTTP 400).',
160
+ recovery: 'Check that zip_code is a valid 5-digit US ZIP code, or pass latitude and longitude instead.',
161
+ thrownBy: 'service',
100
162
  },
101
163
  ],
102
164
  async handler(input, ctx) {
103
- // Resolve the location once into a discriminated shape so the service branches below
104
- // narrow without non-null assertions. Zip takes precedence over lat/lng, and the raw
105
- // (untrimmed) zip_code is forwarded to match prior behavior.
106
- const zip = input.zip_code;
107
- const loc = zip !== undefined && zip.trim() !== ''
165
+ // Zip takes precedence over lat/lng; a blank zip (form clients) falls through to lat/lng.
166
+ const zip = input.zip_code?.trim();
167
+ const location = zip
108
168
  ? { kind: 'zip', zipCode: zip }
109
169
  : input.latitude !== undefined && input.longitude !== undefined
110
170
  ? { kind: 'latlng', latitude: input.latitude, longitude: input.longitude }
111
171
  : undefined;
112
- if (!loc) {
113
- throw ctx.fail('no_location', 'Provide either zip_code or both latitude and longitude.', {
114
- ...ctx.recoveryFor('no_location'),
115
- });
172
+ if (!location) {
173
+ throw ctx.fail('no_location', 'Provide either zip_code or both latitude and longitude.');
116
174
  }
117
- // forecast mode requires a date — validate up front so the error path is unchanged.
118
- let forecastDate = '';
119
- if (input.mode === 'forecast') {
120
- if (input.forecast_date === undefined || input.forecast_date.trim() === '') {
121
- throw ctx.fail('forecast_date_required', 'forecast_date (YYYY-MM-DD) is required when mode is "forecast".', {
122
- ...ctx.recoveryFor('forecast_date_required'),
123
- });
124
- }
125
- forecastDate = input.forecast_date;
175
+ const forecastDate = input.forecast_date?.trim() || undefined;
176
+ if (forecastDate && input.mode === 'current') {
177
+ throw ctx.fail('forecast_date_needs_forecast_mode', `forecast_date "${forecastDate}" only filters forecasts; current mode returns the latest observations.`);
126
178
  }
127
179
  ctx.log.info('epa_get_air_quality', {
128
180
  mode: input.mode,
129
- zip: input.zip_code,
130
- lat: input.latitude,
181
+ location: location.kind,
182
+ forecastDate,
131
183
  });
132
184
  const service = getAirNowService();
133
- let observations;
134
- if (input.mode === 'current') {
135
- observations =
136
- loc.kind === 'zip'
137
- ? await service.getCurrentByZip({ zipCode: loc.zipCode, distanceMiles: input.distance_miles }, ctx)
138
- : await service.getCurrentByLatLng({
139
- latitude: loc.latitude,
140
- longitude: loc.longitude,
141
- distanceMiles: input.distance_miles,
142
- }, ctx);
185
+ const lookup = input.mode === 'forecast'
186
+ ? await service.getForecast(location, ctx)
187
+ : await service.getCurrent(location, ctx);
188
+ const observations = input.mode === 'forecast' && forecastDate
189
+ ? lookup.areas.flatMap((area) => {
190
+ const readings = area.readings.filter((r) => r.dateValid === forecastDate);
191
+ return readings.length > 0 ? [{ ...area, readings }] : [];
192
+ })
193
+ : lookup.areas;
194
+ ctx.log.info('epa_get_air_quality completed', { areas: observations.length });
195
+ const attribution = attributionFor(input.mode, observations);
196
+ if (observations.length > 0)
197
+ return { observations, mode: input.mode, attribution };
198
+ const where = location.kind === 'zip'
199
+ ? `zip_code="${location.zipCode}"`
200
+ : `latitude=${location.latitude}, longitude=${location.longitude}`;
201
+ let message;
202
+ if (lookup.noDataMessage !== undefined) {
203
+ message = `AirNow returned no data for ${where}: "${lookup.noDataMessage}"`;
143
204
  }
144
- else {
145
- observations =
146
- loc.kind === 'zip'
147
- ? await service.getForecastByZip({ zipCode: loc.zipCode, date: forecastDate, distanceMiles: input.distance_miles }, ctx)
148
- : await service.getForecastByLatLng({
149
- latitude: loc.latitude,
150
- longitude: loc.longitude,
151
- date: forecastDate,
152
- distanceMiles: input.distance_miles,
153
- }, ctx);
205
+ else if (lookup.areas.length > 0) {
206
+ const issued = [
207
+ ...new Set(lookup.areas.flatMap((a) => a.readings.flatMap((r) => r.dateValid ?? []))),
208
+ ].sort();
209
+ message = `No forecast valid on ${forecastDate} for ${where}. ${issued.length > 0 ? `Issued forecast dates: ${issued.join(', ')}.` : 'AirNow listed no valid dates.'} Omit forecast_date to get every issued day.`;
154
210
  }
155
- ctx.log.info('epa_get_air_quality completed', { areas: observations.length });
156
- if (observations.length === 0) {
157
- const location = loc.kind === 'zip'
158
- ? `zip_code="${input.zip_code}"`
159
- : `lat=${input.latitude}, lng=${input.longitude}`;
160
- return {
161
- observations: [],
162
- mode: input.mode,
163
- message: `No AQI data found for ${location} within ${input.distance_miles} miles. Try increasing distance_miles or check that the location is within the US.`,
164
- };
211
+ else {
212
+ message = `No AQI data found for ${where}. AirNow observations come from monitors within 50 miles and forecasts from the location's reporting area; check that the location is in the US, or try a nearby ZIP code.`;
165
213
  }
166
- return { observations, mode: input.mode };
214
+ return { observations: [], mode: input.mode, message, attribution };
167
215
  },
168
216
  format: (result) => {
169
- const lines = [];
170
- lines.push(`## Air Quality Index — ${result.mode === 'forecast' ? 'Forecast' : 'Current Observations'} (mode: ${result.mode})`);
217
+ const lines = [
218
+ `## Air Quality Index — ${result.mode === 'forecast' ? 'Forecast' : 'Current Observations'} (mode: ${result.mode})`,
219
+ ];
171
220
  if (result.message)
172
221
  lines.push(`\n> ${result.message}`);
173
- for (const obs of result.observations) {
174
- lines.push(`\n### ${obs.reportingArea ?? 'Unknown Area'}`);
175
- if (obs.stateCode)
176
- lines.push(`**State:** ${obs.stateCode}`);
177
- if (obs.dateObserved) {
178
- const timeStr = obs.hourObserved !== undefined
179
- ? ` at ${obs.hourObserved}:00 ${obs.localTimeZone ?? ''}`
222
+ for (const area of result.observations) {
223
+ lines.push(`\n### ${area.reportingArea ?? 'Unknown Area'}`);
224
+ const meta = [
225
+ area.stateCode && `**State:** ${area.stateCode}`,
226
+ area.reportingAreaCode && `**Reporting area code:** ${area.reportingAreaCode}`,
227
+ ].filter(Boolean);
228
+ if (meta.length > 0)
229
+ lines.push(meta.join(' | '));
230
+ if (area.dateObserved || area.hourObserved) {
231
+ const time = area.hourObserved
232
+ ? ` at ${area.hourObserved}${area.localTimeZone ? ` ${area.localTimeZone}` : ''}`
180
233
  : '';
181
- lines.push(`**Date:** ${obs.dateObserved}${timeStr}`);
234
+ lines.push(`**Observed:** ${area.dateObserved ?? 'date not reported'}${time}`);
182
235
  }
183
- if (obs.latitude !== undefined && obs.longitude !== undefined) {
184
- lines.push(`**Coordinates:** ${obs.latitude}, ${obs.longitude}`);
185
- }
186
- for (const reading of obs.readings) {
187
- const category = reading.categoryName ? ` (${reading.categoryName})` : '';
188
- const catNum = reading.categoryNumber !== undefined ? ` [category ${reading.categoryNumber}]` : '';
189
- lines.push(`**${reading.parameterName}:** AQI ${reading.aqi}${category}${catNum}`);
236
+ for (const r of area.readings) {
237
+ const label = r.dateValid ? `${r.dateValid} ${r.parameterName}` : r.parameterName;
238
+ const value = r.aqi !== undefined
239
+ ? `AQI ${r.aqi}${r.categoryName ? ` (${r.categoryName})` : ''}`
240
+ : (r.categoryName ?? 'Category not reported');
241
+ const category = r.categoryNumber !== undefined ? ` [category ${r.categoryNumber}]` : '';
242
+ const categoryOnly = r.aqi === undefined ? ' (category only, no AQI number)' : '';
243
+ const site = r.siteName || r.siteID
244
+ ? ` — ${[r.siteName, r.siteID && `site ${r.siteID}`].filter(Boolean).join(', ')}`
245
+ : '';
246
+ const details = [
247
+ r.reportingAgency,
248
+ (r.dateIssue || r.forecastAgency) &&
249
+ ['issued', r.dateIssue, r.forecastAgency && `by ${r.forecastAgency}`]
250
+ .filter(Boolean)
251
+ .join(' '),
252
+ r.actionDay !== undefined && `action day: ${r.actionDay ? 'yes' : 'no'}`,
253
+ ].filter(Boolean);
254
+ lines.push(`- **${label}:** ${value}${category}${categoryOnly}${site}${details.length > 0 ? ` · ${details.join(' · ')}` : ''}`);
190
255
  }
256
+ if (area.discussion)
257
+ lines.push(`\n**Discussion:**\n${area.discussion}`);
191
258
  }
259
+ lines.push(`\n**Source:** ${result.attribution}`);
192
260
  return [{ type: 'text', text: lines.join('\n') }];
193
261
  },
194
262
  });
@@ -1 +1 @@
1
- {"version":3,"file":"get-air-quality.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-air-quality.tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"get-air-quality.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-air-quality.tool.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-ejscreen.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-ejscreen.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAQjE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgT1B,CAAC"}
1
+ {"version":3,"file":"get-ejscreen.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-ejscreen.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAQjE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+S1B,CAAC"}
@@ -179,7 +179,7 @@ export const getEjscreenTool = tool('epa_get_ejscreen', {
179
179
  async handler(input, ctx) {
180
180
  const bufferMiles = input.unit === 'kilometers' ? input.distance * MILES_PER_KM : input.distance;
181
181
  if (bufferMiles > MAX_BUFFER_MILES) {
182
- throw ctx.fail('buffer_too_large', `Buffer of ${bufferMiles.toFixed(2)} miles exceeds the EJAM API limit of ${MAX_BUFFER_MILES} miles.`, { ...ctx.recoveryFor('buffer_too_large') });
182
+ throw ctx.fail('buffer_too_large', `Buffer of ${bufferMiles.toFixed(2)} miles exceeds the EJAM API limit of ${MAX_BUFFER_MILES} miles.`);
183
183
  }
184
184
  ctx.log.info('epa_get_ejscreen', {
185
185
  lat: input.latitude,