geotap-mcp-server 2.1.0 → 2.2.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/package.json +1 -1
- package/src/consolidatedTools.js +6 -6
- package/src/discoverTools.js +24 -2
- package/src/index.js +9 -4
- package/src/llms.txt +2 -2
- package/src/paramNormalize.js +60 -1
- package/tests/Spec_Comprehensive_Test_Suite.md +1203 -0
- package/tests/comprehensive-test.js +865 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "geotap-mcp-server",
|
|
3
|
-
"version": "2.1
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "MCP server for GeoTap — access 37 US federal environmental and infrastructure data sources from Claude, Cursor, and other AI tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/consolidatedTools.js
CHANGED
|
@@ -26,7 +26,7 @@ Actions:
|
|
|
26
26
|
- "polygon" — Query features in a polygon area. Set geometry="none" and specify layers.
|
|
27
27
|
- "summary" — Quick feature counts for an area (no geometry, just numbers). Fastest option for "how many?" questions.
|
|
28
28
|
- "geocode" — Convert address/place name to coordinates. Use only when you need coordinates for other tools.
|
|
29
|
-
- "list_layers" — List
|
|
29
|
+
- "list_layers" — List available data layers.
|
|
30
30
|
- "layer_details" — Get metadata about a specific layer.
|
|
31
31
|
- "layer_features" — Get features from one specific layer in a bbox.`,
|
|
32
32
|
parameters: {
|
|
@@ -76,7 +76,7 @@ Actions:
|
|
|
76
76
|
- "hyetograph" — Generate a design storm hyetograph (rainfall over time) for hydrologic modeling.
|
|
77
77
|
- "export_hyetograph" — Export hyetograph as CSV/JSON for HEC-HMS, SWMM, etc.
|
|
78
78
|
- "distributions" — List available rainfall distribution types (SCS Type I/IA/II/III, Huff, etc.).
|
|
79
|
-
- "recommend_distribution" — Determine which distribution type applies at a location.
|
|
79
|
+
- "recommend_distribution" — Determine which distribution type applies at a location. Note: this uses coastal/inland boundaries. For SCS design storms, prefer get_hydrology(action=distribution_for_location) which uses NRCS regional mapping.
|
|
80
80
|
- "climate_scenarios" — List available SSP scenarios and time horizons.
|
|
81
81
|
- "climate_factors" — Get climate change adjustment multipliers for a location.
|
|
82
82
|
- "climate_projection" — Apply climate change projections to Atlas 14 data.
|
|
@@ -396,7 +396,7 @@ Actions:
|
|
|
396
396
|
// ═══════════════════════════════════════════════════════════════════
|
|
397
397
|
{
|
|
398
398
|
name: 'export_data',
|
|
399
|
-
description: `Export environmental data layers to GIS formats (GeoJSON, Shapefile,
|
|
399
|
+
description: `Export environmental data layers to GIS formats (GeoJSON, Shapefile, CSV).
|
|
400
400
|
|
|
401
401
|
Actions:
|
|
402
402
|
- "export" — Export layers to a file format. Supports CRS transformation and clipping.
|
|
@@ -406,7 +406,7 @@ Actions:
|
|
|
406
406
|
action: z.enum(['export', 'options', 'status'])
|
|
407
407
|
.describe('Which export operation'),
|
|
408
408
|
layers: z.array(z.string()).optional().describe('Layer names to export'),
|
|
409
|
-
format: z.enum(['geojson', 'shapefile', '
|
|
409
|
+
format: z.enum(['geojson', 'shapefile', 'csv']).optional().describe('Output format'),
|
|
410
410
|
crs: z.string().optional().describe('Target CRS (e.g., "EPSG:4326")'),
|
|
411
411
|
geometry: z.any().optional().describe('GeoJSON geometry to clip export area'),
|
|
412
412
|
options: z.any().optional().describe('Additional options: {dem, satellite, nlcd, contours}'),
|
|
@@ -555,10 +555,10 @@ Actions:
|
|
|
555
555
|
- "fire_stations" — Fire stations: type, status.
|
|
556
556
|
- "schools" — Public schools: enrollment, grade levels, teacher count.
|
|
557
557
|
- "power_plants" — Power plants: fuel type, installed capacity (MW).
|
|
558
|
-
- "airports" — FAA airports:
|
|
558
|
+
- "airports" — FAA airports: name, FAA code, city, state.
|
|
559
559
|
- "railroad_crossings" — FRA highway-rail crossings: warning devices, trains/day, crash data.
|
|
560
560
|
- "bridges" — DOT bridges: condition ratings (0-9), sufficiency rating (0-100), year built.
|
|
561
|
-
- "historic_places" — National Register of Historic Places:
|
|
561
|
+
- "historic_places" — National Register of Historic Places: name, NRIS reference number.`,
|
|
562
562
|
parameters: {
|
|
563
563
|
action: z.enum(['hospitals', 'fire_stations', 'schools', 'power_plants', 'airports', 'railroad_crossings', 'bridges', 'historic_places'])
|
|
564
564
|
.describe('Which infrastructure data to query'),
|
package/src/discoverTools.js
CHANGED
|
@@ -7,6 +7,20 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { tools } from './tools.js';
|
|
10
|
+
import { consolidatedTools } from './consolidatedTools.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Build reverse mapping: legacy tool name → consolidated "tool(action=X)" format.
|
|
14
|
+
* Used to translate discover_tools results when running in consolidated mode.
|
|
15
|
+
*/
|
|
16
|
+
const legacyToConsolidated = {};
|
|
17
|
+
for (const ctool of consolidatedTools) {
|
|
18
|
+
for (const [action, legacyName] of Object.entries(ctool._actionMap)) {
|
|
19
|
+
legacyToConsolidated[legacyName] = { tool: ctool.name, action };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const useLegacyTools = process.env.GEOTAP_LEGACY_TOOLS === 'true';
|
|
10
24
|
|
|
11
25
|
/**
|
|
12
26
|
* Tool categories with keywords for matching.
|
|
@@ -156,8 +170,14 @@ export function discoverTools(question, maxResults = 5) {
|
|
|
156
170
|
}
|
|
157
171
|
}
|
|
158
172
|
|
|
173
|
+
// In consolidated mode, translate legacy name to consolidated tool+action format
|
|
174
|
+
const consolidated = !useLegacyTools ? legacyToConsolidated[tool.name] : null;
|
|
175
|
+
const displayName = consolidated
|
|
176
|
+
? `${consolidated.tool}(action="${consolidated.action}")`
|
|
177
|
+
: tool.name;
|
|
178
|
+
|
|
159
179
|
return {
|
|
160
|
-
name:
|
|
180
|
+
name: displayName,
|
|
161
181
|
description: tool.description.split('.')[0] + '.', // First sentence only
|
|
162
182
|
method: tool.method,
|
|
163
183
|
parameters: params,
|
|
@@ -183,7 +203,9 @@ export function discoverTools(question, maxResults = 5) {
|
|
|
183
203
|
allCategories: Object.keys(TOOL_CATEGORIES),
|
|
184
204
|
hint: results.length > 0
|
|
185
205
|
? `Start with "${results[0].name}" — it's the best match for your question.`
|
|
186
|
-
:
|
|
206
|
+
: useLegacyTools
|
|
207
|
+
? 'No strong matches found. Try query_address for location-based questions, or list_data_layers to see available data.'
|
|
208
|
+
: 'No strong matches found. Try query_location(action="address") for location-based questions, or query_location(action="list_layers") to see available data.',
|
|
187
209
|
totalToolsAvailable: tools.length
|
|
188
210
|
};
|
|
189
211
|
}
|
package/src/index.js
CHANGED
|
@@ -25,12 +25,12 @@ const legacyToolMap = new Map(tools.map(t => [t.name, t]));
|
|
|
25
25
|
const server = new McpServer({
|
|
26
26
|
name: 'geotap',
|
|
27
27
|
version: '2.0.0',
|
|
28
|
-
description: 'Access
|
|
28
|
+
description: 'Access US federal environmental and infrastructure data layers from 64+ agencies. Query flood zones, wetlands, soils, rainfall, watersheds, water quality, endangered species, elevation, land use, hazards, energy, infrastructure, transportation, and more for any location in the United States.',
|
|
29
29
|
instructions: useLegacyTools
|
|
30
30
|
? `You have access to GeoTap with 85 individual tools. Use discover_tools to find the right one.`
|
|
31
31
|
: `You have access to GeoTap, which provides real-time data from 37 US federal agencies (FEMA, USGS, NOAA, EPA, NRCS, USFWS, USACE, and more).
|
|
32
32
|
|
|
33
|
-
TOOL OVERVIEW (
|
|
33
|
+
TOOL OVERVIEW (16 tools + 2 meta-tools):
|
|
34
34
|
1. query_location — Start here. Query environmental data by address, coordinates, bbox, polygon, or radius.
|
|
35
35
|
2. get_rainfall — NOAA Atlas 14 precipitation, IDF curves, hyetographs, climate projections.
|
|
36
36
|
3. get_watershed — Watershed delineation, flow statistics, flowlines, HUC boundaries, FIRM panels.
|
|
@@ -40,9 +40,13 @@ TOOL OVERVIEW (12 tools + 2 meta-tools):
|
|
|
40
40
|
7. analyze_gage — USGS stream gage analysis: flood frequency, flow duration, storm events.
|
|
41
41
|
8. estimate_ungaged — Flow estimation at ungaged sites: regression, similarity, transfer methods.
|
|
42
42
|
9. generate_report — Site analysis, constraints, and developability reports with scoring.
|
|
43
|
-
10. export_data — Export layers to GeoJSON, Shapefile,
|
|
43
|
+
10. export_data — Export layers to GeoJSON, Shapefile, CSV.
|
|
44
44
|
11. find_stations — Find monitoring stations (USGS, NOAA) and analyze waterway permit requirements.
|
|
45
45
|
12. check_status — API health and federal data source connectivity.
|
|
46
|
+
13. get_hazards — FEMA risk index, seismic design values, wildfires, landslides, coastal vulnerability, flood insurance claims, social vulnerability.
|
|
47
|
+
14. get_energy — Solar resource, PVWatts production estimates, utility rates, EV charging stations.
|
|
48
|
+
15. get_infrastructure — Hospitals, fire stations, schools, power plants, airports, railroad crossings, bridges, historic places.
|
|
49
|
+
16. get_ecology — Species occurrences, essential fish habitat.
|
|
46
50
|
|
|
47
51
|
Every tool uses an "action" parameter to select the specific operation. Read the tool description to see available actions.
|
|
48
52
|
|
|
@@ -66,7 +70,8 @@ IMPORTANT:
|
|
|
66
70
|
- All data from authoritative US federal sources. Always cite the source agency.
|
|
67
71
|
- Responses include _summary with plain-English descriptions — use these in answers.
|
|
68
72
|
- Data is for informational purposes. Remind users to verify for engineering/regulatory decisions.
|
|
69
|
-
- Coordinates must be within the United States (including territories)
|
|
73
|
+
- Coordinates must be within the United States (including territories).
|
|
74
|
+
- API key required. Users can get a free key at https://geotapdata.com/developers (one-click signup).`
|
|
70
75
|
});
|
|
71
76
|
|
|
72
77
|
// ── Shared tool call handler ────────────────────────────────────────
|
package/src/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GeoTap API
|
|
2
2
|
|
|
3
|
-
> Access
|
|
3
|
+
> Access 71 US federal environmental and infrastructure data layers through a single API.
|
|
4
4
|
|
|
5
5
|
GeoTap aggregates real-time data from FEMA, USGS, EPA, NOAA, USDA/NRCS, USFWS, USACE, DOT, and Census Bureau into a unified REST API and MCP server for AI tools.
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@ https://geotapdata.com/api/v1
|
|
|
16
16
|
|
|
17
17
|
## Authentication
|
|
18
18
|
|
|
19
|
-
Include `X-API-Key` header. Get a key at https://geotapdata.com (
|
|
19
|
+
Include `X-API-Key` header. Get a free API key at https://geotapdata.com/developers (one-click signup).
|
|
20
20
|
|
|
21
21
|
## MCP Server
|
|
22
22
|
|
package/src/paramNormalize.js
CHANGED
|
@@ -112,7 +112,66 @@ export function normalizeParams(toolName, params) {
|
|
|
112
112
|
p.geometry = 'none';
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
// ── 3.
|
|
115
|
+
// ── 3. Ungaged estimation: map `parameters` → `basinCharacteristics` ──
|
|
116
|
+
// The MCP tool accepts friendly names (drainageArea, meanBasinSlope)
|
|
117
|
+
// but the backend NSS API expects USGS codes (DRNAREA, BSLDEM)
|
|
118
|
+
if (toolName === 'estimate_ungaged_flood_frequency' ||
|
|
119
|
+
toolName === 'estimate_all_ungaged_statistics') {
|
|
120
|
+
const paramObj = p.parameters || p.characteristics || {};
|
|
121
|
+
if (Object.keys(paramObj).length > 0) {
|
|
122
|
+
// Map friendly names → USGS NSS parameter codes
|
|
123
|
+
const PARAM_MAP = {
|
|
124
|
+
drainageArea: 'DRNAREA',
|
|
125
|
+
contributingDrainageArea: 'CONTDA',
|
|
126
|
+
meanAnnualPrecipitation: 'PRECIP',
|
|
127
|
+
meanBasinSlope: 'BSLDEM',
|
|
128
|
+
percentForest: 'FOREST',
|
|
129
|
+
percentStorage: 'STORAGE',
|
|
130
|
+
percentImpervious: 'IMPERV',
|
|
131
|
+
meanBasinElevation: 'ELEV',
|
|
132
|
+
basinLength: 'BSHAPE',
|
|
133
|
+
annualRunoff: 'RUNOFF',
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const basinChars = {};
|
|
137
|
+
for (const [key, value] of Object.entries(paramObj)) {
|
|
138
|
+
// Use mapped name if available, otherwise pass through as-is
|
|
139
|
+
// (allows users to send DRNAREA directly too)
|
|
140
|
+
const mappedKey = PARAM_MAP[key] || key;
|
|
141
|
+
basinChars[mappedKey] = Number(value);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
p.basinCharacteristics = basinChars;
|
|
145
|
+
delete p.parameters;
|
|
146
|
+
delete p.characteristics;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Also map for find_similar tools
|
|
151
|
+
if (toolName === 'find_similar_watersheds' ||
|
|
152
|
+
toolName === 'find_similar_watersheds_with_stats') {
|
|
153
|
+
const charObj = p.characteristics || p.parameters || {};
|
|
154
|
+
if (Object.keys(charObj).length > 0) {
|
|
155
|
+
const PARAM_MAP = {
|
|
156
|
+
drainageArea: 'DRNAREA',
|
|
157
|
+
contributingDrainageArea: 'CONTDA',
|
|
158
|
+
meanAnnualPrecipitation: 'PRECIP',
|
|
159
|
+
meanBasinSlope: 'BSLDEM',
|
|
160
|
+
percentForest: 'FOREST',
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const mapped = {};
|
|
164
|
+
for (const [key, value] of Object.entries(charObj)) {
|
|
165
|
+
const mappedKey = PARAM_MAP[key] || key;
|
|
166
|
+
mapped[mappedKey] = Number(value);
|
|
167
|
+
}
|
|
168
|
+
p.basinCharacteristics = mapped;
|
|
169
|
+
delete p.characteristics;
|
|
170
|
+
delete p.parameters;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ── 4. Strip undefined/null optional params ──────────────────────
|
|
116
175
|
for (const [key, value] of Object.entries(p)) {
|
|
117
176
|
if (value === undefined || value === null) {
|
|
118
177
|
delete p[key];
|