@cyanheads/epa-mcp-server 0.1.1

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 (88) hide show
  1. package/CLAUDE.md +405 -0
  2. package/Dockerfile +98 -0
  3. package/README.md +322 -0
  4. package/changelog/0.1.x/0.1.0.md +22 -0
  5. package/changelog/0.1.x/0.1.1.md +18 -0
  6. package/changelog/template.md +119 -0
  7. package/dist/config/server-config.d.ts +15 -0
  8. package/dist/config/server-config.d.ts.map +1 -0
  9. package/dist/config/server-config.js +38 -0
  10. package/dist/config/server-config.js.map +1 -0
  11. package/dist/index.d.ts +7 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +28 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/mcp-server/resources/definitions/facility.resource.d.ts +9 -0
  16. package/dist/mcp-server/resources/definitions/facility.resource.d.ts.map +1 -0
  17. package/dist/mcp-server/resources/definitions/facility.resource.js +24 -0
  18. package/dist/mcp-server/resources/definitions/facility.resource.js.map +1 -0
  19. package/dist/mcp-server/resources/definitions/index.d.ts +12 -0
  20. package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -0
  21. package/dist/mcp-server/resources/definitions/index.js +10 -0
  22. package/dist/mcp-server/resources/definitions/index.js.map +1 -0
  23. package/dist/mcp-server/resources/definitions/superfund-site.resource.d.ts +9 -0
  24. package/dist/mcp-server/resources/definitions/superfund-site.resource.d.ts.map +1 -0
  25. package/dist/mcp-server/resources/definitions/superfund-site.resource.js +26 -0
  26. package/dist/mcp-server/resources/definitions/superfund-site.resource.js.map +1 -0
  27. package/dist/mcp-server/tools/definitions/get-air-quality.tool.d.ts +46 -0
  28. package/dist/mcp-server/tools/definitions/get-air-quality.tool.d.ts.map +1 -0
  29. package/dist/mcp-server/tools/definitions/get-air-quality.tool.js +193 -0
  30. package/dist/mcp-server/tools/definitions/get-air-quality.tool.js.map +1 -0
  31. package/dist/mcp-server/tools/definitions/get-facility.tool.d.ts +61 -0
  32. package/dist/mcp-server/tools/definitions/get-facility.tool.d.ts.map +1 -0
  33. package/dist/mcp-server/tools/definitions/get-facility.tool.js +193 -0
  34. package/dist/mcp-server/tools/definitions/get-facility.tool.js.map +1 -0
  35. package/dist/mcp-server/tools/definitions/get-tri-releases.tool.d.ts +26 -0
  36. package/dist/mcp-server/tools/definitions/get-tri-releases.tool.d.ts.map +1 -0
  37. package/dist/mcp-server/tools/definitions/get-tri-releases.tool.js +92 -0
  38. package/dist/mcp-server/tools/definitions/get-tri-releases.tool.js.map +1 -0
  39. package/dist/mcp-server/tools/definitions/index.d.ts +305 -0
  40. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
  41. package/dist/mcp-server/tools/definitions/index.js +31 -0
  42. package/dist/mcp-server/tools/definitions/index.js.map +1 -0
  43. package/dist/mcp-server/tools/definitions/search-facilities.tool.d.ts +58 -0
  44. package/dist/mcp-server/tools/definitions/search-facilities.tool.d.ts.map +1 -0
  45. package/dist/mcp-server/tools/definitions/search-facilities.tool.js +182 -0
  46. package/dist/mcp-server/tools/definitions/search-facilities.tool.js.map +1 -0
  47. package/dist/mcp-server/tools/definitions/search-superfund.tool.d.ts +49 -0
  48. package/dist/mcp-server/tools/definitions/search-superfund.tool.d.ts.map +1 -0
  49. package/dist/mcp-server/tools/definitions/search-superfund.tool.js +155 -0
  50. package/dist/mcp-server/tools/definitions/search-superfund.tool.js.map +1 -0
  51. package/dist/mcp-server/tools/definitions/search-tri-releases.tool.d.ts +29 -0
  52. package/dist/mcp-server/tools/definitions/search-tri-releases.tool.d.ts.map +1 -0
  53. package/dist/mcp-server/tools/definitions/search-tri-releases.tool.js +113 -0
  54. package/dist/mcp-server/tools/definitions/search-tri-releases.tool.js.map +1 -0
  55. package/dist/mcp-server/tools/definitions/search-violations.tool.d.ts +48 -0
  56. package/dist/mcp-server/tools/definitions/search-violations.tool.d.ts.map +1 -0
  57. package/dist/mcp-server/tools/definitions/search-violations.tool.js +156 -0
  58. package/dist/mcp-server/tools/definitions/search-violations.tool.js.map +1 -0
  59. package/dist/mcp-server/tools/definitions/search-water-systems.tool.d.ts +38 -0
  60. package/dist/mcp-server/tools/definitions/search-water-systems.tool.d.ts.map +1 -0
  61. package/dist/mcp-server/tools/definitions/search-water-systems.tool.js +147 -0
  62. package/dist/mcp-server/tools/definitions/search-water-systems.tool.js.map +1 -0
  63. package/dist/services/airnow/airnow-service.d.ts +45 -0
  64. package/dist/services/airnow/airnow-service.d.ts.map +1 -0
  65. package/dist/services/airnow/airnow-service.js +160 -0
  66. package/dist/services/airnow/airnow-service.js.map +1 -0
  67. package/dist/services/airnow/types.d.ts +39 -0
  68. package/dist/services/airnow/types.d.ts.map +1 -0
  69. package/dist/services/airnow/types.js +6 -0
  70. package/dist/services/airnow/types.js.map +1 -0
  71. package/dist/services/dmap/dmap-service.d.ts +60 -0
  72. package/dist/services/dmap/dmap-service.d.ts.map +1 -0
  73. package/dist/services/dmap/dmap-service.js +320 -0
  74. package/dist/services/dmap/dmap-service.js.map +1 -0
  75. package/dist/services/dmap/types.d.ts +108 -0
  76. package/dist/services/dmap/types.d.ts.map +1 -0
  77. package/dist/services/dmap/types.js +6 -0
  78. package/dist/services/dmap/types.js.map +1 -0
  79. package/dist/services/echo/echo-service.d.ts +57 -0
  80. package/dist/services/echo/echo-service.d.ts.map +1 -0
  81. package/dist/services/echo/echo-service.js +295 -0
  82. package/dist/services/echo/echo-service.js.map +1 -0
  83. package/dist/services/echo/types.d.ts +198 -0
  84. package/dist/services/echo/types.d.ts.map +1 -0
  85. package/dist/services/echo/types.js +6 -0
  86. package/dist/services/echo/types.js.map +1 -0
  87. package/package.json +80 -0
  88. package/server.json +111 -0
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @fileoverview Envirofacts DMAP REST service for TRI, Superfund, and drinking water data.
3
+ * Wraps data.epa.gov/dmapservice REST endpoints.
4
+ * @module services/dmap/dmap-service
5
+ */
6
+ import type { Context } from '@cyanheads/mcp-ts-core';
7
+ import type { AppConfig } from '@cyanheads/mcp-ts-core/config';
8
+ import type { StorageService } from '@cyanheads/mcp-ts-core/storage';
9
+ import type { SuperfundSite, TriRelease, WaterSystem } from './types.js';
10
+ export declare class DmapService {
11
+ private readonly baseUrl;
12
+ constructor(_config: AppConfig, _storage: StorageService);
13
+ /**
14
+ * Build a DMAP REST URL for a multi-filter query.
15
+ * Format: {base}/{schema}.{table}/{col1}/{op1}/{val1}/and/{col2}/{op2}/{val2}/{first}:{last}
16
+ */
17
+ private buildTableUrl;
18
+ /** Fetch a DMAP table result as JSON array. */
19
+ private fetchTable;
20
+ /** Get TRI releases for a specific facility. */
21
+ getTriReleases(params: {
22
+ facilityId: string;
23
+ year?: number;
24
+ chemicalName?: string;
25
+ }, ctx: Context): Promise<TriRelease[]>;
26
+ /** Search TRI releases by state, optionally filtered by county, year, or chemical. */
27
+ searchTriReleases(params: {
28
+ state: string;
29
+ county?: string;
30
+ year?: number;
31
+ chemicalName?: string;
32
+ limit?: number;
33
+ }, ctx: Context): Promise<(TriRelease & {
34
+ facilityName?: string;
35
+ })[]>;
36
+ /** Search Superfund sites by state or coordinates + radius. */
37
+ searchSuperfund(params: {
38
+ state?: string;
39
+ city?: string;
40
+ zipCode?: string;
41
+ latitude?: number;
42
+ longitude?: number;
43
+ radiusMiles?: number;
44
+ nplStatus?: string;
45
+ limit?: number;
46
+ }, ctx: Context): Promise<SuperfundSite[]>;
47
+ /** Fetch a single Superfund site by exact SEMS site ID. */
48
+ searchSuperfundById(siteId: string, ctx: Context): Promise<SuperfundSite[]>;
49
+ /** Search drinking water systems by state or ZIP code. */
50
+ searchWaterSystems(params: {
51
+ state?: string;
52
+ zipCode?: string;
53
+ hasViolation?: boolean;
54
+ pwsType?: string;
55
+ limit?: number;
56
+ }, ctx: Context): Promise<WaterSystem[]>;
57
+ }
58
+ export declare function initDmapService(config: AppConfig, storage: StorageService): void;
59
+ export declare function getDmapService(): DmapService;
60
+ //# sourceMappingURL=dmap-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dmap-service.d.ts","sourceRoot":"","sources":["../../../src/services/dmap/dmap-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,KAAK,EAMV,aAAa,EACb,UAAU,EACV,WAAW,EACZ,MAAM,YAAY,CAAC;AAkFpB,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc;IAIxD;;;OAGG;IACH,OAAO,CAAC,aAAa;IAarB,+CAA+C;YAEjC,UAAU;IA4BxB,gDAAgD;IAC1C,cAAc,CAClB,MAAM,EAAE;QACN,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,EACD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,UAAU,EAAE,CAAC;IAuBxB,sFAAsF;IAChF,iBAAiB,CACrB,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,EACD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,CAAC,UAAU,GAAG;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAyDtD,+DAA+D;IACzD,eAAe,CACnB,MAAM,EAAE;QACN,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,EACD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,aAAa,EAAE,CAAC;IAwD3B,2DAA2D;IACrD,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAYjF,0DAA0D;IACpD,kBAAkB,CACtB,MAAM,EAAE;QACN,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,EACD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,WAAW,EAAE,CAAC;CAmE1B;AAMD,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAEhF;AAED,wBAAgB,cAAc,IAAI,WAAW,CAK5C"}
@@ -0,0 +1,320 @@
1
+ /**
2
+ * @fileoverview Envirofacts DMAP REST service for TRI, Superfund, and drinking water data.
3
+ * Wraps data.epa.gov/dmapservice REST endpoints.
4
+ * @module services/dmap/dmap-service
5
+ */
6
+ import { serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
7
+ import { httpErrorFromResponse, withRetry } from '@cyanheads/mcp-ts-core/utils';
8
+ import { getServerConfig } from '../../config/server-config.js';
9
+ /** Parse a numeric field, returning undefined if absent/NaN. */
10
+ function parseNum(val) {
11
+ if (val === undefined || val === null || val === '')
12
+ return;
13
+ const n = Number(val);
14
+ return Number.isNaN(n) ? undefined : n;
15
+ }
16
+ /** Normalize a raw TRI reporting form row. */
17
+ function normalizeTriRelease(raw) {
18
+ const result = {
19
+ facilityId: raw.tri_facility_id ?? '',
20
+ // tri_reporting_form uses cas_chem_name, not chemical_name_text
21
+ chemicalName: raw.cas_chem_name ?? '',
22
+ reportingYear: Number(raw.reporting_year ?? 0),
23
+ };
24
+ // tri_reporting_form only has one_time_release_qty; air/water/land breakdowns are not in this table
25
+ const oneTime = parseNum(raw.one_time_release_qty);
26
+ if (oneTime !== undefined)
27
+ result.totalReleasesInLbs = oneTime;
28
+ return result;
29
+ }
30
+ /** Normalize a raw SEMS envirofacts_site record. */
31
+ function normalizeSemsSite(raw) {
32
+ const lat = parseNum(raw.primary_latitude_decimal_val);
33
+ const lng = parseNum(raw.primary_longitude_decimal_val);
34
+ return {
35
+ siteId: raw.site_id ?? '',
36
+ // actual field is `name`, not `site_name` (site_name is null in SEMS)
37
+ name: raw.name ?? '',
38
+ // actual field is `street_addr_txt`, not `street_address_1`
39
+ ...(raw.street_addr_txt && { street: raw.street_addr_txt }),
40
+ ...(raw.city_name && { city: raw.city_name }),
41
+ ...(raw.fk_ref_state_code && { state: raw.fk_ref_state_code }),
42
+ ...(raw.zip_code && { zip: raw.zip_code }),
43
+ ...(raw.county_name && { county: raw.county_name }),
44
+ // actual field is `fips_code`, not `county_fips_code`
45
+ ...(raw.fips_code && { fipsCode: raw.fips_code }),
46
+ ...(raw.npl_status_code && { nplStatus: raw.npl_status_code }),
47
+ ...(raw.cleanup_status && { cleanupStatus: raw.cleanup_status }),
48
+ ...(lat !== undefined && { latitude: lat }),
49
+ ...(lng !== undefined && { longitude: lng }),
50
+ };
51
+ }
52
+ /** Normalize a raw SDWIS water system record. */
53
+ function normalizeSdwisWaterSystem(raw, violatingPwsids) {
54
+ const pop = parseNum(raw.population_served_count);
55
+ const pwsid = raw.pwsid ?? '';
56
+ return {
57
+ pwsid,
58
+ name: raw.pws_name ?? '',
59
+ ...(raw.primacy_agency_code && { state: raw.primacy_agency_code }),
60
+ // actual field is city_name, not city_served
61
+ ...(raw.city_name && { city: raw.city_name }),
62
+ ...(raw.zip_code && { zip: raw.zip_code }),
63
+ ...(raw.pws_type_code && { type: raw.pws_type_code }),
64
+ ...(raw.primary_source_code && { primarySourceCode: raw.primary_source_code }),
65
+ ...(pop !== undefined && { populationServed: pop }),
66
+ ...(violatingPwsids !== undefined && { hasViolation: violatingPwsids.has(pwsid) }),
67
+ // actual field is pws_activity_code, not active_flag; 'A' = active
68
+ ...(raw.pws_activity_code !== undefined && { isActive: raw.pws_activity_code === 'A' }),
69
+ };
70
+ }
71
+ /**
72
+ * Compute the Haversine distance in miles between two lat/lng points.
73
+ */
74
+ function haversineDistanceMiles(lat1, lon1, lat2, lon2) {
75
+ const R = 3958.8;
76
+ const dLat = ((lat2 - lat1) * Math.PI) / 180;
77
+ const dLon = ((lon2 - lon1) * Math.PI) / 180;
78
+ const a = Math.sin(dLat / 2) ** 2 +
79
+ Math.cos((lat1 * Math.PI) / 180) * Math.cos((lat2 * Math.PI) / 180) * Math.sin(dLon / 2) ** 2;
80
+ return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
81
+ }
82
+ export class DmapService {
83
+ baseUrl;
84
+ constructor(_config, _storage) {
85
+ this.baseUrl = getServerConfig().dmapBaseUrl;
86
+ }
87
+ /**
88
+ * Build a DMAP REST URL for a multi-filter query.
89
+ * Format: {base}/{schema}.{table}/{col1}/{op1}/{val1}/and/{col2}/{op2}/{val2}/{first}:{last}
90
+ */
91
+ buildTableUrl(schema, table, filters, pagination) {
92
+ const filterPath = filters
93
+ .map((f) => `${encodeURIComponent(f.column)}/${f.operator}/${encodeURIComponent(f.value)}`)
94
+ .join('/and/');
95
+ const pagePath = `${pagination.first}:${pagination.last}`;
96
+ return `${this.baseUrl}/${schema}.${table}/${filterPath}/${pagePath}`;
97
+ }
98
+ /** Fetch a DMAP table result as JSON array. */
99
+ // biome-ignore lint/suspicious/useAwait: delegates to withRetry() which returns a Promise — async typing is correct
100
+ async fetchTable(url, ctx) {
101
+ return withRetry(async () => {
102
+ const jsonUrl = url.endsWith('/json') ? url : `${url}/json`;
103
+ const response = await fetch(jsonUrl, { signal: ctx.signal });
104
+ if (!response.ok) {
105
+ throw await httpErrorFromResponse(response, { service: 'DMAP', data: { url: jsonUrl } });
106
+ }
107
+ const text = await response.text();
108
+ if (/^\s*<(!DOCTYPE\s+html|html[\s>])/i.test(text)) {
109
+ throw serviceUnavailable('DMAP API returned HTML instead of JSON — likely rate-limited or unavailable.', { url: jsonUrl });
110
+ }
111
+ const parsed = JSON.parse(text);
112
+ if (Array.isArray(parsed))
113
+ return parsed;
114
+ const keys = Object.keys(parsed);
115
+ return (parsed[keys[0]] ?? []);
116
+ }, {
117
+ operation: 'DmapService.fetchTable',
118
+ baseDelayMs: 1000,
119
+ signal: ctx.signal,
120
+ });
121
+ }
122
+ /** Get TRI releases for a specific facility. */
123
+ async getTriReleases(params, ctx) {
124
+ const filters = [
125
+ { column: 'tri_facility_id', operator: 'equals', value: params.facilityId },
126
+ ];
127
+ if (params.year !== undefined) {
128
+ filters.push({ column: 'reporting_year', operator: 'equals', value: String(params.year) });
129
+ }
130
+ if (params.chemicalName) {
131
+ // actual field is cas_chem_name, not chemical_name_text
132
+ filters.push({
133
+ column: 'cas_chem_name',
134
+ operator: 'contains',
135
+ value: params.chemicalName,
136
+ });
137
+ }
138
+ const url = this.buildTableUrl('tri', 'tri_reporting_form', filters, { first: 0, last: 499 });
139
+ ctx.log.debug('DMAP TRI releases query', { facilityId: params.facilityId, year: params.year });
140
+ const rows = await this.fetchTable(url, ctx);
141
+ return rows.map(normalizeTriRelease);
142
+ }
143
+ /** Search TRI releases by state, optionally filtered by county, year, or chemical. */
144
+ async searchTriReleases(params, ctx) {
145
+ const limit = params.limit ?? 50;
146
+ const facilityFilters = [
147
+ { column: 'state_abbr', operator: 'equals', value: params.state },
148
+ ];
149
+ if (params.county) {
150
+ facilityFilters.push({ column: 'county', operator: 'contains', value: params.county });
151
+ }
152
+ const facilityUrl = this.buildTableUrl('tri', 'tri_facility', facilityFilters, {
153
+ first: 0,
154
+ last: limit - 1,
155
+ });
156
+ ctx.log.debug('DMAP TRI facility query', { state: params.state });
157
+ const facilities = await this.fetchTable(facilityUrl, ctx);
158
+ if (facilities.length === 0)
159
+ return [];
160
+ const facilityIds = facilities
161
+ .map((f) => f.tri_facility_id)
162
+ .filter((id) => typeof id === 'string' && id.length > 0);
163
+ const releaseFilters = [
164
+ { column: 'tri_facility_id', operator: 'in', value: facilityIds.join(',') },
165
+ ];
166
+ if (params.year !== undefined) {
167
+ releaseFilters.push({
168
+ column: 'reporting_year',
169
+ operator: 'equals',
170
+ value: String(params.year),
171
+ });
172
+ }
173
+ if (params.chemicalName) {
174
+ // actual field is cas_chem_name, not chemical_name_text
175
+ releaseFilters.push({
176
+ column: 'cas_chem_name',
177
+ operator: 'contains',
178
+ value: params.chemicalName,
179
+ });
180
+ }
181
+ const releaseUrl = this.buildTableUrl('tri', 'tri_reporting_form', releaseFilters, {
182
+ first: 0,
183
+ last: 499,
184
+ });
185
+ const releaseRows = await this.fetchTable(releaseUrl, ctx);
186
+ const facilityMap = new Map(facilities.map((f) => [f.tri_facility_id, f]));
187
+ return releaseRows.map((row) => {
188
+ const release = normalizeTriRelease(row);
189
+ const fac = facilityMap.get(row.tri_facility_id);
190
+ return fac ? { ...release, facilityName: fac.facility_name ?? '' } : release;
191
+ });
192
+ }
193
+ /** Search Superfund sites by state or coordinates + radius. */
194
+ async searchSuperfund(params, ctx) {
195
+ const limit = params.limit ?? 50;
196
+ const filters = [];
197
+ if (params.state) {
198
+ filters.push({ column: 'fk_ref_state_code', operator: 'equals', value: params.state });
199
+ }
200
+ if (params.city) {
201
+ filters.push({ column: 'city_name', operator: 'contains', value: params.city });
202
+ }
203
+ if (params.zipCode) {
204
+ filters.push({ column: 'zip_code', operator: 'equals', value: params.zipCode });
205
+ }
206
+ if (params.nplStatus && params.nplStatus !== 'all') {
207
+ const nplMap = { listed: 'NPL', 'not-listed': 'N', proposed: 'P' };
208
+ const nplCode = nplMap[params.nplStatus];
209
+ if (nplCode) {
210
+ filters.push({ column: 'npl_status_code', operator: 'equals', value: nplCode });
211
+ }
212
+ }
213
+ // Need at least one filter for DMAP; fall back to a no-op that returns empty
214
+ if (filters.length === 0) {
215
+ ctx.log.debug('DMAP Superfund query: no filters, returning empty');
216
+ return [];
217
+ }
218
+ const pageSize = params.latitude !== undefined && params.longitude !== undefined
219
+ ? Math.min(500, limit * 10)
220
+ : limit;
221
+ const url = this.buildTableUrl('sems', 'envirofacts_site', filters, {
222
+ first: 0,
223
+ last: pageSize - 1,
224
+ });
225
+ ctx.log.debug('DMAP Superfund query', { state: params.state, lat: params.latitude });
226
+ const rows = await this.fetchTable(url, ctx);
227
+ let sites = rows.map(normalizeSemsSite);
228
+ if (params.latitude !== undefined && params.longitude !== undefined && params.radiusMiles) {
229
+ sites = sites.filter((site) => {
230
+ if (site.latitude === undefined || site.longitude === undefined)
231
+ return false;
232
+ const dist = haversineDistanceMiles(params.latitude, params.longitude, site.latitude, site.longitude);
233
+ return dist <= (params.radiusMiles ?? 0);
234
+ });
235
+ }
236
+ return sites.slice(0, limit);
237
+ }
238
+ /** Fetch a single Superfund site by exact SEMS site ID. */
239
+ async searchSuperfundById(siteId, ctx) {
240
+ const url = this.buildTableUrl('sems', 'envirofacts_site', [{ column: 'site_id', operator: 'equals', value: siteId }], { first: 0, last: 1 });
241
+ ctx.log.debug('DMAP Superfund by ID', { siteId });
242
+ const rows = await this.fetchTable(url, ctx);
243
+ return rows.map(normalizeSemsSite);
244
+ }
245
+ /** Search drinking water systems by state or ZIP code. */
246
+ async searchWaterSystems(params, ctx) {
247
+ const limit = params.limit ?? 50;
248
+ const filters = [];
249
+ if (params.state) {
250
+ filters.push({ column: 'primacy_agency_code', operator: 'equals', value: params.state });
251
+ }
252
+ if (params.zipCode) {
253
+ filters.push({ column: 'zip_code', operator: 'equals', value: params.zipCode });
254
+ }
255
+ if (params.pwsType) {
256
+ const typeMap = {
257
+ community: 'CWS',
258
+ 'non-transient': 'NTNCWS',
259
+ transient: 'TNCWS',
260
+ };
261
+ const typeCode = typeMap[params.pwsType] ?? params.pwsType;
262
+ filters.push({ column: 'pws_type_code', operator: 'equals', value: typeCode });
263
+ }
264
+ if (filters.length === 0)
265
+ return [];
266
+ // When has_violation is requested, first collect violating PWS IDs from sdwis.violation.
267
+ // water_system has no violation_flag column — violations are in a separate table.
268
+ let violatingPwsids;
269
+ if (params.hasViolation) {
270
+ const violFilters = [];
271
+ if (params.state) {
272
+ violFilters.push({
273
+ column: 'primacy_agency_code',
274
+ operator: 'equals',
275
+ value: params.state,
276
+ });
277
+ }
278
+ if (params.zipCode) {
279
+ // sdwis.violation has no zip column; fall back to post-filter on the system level
280
+ // by still fetching all violations for the state
281
+ }
282
+ if (violFilters.length > 0) {
283
+ const violUrl = this.buildTableUrl('sdwis', 'violation', violFilters, {
284
+ first: 0,
285
+ last: 999,
286
+ });
287
+ ctx.log.debug('DMAP SDWIS violation query', { state: params.state });
288
+ const violRows = await this.fetchTable(violUrl, ctx);
289
+ violatingPwsids = new Set(violRows.map((r) => r.pwsid).filter((id) => typeof id === 'string'));
290
+ // If filtering by violation, restrict the main query to only violating PWS IDs
291
+ if (violatingPwsids.size > 0) {
292
+ filters.push({
293
+ column: 'pwsid',
294
+ operator: 'in',
295
+ value: Array.from(violatingPwsids).slice(0, 100).join(','),
296
+ });
297
+ }
298
+ else {
299
+ return [];
300
+ }
301
+ }
302
+ }
303
+ const url = this.buildTableUrl('sdwis', 'water_system', filters, { first: 0, last: limit - 1 });
304
+ ctx.log.debug('DMAP water systems query', { state: params.state });
305
+ const rows = await this.fetchTable(url, ctx);
306
+ return rows.map((r) => normalizeSdwisWaterSystem(r, violatingPwsids));
307
+ }
308
+ }
309
+ // --- Init/accessor pattern ---
310
+ let _service;
311
+ export function initDmapService(config, storage) {
312
+ _service = new DmapService(config, storage);
313
+ }
314
+ export function getDmapService() {
315
+ if (!_service) {
316
+ throw new Error('DmapService not initialized — call initDmapService() in setup()');
317
+ }
318
+ return _service;
319
+ }
320
+ //# sourceMappingURL=dmap-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dmap-service.js","sourceRoot":"","sources":["../../../src/services/dmap/dmap-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @fileoverview DMAP (Envirofacts) API response types and normalized domain types.
3
+ * @module services/dmap/types
4
+ */
5
+ /** Raw row from tri.tri_facility table. Coordinates encoded as DDMMSS integers. */
6
+ export interface RawTriFacility {
7
+ city?: string;
8
+ county?: string;
9
+ fac_latitude?: string | number;
10
+ fac_longitude?: string | number;
11
+ facility_name?: string;
12
+ state_abbr?: string;
13
+ street?: string;
14
+ tri_facility_id?: string;
15
+ zip_code?: string;
16
+ [key: string]: string | number | undefined;
17
+ }
18
+ /** Raw row from tri.tri_reporting_form table. */
19
+ export interface RawTriReportingForm {
20
+ /** Chemical name — actual field name in tri.tri_reporting_form */
21
+ cas_chem_name?: string;
22
+ /** One-time release quantity (the only release qty field in this table) */
23
+ one_time_release_qty?: string | number;
24
+ reporting_year?: string | number;
25
+ tri_facility_id?: string;
26
+ [key: string]: string | number | undefined;
27
+ }
28
+ /** Raw row from sems.envirofacts_site table. */
29
+ export interface RawSemsSite {
30
+ city_name?: string;
31
+ cleanup_status?: string;
32
+ county_name?: string;
33
+ /** Actual FIPS field name — county_fips_code does not exist */
34
+ fips_code?: string;
35
+ fk_ref_state_code?: string;
36
+ /** Actual site name field — site_name is null in SEMS */
37
+ name?: string;
38
+ npl_status_code?: string;
39
+ primary_latitude_decimal_val?: string | number;
40
+ primary_longitude_decimal_val?: string | number;
41
+ site_id?: string;
42
+ /** Actual street address field — street_address_1 does not exist */
43
+ street_addr_txt?: string;
44
+ zip_code?: string;
45
+ [key: string]: string | number | undefined;
46
+ }
47
+ /** Raw row from sdwis.water_system table. */
48
+ export interface RawSdwisWaterSystem {
49
+ /** Actual city field — city_served does not exist */
50
+ city_name?: string;
51
+ population_served_count?: string | number;
52
+ primacy_agency_code?: string;
53
+ primary_source_code?: string;
54
+ /** Actual activity field — active_flag does not exist; 'A' = active */
55
+ pws_activity_code?: string;
56
+ pws_name?: string;
57
+ pws_type_code?: string;
58
+ pwsid?: string;
59
+ zip_code?: string;
60
+ [key: string]: string | number | undefined;
61
+ }
62
+ /** Raw row from sdwis.violation table (used for has_violation filtering). */
63
+ export interface RawSdwisViolation {
64
+ primacy_agency_code?: string;
65
+ pwsid?: string;
66
+ [key: string]: string | number | undefined;
67
+ }
68
+ /**
69
+ * Normalized TRI chemical release record.
70
+ * Note: tri_reporting_form only provides one_time_release_qty (mapped to totalReleasesInLbs).
71
+ * Air/water/land breakdown fields are not available in DMAP's tri_reporting_form table.
72
+ */
73
+ export interface TriRelease {
74
+ chemicalName: string;
75
+ facilityId: string;
76
+ reportingYear: number;
77
+ /** Mapped from one_time_release_qty — the only release quantity in tri_reporting_form */
78
+ totalReleasesInLbs?: number;
79
+ }
80
+ /** Normalized Superfund site record. */
81
+ export interface SuperfundSite {
82
+ city?: string;
83
+ cleanupStatus?: string;
84
+ county?: string;
85
+ fipsCode?: string;
86
+ latitude?: number;
87
+ longitude?: number;
88
+ name: string;
89
+ nplStatus?: string;
90
+ siteId: string;
91
+ state?: string;
92
+ street?: string;
93
+ zip?: string;
94
+ }
95
+ /** Normalized drinking water system record. */
96
+ export interface WaterSystem {
97
+ city?: string;
98
+ hasViolation?: boolean;
99
+ isActive?: boolean;
100
+ name: string;
101
+ populationServed?: number;
102
+ primarySourceCode?: string;
103
+ pwsid: string;
104
+ state?: string;
105
+ type?: string;
106
+ zip?: string;
107
+ }
108
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/dmap/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @fileoverview DMAP (Envirofacts) API response types and normalized domain types.
3
+ * @module services/dmap/types
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/services/dmap/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @fileoverview ECHO API service for EPA facility compliance and enforcement data.
3
+ * Wraps echodata.epa.gov/echo REST endpoints for facility search, facility detail,
4
+ * and enforcement case search.
5
+ * @module services/echo/echo-service
6
+ */
7
+ import type { Context } from '@cyanheads/mcp-ts-core';
8
+ import type { AppConfig } from '@cyanheads/mcp-ts-core/config';
9
+ import type { StorageService } from '@cyanheads/mcp-ts-core/storage';
10
+ import type { EpaCase, EpaFacility, EpaFacilityProfile } from './types.js';
11
+ export declare class EchoService {
12
+ private readonly baseUrl;
13
+ constructor(_config: AppConfig, _storage: StorageService);
14
+ /** Build URL with query params. */
15
+ private buildUrl;
16
+ /** Fetch JSON from ECHO with retry. */
17
+ private fetchJson;
18
+ /**
19
+ * Search EPA-regulated facilities using ECHO get_facility_info.
20
+ * At least one geographic parameter must be supplied.
21
+ */
22
+ searchFacilities(params: {
23
+ zipCode?: string;
24
+ state?: string;
25
+ city?: string;
26
+ activeOnly?: boolean;
27
+ programs?: string[];
28
+ hasViolation?: boolean;
29
+ limit?: number;
30
+ }, ctx: Context): Promise<{
31
+ facilities: EpaFacility[];
32
+ totalCount: number;
33
+ }>;
34
+ /**
35
+ * Retrieve a full compliance profile for a single facility, aggregating multiple DFR endpoints.
36
+ * Steps 2-5 run in parallel after the initial facility info fetch.
37
+ */
38
+ getFacility(registryId: string, ctx: Context): Promise<EpaFacilityProfile>;
39
+ /**
40
+ * Search EPA enforcement cases using ECHO case_rest_services.
41
+ */
42
+ searchViolations(params: {
43
+ state?: string;
44
+ zipCode?: string;
45
+ program?: string;
46
+ caseType?: string;
47
+ dateFiledStart?: string;
48
+ dateFiledEnd?: string;
49
+ limit?: number;
50
+ }, ctx: Context): Promise<{
51
+ cases: EpaCase[];
52
+ totalCount: number;
53
+ }>;
54
+ }
55
+ export declare function initEchoService(config: AppConfig, storage: StorageService): void;
56
+ export declare function getEchoService(): EchoService;
57
+ //# sourceMappingURL=echo-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"echo-service.d.ts","sourceRoot":"","sources":["../../../src/services/echo/echo-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,KAAK,EACV,OAAO,EACP,WAAW,EACX,kBAAkB,EAOnB,MAAM,YAAY,CAAC;AA0CpB,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAGrB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc;IAIxD,mCAAmC;IACnC,OAAO,CAAC,QAAQ;IAahB,uCAAuC;YAEzB,SAAS;IAkCvB;;;OAGG;IACG,gBAAgB,CACpB,MAAM,EAAE;QACN,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,EACD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC;QAAE,UAAU,EAAE,WAAW,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAsC7D;;;OAGG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA4HhF;;OAEG;IACG,gBAAgB,CACpB,MAAM,EAAE;QACN,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,EACD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CA0CrD;AAMD,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAEhF;AAED,wBAAgB,cAAc,IAAI,WAAW,CAK5C"}