@cyanheads/epa-mcp-server 0.2.1 → 0.3.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.
- package/CLAUDE.md +69 -70
- package/Dockerfile +14 -7
- package/LICENSE +1 -1
- package/README.md +24 -9
- package/changelog/0.3.x/0.3.0.md +13 -0
- package/changelog/0.3.x/0.3.1.md +27 -0
- package/changelog/template.md +60 -19
- package/dist/config/server-config.d.ts +1 -0
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +7 -0
- package/dist/config/server-config.js.map +1 -1
- package/dist/epa-mcp-server.mcpb +0 -0
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-ejscreen.tool.d.ts +73 -0
- package/dist/mcp-server/tools/definitions/get-ejscreen.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-ejscreen.tool.js +273 -0
- package/dist/mcp-server/tools/definitions/get-ejscreen.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/index.d.ts +139 -10
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/index.js +4 -1
- package/dist/mcp-server/tools/definitions/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-facilities.tool.d.ts +1 -1
- package/dist/mcp-server/tools/definitions/search-violations.tool.d.ts +3 -3
- package/dist/services/airnow/airnow-service.d.ts.map +1 -1
- package/dist/services/dmap/dmap-service.d.ts.map +1 -1
- package/dist/services/dmap/dmap-service.js +55 -39
- package/dist/services/dmap/dmap-service.js.map +1 -1
- package/dist/services/echo/echo-service.d.ts.map +1 -1
- package/dist/services/echo/echo-service.js +30 -7
- package/dist/services/echo/echo-service.js.map +1 -1
- package/dist/services/echo/types.d.ts +1 -0
- package/dist/services/echo/types.d.ts.map +1 -1
- package/dist/services/ejscreen/ejscreen-service.d.ts +38 -0
- package/dist/services/ejscreen/ejscreen-service.d.ts.map +1 -0
- package/dist/services/ejscreen/ejscreen-service.js +258 -0
- package/dist/services/ejscreen/ejscreen-service.js.map +1 -0
- package/dist/services/ejscreen/types.d.ts +63 -0
- package/dist/services/ejscreen/types.d.ts.map +1 -0
- package/dist/services/ejscreen/types.js +9 -0
- package/dist/services/ejscreen/types.js.map +1 -0
- package/package.json +13 -12
- package/server.json +18 -4
|
@@ -8,6 +8,7 @@ declare const ServerConfigSchema: z.ZodObject<{
|
|
|
8
8
|
echoBaseUrl: z.ZodDefault<z.ZodString>;
|
|
9
9
|
dmapBaseUrl: z.ZodDefault<z.ZodString>;
|
|
10
10
|
airNowBaseUrl: z.ZodDefault<z.ZodString>;
|
|
11
|
+
ejscreenBaseUrl: z.ZodPreprocess<z.ZodDefault<z.ZodString>>;
|
|
11
12
|
}, z.core.$strip>;
|
|
12
13
|
export type ServerConfig = z.infer<typeof ServerConfigSchema>;
|
|
13
14
|
export declare function getServerConfig(): ServerConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C,QAAA,MAAM,kBAAkB
|
|
1
|
+
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C,QAAA,MAAM,kBAAkB;;;;;;iBAoCtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,CAS9C"}
|
|
@@ -26,6 +26,12 @@ const ServerConfigSchema = z.object({
|
|
|
26
26
|
.url()
|
|
27
27
|
.default('https://www.airnowapi.org/aq')
|
|
28
28
|
.describe('AirNow API base URL'),
|
|
29
|
+
// Optional override. Bundle/compose configs may inject an unfilled
|
|
30
|
+
// `${EJSCREEN_API_BASE_URL}` placeholder as an empty string — treat empty or
|
|
31
|
+
// whitespace-only as absent so the default applies instead of failing `.url()`.
|
|
32
|
+
ejscreenBaseUrl: z
|
|
33
|
+
.preprocess((v) => (typeof v === 'string' && v.trim() === '' ? undefined : v), z.string().url().default('https://api.ejanalysis.com'))
|
|
34
|
+
.describe('EJScreen (EJAM) API base URL — the community-maintained EJScreen rehost'),
|
|
29
35
|
});
|
|
30
36
|
let _config;
|
|
31
37
|
export function getServerConfig() {
|
|
@@ -34,6 +40,7 @@ export function getServerConfig() {
|
|
|
34
40
|
echoBaseUrl: 'EPA_ECHO_BASE_URL',
|
|
35
41
|
dmapBaseUrl: 'EPA_DMAP_BASE_URL',
|
|
36
42
|
airNowBaseUrl: 'EPA_AIRNOW_BASE_URL',
|
|
43
|
+
ejscreenBaseUrl: 'EJSCREEN_API_BASE_URL',
|
|
37
44
|
});
|
|
38
45
|
return _config;
|
|
39
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,oFAAoF;IACpF,qFAAqF;IACrF,uFAAuF;IACvF,YAAY,EAAE,CAAC;SACZ,UAAU,CACT,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EACjE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAC7B;SACA,QAAQ,CACP,4JAA4J,CAC7J;IACH,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,GAAG,EAAE;SACL,OAAO,CAAC,+BAA+B,CAAC;SACxC,QAAQ,CAAC,mBAAmB,CAAC;IAChC,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,GAAG,EAAE;SACL,OAAO,CAAC,kCAAkC,CAAC;SAC3C,QAAQ,CAAC,mBAAmB,CAAC;IAChC,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,GAAG,EAAE;SACL,OAAO,CAAC,8BAA8B,CAAC;SACvC,QAAQ,CAAC,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,oFAAoF;IACpF,qFAAqF;IACrF,uFAAuF;IACvF,YAAY,EAAE,CAAC;SACZ,UAAU,CACT,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EACjE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAC7B;SACA,QAAQ,CACP,4JAA4J,CAC7J;IACH,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,GAAG,EAAE;SACL,OAAO,CAAC,+BAA+B,CAAC;SACxC,QAAQ,CAAC,mBAAmB,CAAC;IAChC,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,GAAG,EAAE;SACL,OAAO,CAAC,kCAAkC,CAAC;SAC3C,QAAQ,CAAC,mBAAmB,CAAC;IAChC,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,GAAG,EAAE;SACL,OAAO,CAAC,8BAA8B,CAAC;SACvC,QAAQ,CAAC,qBAAqB,CAAC;IAClC,mEAAmE;IACnE,6EAA6E;IAC7E,gFAAgF;IAChF,eAAe,EAAE,CAAC;SACf,UAAU,CACT,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EACjE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,4BAA4B,CAAC,CACvD;SACA,QAAQ,CAAC,yEAAyE,CAAC;CACvF,CAAC,CAAC;AAIH,IAAI,OAAiC,CAAC;AAEtC,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,cAAc,CAAC,kBAAkB,EAAE;QAC7C,YAAY,EAAE,gBAAgB;QAC9B,WAAW,EAAE,mBAAmB;QAChC,WAAW,EAAE,mBAAmB;QAChC,aAAa,EAAE,qBAAqB;QACpC,eAAe,EAAE,uBAAuB;KACzC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -10,21 +10,23 @@ import { allToolDefinitions, coreToolDefinitions } from './mcp-server/tools/defi
|
|
|
10
10
|
import { initAirNowService } from './services/airnow/airnow-service.js';
|
|
11
11
|
import { initDmapService } from './services/dmap/dmap-service.js';
|
|
12
12
|
import { initEchoService } from './services/echo/echo-service.js';
|
|
13
|
+
import { initEjscreenService } from './services/ejscreen/ejscreen-service.js';
|
|
13
14
|
// AirNow is the only key-gated service. When AIRNOW_API_KEY is absent the server
|
|
14
|
-
// starts without epa_get_air_quality, leaving the
|
|
15
|
+
// starts without epa_get_air_quality, leaving the 8 keyless tools available.
|
|
15
16
|
const airNowEnabled = getServerConfig().airNowApiKey !== undefined;
|
|
16
17
|
/** Server instructions, omitting AirNow guidance when the air quality tool is disabled. */
|
|
17
18
|
function buildInstructions() {
|
|
18
19
|
const lines = [
|
|
19
|
-
`EPA environmental data server covering facility compliance (ECHO), toxic releases (TRI), Superfund sites, drinking water systems (SDWIS)${airNowEnabled ? ', and real-time air quality (AirNow)' : ''}.`,
|
|
20
|
-
'- All tools are read-only.
|
|
20
|
+
`EPA environmental data server covering facility compliance (ECHO), toxic releases (TRI), Superfund sites, drinking water systems (SDWIS), environmental-justice screening (EJScreen)${airNowEnabled ? ', and real-time air quality (AirNow)' : ''}.`,
|
|
21
|
+
'- All tools are read-only. Most APIs are US federal government public domain data.',
|
|
21
22
|
'- ECHO tools require at least one geographic filter (zip_code, state, or city) — unscoped searches time out. epa_search_facilities also accepts latitude + longitude + radius_miles for proximity search.',
|
|
22
23
|
'- TRI data lags ~18 months — most recent available year is typically 2 years prior to current.',
|
|
24
|
+
'- epa_get_ejscreen serves EJScreen v2.2 (2022) via the community-maintained EJAM API (Public Environmental Data Partners), which rehosts EJScreen after EPA discontinued public access in 2025 — not a live EPA endpoint; US coverage only.',
|
|
23
25
|
];
|
|
24
26
|
if (airNowEnabled) {
|
|
25
27
|
lines.push('- AirNow data is preliminary and not valid for regulatory, trend, or enforcement purposes.');
|
|
26
28
|
}
|
|
27
|
-
lines.push('- Typical workflows: epa_search_facilities → epa_get_facility → epa_search_violations (compliance audit); epa_search_superfund (proximity); epa_search_water_systems + has_violation=true (drinking water safety).');
|
|
29
|
+
lines.push('- Typical workflows: epa_search_facilities → epa_get_facility → epa_search_violations (compliance audit); epa_search_superfund (proximity); epa_search_water_systems + has_violation=true (drinking water safety); epa_get_ejscreen (environmental-justice indicators for a point + buffer).');
|
|
28
30
|
return lines.join('\n');
|
|
29
31
|
}
|
|
30
32
|
await createApp({
|
|
@@ -37,6 +39,7 @@ await createApp({
|
|
|
37
39
|
setup(core) {
|
|
38
40
|
initEchoService(core.config, core.storage);
|
|
39
41
|
initDmapService(core.config, core.storage);
|
|
42
|
+
initEjscreenService(core.config, core.storage);
|
|
40
43
|
if (airNowEnabled)
|
|
41
44
|
initAirNowService(core.config, core.storage);
|
|
42
45
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAE9E,iFAAiF;AACjF,6EAA6E;AAC7E,MAAM,aAAa,GAAG,eAAe,EAAE,CAAC,YAAY,KAAK,SAAS,CAAC;AAEnE,2FAA2F;AAC3F,SAAS,iBAAiB;IACxB,MAAM,KAAK,GAAG;QACZ,uLAAuL,aAAa,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,EAAE,GAAG;QACrP,oFAAoF;QACpF,2MAA2M;QAC3M,gGAAgG;QAChG,6OAA6O;KAC9O,CAAC;IACF,IAAI,aAAa,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CACR,4FAA4F,CAC7F,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,IAAI,CACR,8RAA8R,CAC/R,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,gBAAgB;IACvB,KAAK,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;IACtE,SAAS,EAAE,CAAC,GAAG,sBAAsB,CAAC;IACtC,OAAO,EAAE,EAAE;IACX,YAAY,EAAE,iBAAiB,EAAE;IACjC,KAAK,CAAC,IAAI;QACR,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3C,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3C,mBAAmB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,aAAa;YAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAClE,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool for retrieving EJScreen environmental-justice indicators for a
|
|
3
|
+
* point + buffer, backed by the community-maintained EJAM API.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-ejscreen.tool
|
|
5
|
+
*/
|
|
6
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
export declare const getEjscreenTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
9
|
+
latitude: z.ZodNumber;
|
|
10
|
+
longitude: z.ZodNumber;
|
|
11
|
+
distance: z.ZodDefault<z.ZodNumber>;
|
|
12
|
+
unit: z.ZodDefault<z.ZodEnum<{
|
|
13
|
+
kilometers: "kilometers";
|
|
14
|
+
miles: "miles";
|
|
15
|
+
}>>;
|
|
16
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
17
|
+
location: z.ZodObject<{
|
|
18
|
+
latitude: z.ZodNumber;
|
|
19
|
+
longitude: z.ZodNumber;
|
|
20
|
+
bufferMiles: z.ZodNumber;
|
|
21
|
+
state: z.ZodOptional<z.ZodString>;
|
|
22
|
+
stateName: z.ZodOptional<z.ZodString>;
|
|
23
|
+
population: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
blockGroupCount: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
environmental: z.ZodArray<z.ZodObject<{
|
|
27
|
+
code: z.ZodString;
|
|
28
|
+
label: z.ZodString;
|
|
29
|
+
value: z.ZodNumber;
|
|
30
|
+
unit: z.ZodOptional<z.ZodString>;
|
|
31
|
+
usPercentile: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
statePercentile: z.ZodOptional<z.ZodNumber>;
|
|
33
|
+
ejIndex: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
ejIndexUsPercentile: z.ZodOptional<z.ZodNumber>;
|
|
35
|
+
ejIndexStatePercentile: z.ZodOptional<z.ZodNumber>;
|
|
36
|
+
}, z.core.$strip>>;
|
|
37
|
+
demographic: z.ZodArray<z.ZodObject<{
|
|
38
|
+
code: z.ZodString;
|
|
39
|
+
label: z.ZodString;
|
|
40
|
+
percent: z.ZodNumber;
|
|
41
|
+
usPercentile: z.ZodOptional<z.ZodNumber>;
|
|
42
|
+
statePercentile: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
}, z.core.$strip>>;
|
|
44
|
+
demographicIndex: z.ZodOptional<z.ZodObject<{
|
|
45
|
+
value: z.ZodNumber;
|
|
46
|
+
usPercentile: z.ZodOptional<z.ZodNumber>;
|
|
47
|
+
statePercentile: z.ZodOptional<z.ZodNumber>;
|
|
48
|
+
}, z.core.$strip>>;
|
|
49
|
+
supplementalDemographicIndex: z.ZodOptional<z.ZodObject<{
|
|
50
|
+
value: z.ZodNumber;
|
|
51
|
+
usPercentile: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
statePercentile: z.ZodOptional<z.ZodNumber>;
|
|
53
|
+
}, z.core.$strip>>;
|
|
54
|
+
reportUrl: z.ZodOptional<z.ZodString>;
|
|
55
|
+
coverage: z.ZodObject<{
|
|
56
|
+
valid: z.ZodBoolean;
|
|
57
|
+
note: z.ZodOptional<z.ZodString>;
|
|
58
|
+
}, z.core.$strip>;
|
|
59
|
+
dataSource: z.ZodString;
|
|
60
|
+
}, z.core.$strip>, readonly [{
|
|
61
|
+
readonly reason: "buffer_too_large";
|
|
62
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
63
|
+
readonly when: "The buffer radius exceeds the EJAM API cap of 15 miles (after converting kilometers to miles).";
|
|
64
|
+
readonly recovery: "Reduce distance so the miles-equivalent is 15 or less (about 24 km) and retry.";
|
|
65
|
+
}, {
|
|
66
|
+
readonly reason: "upstream_rejected";
|
|
67
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
68
|
+
readonly when: "The EJAM API rejected the request, typically for invalid coordinates.";
|
|
69
|
+
readonly recovery: "Check that latitude and longitude are valid decimal-degree US coordinates and retry.";
|
|
70
|
+
}], {
|
|
71
|
+
readonly notice: z.ZodOptional<z.ZodString>;
|
|
72
|
+
}>;
|
|
73
|
+
//# sourceMappingURL=get-ejscreen.tool.d.ts.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+S1B,CAAC"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool for retrieving EJScreen environmental-justice indicators for a
|
|
3
|
+
* point + buffer, backed by the community-maintained EJAM API.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-ejscreen.tool
|
|
5
|
+
*/
|
|
6
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
import { getEjscreenService } from '../../../services/ejscreen/ejscreen-service.js';
|
|
9
|
+
/** Miles-per-kilometer conversion factor. */
|
|
10
|
+
const MILES_PER_KM = 0.621371;
|
|
11
|
+
/** The EJAM API caps the buffer at 15 miles. */
|
|
12
|
+
const MAX_BUFFER_MILES = 15;
|
|
13
|
+
export const getEjscreenTool = tool('epa_get_ejscreen', {
|
|
14
|
+
title: 'Get EJScreen Environmental Justice Indicators',
|
|
15
|
+
description: 'Get EJScreen environmental-justice indicators for a point and surrounding buffer. Returns the 13 EJScreen environmental indicators (PM2.5, ozone, diesel particulate, NO2, lead paint, traffic proximity, Superfund/RMP/hazardous-waste/wastewater proximity, underground storage tanks, drinking-water non-compliance, and RSEI toxic air releases) and 6 demographic indicators (people of color, low income, limited English, less than high school, under 5, over 64), each with national and state percentiles plus EJ Index values, along with the Demographic Index and Supplemental Demographic Index. Data is EJScreen v2.2 (2022) served via the community-maintained EJAM API (api.ejanalysis.com, Public Environmental Data Partners), which rehosts EJScreen after EPA discontinued public access in 2025 — not a live EPA endpoint. Provide latitude, longitude, and a buffer distance (default 1 mile, max 15 miles). Points outside US coverage return a coverage note instead of indicators.',
|
|
16
|
+
annotations: { readOnlyHint: true, openWorldHint: true, idempotentHint: true },
|
|
17
|
+
input: z.object({
|
|
18
|
+
latitude: z.number().min(-90).max(90).describe('Latitude in decimal degrees.'),
|
|
19
|
+
longitude: z.number().min(-180).max(180).describe('Longitude in decimal degrees.'),
|
|
20
|
+
distance: z
|
|
21
|
+
.number()
|
|
22
|
+
.positive()
|
|
23
|
+
.default(1)
|
|
24
|
+
.describe('Buffer radius around the point, in the given unit (default 1). The miles-equivalent must be 15 or less.'),
|
|
25
|
+
unit: z
|
|
26
|
+
.enum(['miles', 'kilometers'])
|
|
27
|
+
.default('miles')
|
|
28
|
+
.describe('Unit for distance. Kilometers are converted to miles (× 0.621371) before the request.'),
|
|
29
|
+
}),
|
|
30
|
+
output: z.object({
|
|
31
|
+
location: z
|
|
32
|
+
.object({
|
|
33
|
+
latitude: z.number().describe('Latitude of the queried point in decimal degrees.'),
|
|
34
|
+
longitude: z.number().describe('Longitude of the queried point in decimal degrees.'),
|
|
35
|
+
bufferMiles: z
|
|
36
|
+
.number()
|
|
37
|
+
.describe('Buffer radius in miles used for the query (kilometers inputs converted first).'),
|
|
38
|
+
state: z
|
|
39
|
+
.string()
|
|
40
|
+
.optional()
|
|
41
|
+
.describe('2-letter state abbreviation for the area (e.g. "MD"). Absent when out of coverage.'),
|
|
42
|
+
stateName: z
|
|
43
|
+
.string()
|
|
44
|
+
.optional()
|
|
45
|
+
.describe('Full state name (e.g. "Maryland"). Absent when out of coverage.'),
|
|
46
|
+
population: z
|
|
47
|
+
.number()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('Area-weighted population within the buffer. Absent when out of coverage.'),
|
|
50
|
+
blockGroupCount: z
|
|
51
|
+
.number()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Number of census block groups intersecting the buffer. Absent when out of coverage.'),
|
|
54
|
+
})
|
|
55
|
+
.describe('The queried location and buffer context.'),
|
|
56
|
+
environmental: z
|
|
57
|
+
.array(z
|
|
58
|
+
.object({
|
|
59
|
+
code: z
|
|
60
|
+
.string()
|
|
61
|
+
.describe('EJScreen environmental indicator code (e.g. "pm", "o3", "proximity.npl").'),
|
|
62
|
+
label: z.string().describe('Human-readable indicator name.'),
|
|
63
|
+
value: z.number().describe('Raw indicator value, in the unit given by the unit field.'),
|
|
64
|
+
unit: z.string().optional().describe('Unit or scale of the raw value.'),
|
|
65
|
+
usPercentile: z
|
|
66
|
+
.number()
|
|
67
|
+
.optional()
|
|
68
|
+
.describe('National percentile (0–100) for the raw value.'),
|
|
69
|
+
statePercentile: z
|
|
70
|
+
.number()
|
|
71
|
+
.optional()
|
|
72
|
+
.describe('State percentile (0–100) for the raw value.'),
|
|
73
|
+
ejIndex: z
|
|
74
|
+
.number()
|
|
75
|
+
.optional()
|
|
76
|
+
.describe('EJ Index (raw) — the indicator combined with the demographic index.'),
|
|
77
|
+
ejIndexUsPercentile: z
|
|
78
|
+
.number()
|
|
79
|
+
.optional()
|
|
80
|
+
.describe('National percentile (0–100) of the EJ Index.'),
|
|
81
|
+
ejIndexStatePercentile: z
|
|
82
|
+
.number()
|
|
83
|
+
.optional()
|
|
84
|
+
.describe('State percentile (0–100) of the EJ Index.'),
|
|
85
|
+
})
|
|
86
|
+
.describe('One environmental indicator with percentiles and its EJ Index.'))
|
|
87
|
+
.describe('EJScreen environmental indicators present for the area. Empty when out of coverage.'),
|
|
88
|
+
demographic: z
|
|
89
|
+
.array(z
|
|
90
|
+
.object({
|
|
91
|
+
code: z
|
|
92
|
+
.string()
|
|
93
|
+
.describe('EJScreen demographic indicator code (e.g. "pctmin", "pctlowinc").'),
|
|
94
|
+
label: z.string().describe('Human-readable indicator name.'),
|
|
95
|
+
percent: z
|
|
96
|
+
.number()
|
|
97
|
+
.describe('Share of the buffer population, as a percentage (0–100).'),
|
|
98
|
+
usPercentile: z
|
|
99
|
+
.number()
|
|
100
|
+
.optional()
|
|
101
|
+
.describe('National percentile (0–100) for the share.'),
|
|
102
|
+
statePercentile: z
|
|
103
|
+
.number()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe('State percentile (0–100) for the share.'),
|
|
106
|
+
})
|
|
107
|
+
.describe('One demographic indicator with percentiles.'))
|
|
108
|
+
.describe('EJScreen demographic indicators present for the area. Empty when out of coverage.'),
|
|
109
|
+
demographicIndex: z
|
|
110
|
+
.object({
|
|
111
|
+
value: z
|
|
112
|
+
.number()
|
|
113
|
+
.describe('Demographic Index raw value (average of low-income and people-of-color shares).'),
|
|
114
|
+
usPercentile: z
|
|
115
|
+
.number()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe('National percentile (0–100) of the Demographic Index.'),
|
|
118
|
+
statePercentile: z
|
|
119
|
+
.number()
|
|
120
|
+
.optional()
|
|
121
|
+
.describe('State percentile (0–100) of the Demographic Index.'),
|
|
122
|
+
})
|
|
123
|
+
.optional()
|
|
124
|
+
.describe('EJScreen Demographic Index. Absent when out of coverage.'),
|
|
125
|
+
supplementalDemographicIndex: z
|
|
126
|
+
.object({
|
|
127
|
+
value: z
|
|
128
|
+
.number()
|
|
129
|
+
.describe('Supplemental Demographic Index raw value (five-factor average).'),
|
|
130
|
+
usPercentile: z
|
|
131
|
+
.number()
|
|
132
|
+
.optional()
|
|
133
|
+
.describe('National percentile (0–100) of the Supplemental Demographic Index.'),
|
|
134
|
+
statePercentile: z
|
|
135
|
+
.number()
|
|
136
|
+
.optional()
|
|
137
|
+
.describe('State percentile (0–100) of the Supplemental Demographic Index.'),
|
|
138
|
+
})
|
|
139
|
+
.optional()
|
|
140
|
+
.describe('EJScreen Supplemental Demographic Index. Absent when out of coverage.'),
|
|
141
|
+
reportUrl: z
|
|
142
|
+
.string()
|
|
143
|
+
.optional()
|
|
144
|
+
.describe('Link (absolute URL) to the full EJScreen report for this point and buffer.'),
|
|
145
|
+
coverage: z
|
|
146
|
+
.object({
|
|
147
|
+
valid: z
|
|
148
|
+
.boolean()
|
|
149
|
+
.describe('True when EJScreen returned indicators for the point; false when the point is outside coverage.'),
|
|
150
|
+
note: z
|
|
151
|
+
.string()
|
|
152
|
+
.optional()
|
|
153
|
+
.describe('Explanation from EJScreen when coverage is unavailable (e.g. point outside the US).'),
|
|
154
|
+
})
|
|
155
|
+
.describe('Whether EJScreen data was available for the point.'),
|
|
156
|
+
dataSource: z.string().describe('Provenance and vintage of the data.'),
|
|
157
|
+
}),
|
|
158
|
+
enrichment: {
|
|
159
|
+
notice: z
|
|
160
|
+
.string()
|
|
161
|
+
.optional()
|
|
162
|
+
.describe('Guidance when the point is outside EJScreen coverage and no indicators were returned.'),
|
|
163
|
+
},
|
|
164
|
+
errors: [
|
|
165
|
+
{
|
|
166
|
+
reason: 'buffer_too_large',
|
|
167
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
168
|
+
when: 'The buffer radius exceeds the EJAM API cap of 15 miles (after converting kilometers to miles).',
|
|
169
|
+
recovery: 'Reduce distance so the miles-equivalent is 15 or less (about 24 km) and retry.',
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
reason: 'upstream_rejected',
|
|
173
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
174
|
+
when: 'The EJAM API rejected the request, typically for invalid coordinates.',
|
|
175
|
+
recovery: 'Check that latitude and longitude are valid decimal-degree US coordinates and retry.',
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
async handler(input, ctx) {
|
|
179
|
+
const bufferMiles = input.unit === 'kilometers' ? input.distance * MILES_PER_KM : input.distance;
|
|
180
|
+
if (bufferMiles > MAX_BUFFER_MILES) {
|
|
181
|
+
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
|
+
}
|
|
183
|
+
ctx.log.info('epa_get_ejscreen', {
|
|
184
|
+
lat: input.latitude,
|
|
185
|
+
lon: input.longitude,
|
|
186
|
+
bufferMiles,
|
|
187
|
+
});
|
|
188
|
+
const result = await getEjscreenService().getIndicators({ latitude: input.latitude, longitude: input.longitude, bufferMiles }, ctx);
|
|
189
|
+
ctx.log.info('epa_get_ejscreen completed', {
|
|
190
|
+
valid: result.coverage.valid,
|
|
191
|
+
environmental: result.environmental.length,
|
|
192
|
+
demographic: result.demographic.length,
|
|
193
|
+
});
|
|
194
|
+
if (!result.coverage.valid) {
|
|
195
|
+
ctx.enrich.notice(result.coverage.note
|
|
196
|
+
? `EJScreen has no coverage for this point: ${result.coverage.note}`
|
|
197
|
+
: `EJScreen returned no indicators for lat=${input.latitude}, lon=${input.longitude}. EJScreen covers US locations only — verify the point is within the United States.`);
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
},
|
|
201
|
+
format: (result) => {
|
|
202
|
+
const lines = [];
|
|
203
|
+
const loc = result.location;
|
|
204
|
+
const place = loc.stateName ?? loc.state;
|
|
205
|
+
lines.push(`## EJScreen Environmental Justice — ${loc.latitude}, ${loc.longitude}${place ? ` (${place})` : ''}`);
|
|
206
|
+
lines.push(`**Buffer:** ${loc.bufferMiles} miles`);
|
|
207
|
+
if (loc.state)
|
|
208
|
+
lines.push(`**State:** ${loc.state}`);
|
|
209
|
+
if (loc.stateName)
|
|
210
|
+
lines.push(`**State name:** ${loc.stateName}`);
|
|
211
|
+
if (loc.population !== undefined)
|
|
212
|
+
lines.push(`**Population in buffer:** ${loc.population}`);
|
|
213
|
+
if (loc.blockGroupCount !== undefined) {
|
|
214
|
+
lines.push(`**Block groups intersected:** ${loc.blockGroupCount}`);
|
|
215
|
+
}
|
|
216
|
+
lines.push(`**Coverage valid:** ${result.coverage.valid ? 'yes' : 'no'}`);
|
|
217
|
+
if (result.coverage.note)
|
|
218
|
+
lines.push(`> ${result.coverage.note}`);
|
|
219
|
+
if (result.environmental.length > 0) {
|
|
220
|
+
lines.push('\n### Environmental indicators');
|
|
221
|
+
for (const e of result.environmental) {
|
|
222
|
+
const parts = [`**${e.label}** (\`${e.code}\`): ${e.value}${e.unit ? ` ${e.unit}` : ''}`];
|
|
223
|
+
if (e.usPercentile !== undefined)
|
|
224
|
+
parts.push(`US pctile ${e.usPercentile}`);
|
|
225
|
+
if (e.statePercentile !== undefined)
|
|
226
|
+
parts.push(`state pctile ${e.statePercentile}`);
|
|
227
|
+
if (e.ejIndex !== undefined)
|
|
228
|
+
parts.push(`EJ Index ${e.ejIndex}`);
|
|
229
|
+
if (e.ejIndexUsPercentile !== undefined) {
|
|
230
|
+
parts.push(`EJ Index US pctile ${e.ejIndexUsPercentile}`);
|
|
231
|
+
}
|
|
232
|
+
if (e.ejIndexStatePercentile !== undefined) {
|
|
233
|
+
parts.push(`EJ Index state pctile ${e.ejIndexStatePercentile}`);
|
|
234
|
+
}
|
|
235
|
+
lines.push(`- ${parts.join(' · ')}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (result.demographic.length > 0) {
|
|
239
|
+
lines.push('\n### Demographic indicators');
|
|
240
|
+
for (const d of result.demographic) {
|
|
241
|
+
const parts = [`**${d.label}** (\`${d.code}\`): ${d.percent}%`];
|
|
242
|
+
if (d.usPercentile !== undefined)
|
|
243
|
+
parts.push(`US pctile ${d.usPercentile}`);
|
|
244
|
+
if (d.statePercentile !== undefined)
|
|
245
|
+
parts.push(`state pctile ${d.statePercentile}`);
|
|
246
|
+
lines.push(`- ${parts.join(' · ')}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (result.demographicIndex) {
|
|
250
|
+
const di = result.demographicIndex;
|
|
251
|
+
const parts = [`**Demographic Index:** ${di.value}`];
|
|
252
|
+
if (di.usPercentile !== undefined)
|
|
253
|
+
parts.push(`US pctile ${di.usPercentile}`);
|
|
254
|
+
if (di.statePercentile !== undefined)
|
|
255
|
+
parts.push(`state pctile ${di.statePercentile}`);
|
|
256
|
+
lines.push(`\n${parts.join(' · ')}`);
|
|
257
|
+
}
|
|
258
|
+
if (result.supplementalDemographicIndex) {
|
|
259
|
+
const si = result.supplementalDemographicIndex;
|
|
260
|
+
const parts = [`**Supplemental Demographic Index:** ${si.value}`];
|
|
261
|
+
if (si.usPercentile !== undefined)
|
|
262
|
+
parts.push(`US pctile ${si.usPercentile}`);
|
|
263
|
+
if (si.statePercentile !== undefined)
|
|
264
|
+
parts.push(`state pctile ${si.statePercentile}`);
|
|
265
|
+
lines.push(parts.join(' · '));
|
|
266
|
+
}
|
|
267
|
+
if (result.reportUrl)
|
|
268
|
+
lines.push(`\n**EJScreen report:** ${result.reportUrl}`);
|
|
269
|
+
lines.push(`\n_Source: ${result.dataSource}_`);
|
|
270
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
//# sourceMappingURL=get-ejscreen.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-ejscreen.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-ejscreen.tool.ts"],"names":[],"mappings":"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"}
|