geotap-mcp-server 1.0.0 → 1.2.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.
package/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # GeoTap Developer
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/geotap-mcp-server.svg)](https://www.npmjs.com/package/geotap-mcp-server)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
3
6
  **One API for 28+ US federal environmental and infrastructure data sources.**
4
7
 
5
8
  GeoTap aggregates data from FEMA, USGS, EPA, NOAA, USDA, USFWS, DOT, Census, and more into a single REST API. This repository contains:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geotap-mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for GeoTap — access 28+ US federal environmental and infrastructure data sources from Claude, Cursor, and other AI tools",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -49,6 +49,6 @@
49
49
  },
50
50
  "repository": {
51
51
  "type": "git",
52
- "url": "https://github.com/jcholly/geotap-mcp-server"
52
+ "url": "https://github.com/jcholly/geotap-developer"
53
53
  }
54
54
  }
package/src/index.js CHANGED
@@ -9,34 +9,39 @@ import { toolSources } from './sources.js';
9
9
 
10
10
  const server = new McpServer({
11
11
  name: 'geotap',
12
- version: '1.0.0',
12
+ version: '1.2.0',
13
13
  description: 'Access 28+ US federal environmental and infrastructure data sources. Query flood zones, wetlands, soils, rainfall, watersheds, water quality, endangered species, elevation, land use, and more for any location in the United States.',
14
14
  instructions: `You have access to GeoTap, which provides real-time data from 28+ US federal agencies (FEMA, USGS, NOAA, EPA, NRCS, USFWS, USACE, and more).
15
15
 
16
- HOW TO USE THESE TOOLS:
17
- - For any US location question, start with geocode_address if the user gives an address (not coordinates).
18
- - Most tools accept lat/lon (or lat/lng). Use WGS84 decimal degrees.
19
- - Combine multiple tools to build a complete picture. For example, to assess a site:
20
- 1. geocode_address get coordinates
21
- 2. get_flood_zones FEMA flood risk
22
- 3. get_wetlands → USFWS wetland boundaries
23
- 4. get_soils NRCS soil type, drainage, hydric rating
24
- 5. get_rainfall_atlas14 → NOAA precipitation data
25
- 6. get_stations_near → nearby USGS/NOAA monitoring stations
26
- 7. get_water_quality_impairments EPA impaired waterways
16
+ START HERE CORE TOOLS (use these for 90% of queries):
17
+ 1. query_address Geocode + environmental lookup in ONE call. Always start here when user gives an address.
18
+ 2. identify_features_at_point Same as above but when you already have lat/lng coordinates.
19
+ 3. get_rainfall_data NOAA Atlas 14 precipitation data for any US location.
20
+ 4. get_environmental_summary Quick feature counts for an area (no geometry, just numbers).
21
+ 5. geocode_address Convert address to coordinates (only needed if query_address doesn't cover your use case).
22
+
23
+ These 5 tools handle most questions. Use specialized tools only when these don't cover the request.
24
+
25
+ RESPONSE SIZE MANAGEMENT:
26
+ - query_address and identify_features_at_point always return <5KB (no geometry, just properties + interpretations).
27
+ - For all other spatial tools, ALWAYS set geometry="none" unless the user specifically needs coordinates.
28
+ - Always specify layers (e.g., layers="flood_zones,wetlands") instead of querying all 19 layers.
29
+ - In urban areas, full-geometry responses can exceed 1MB. Geometry="none" reduces this to <10KB.
27
30
 
28
31
  COMMON WORKFLOWS:
29
- - "Is this a good place to build?" → flood zones + wetlands + soils + constraints
30
- - "What's the flood risk?" → flood zones + rainfall + nearby stream gauges
31
- - "Environmental due diligence" → flood zones + wetlands + contamination + critical habitat + water quality
32
+ - "What flood zone is this address in?" → query_address (one call, done)
33
+ - "Is this a good place to build?" → query_address get_rainfall_data get_environmental_summary
34
+ - "Environmental due diligence" → query_address (covers flood, wetlands, soils, contamination, habitat)
35
+ - "What's the 100-year rainfall?" → get_rainfall_data
32
36
  - "Hydrology analysis" → watershed delineate + curve numbers + rainfall + peak flow
33
- - "Export data" → query the layers you need, then use the export tool for GeoJSON/Shapefile/CSV/KML
37
+ - "Export data" → query layers, then export tool for GeoJSON/Shapefile/CSV/KML
34
38
 
35
39
  IMPORTANT NOTES:
36
- - All data comes from authoritative federal sources. Always mention the source agency when presenting results.
37
- - This data is for informational purposes. Remind users to verify critical data before making engineering or regulatory decisions.
40
+ - All data comes from authoritative federal sources. Always mention the source agency.
41
+ - Responses include _interpretation fields with plain-English summaries use these in your answers.
42
+ - This data is for informational purposes. Remind users to verify critical data for engineering/regulatory decisions.
38
43
  - Coordinates must be within the United States (including territories).
39
- - Some tools (watershed delineation, hydrology) can take 10-60 seconds for complex areas.
44
+ - Some tools (watershed delineation, hydrology) can take 10-60 seconds.
40
45
  - Layer names use underscores: flood_zones, wetlands, dem_elevation, building_footprints, etc.`
41
46
  });
42
47
 
package/src/sources.js CHANGED
@@ -63,6 +63,8 @@ const MULTI_SOURCE = [
63
63
  */
64
64
  export const toolSources = {
65
65
  // ── Spatial Queries ──
66
+ query_address: MULTI_SOURCE,
67
+ identify_features_at_point: MULTI_SOURCE,
66
68
  get_environmental_data_for_area: MULTI_SOURCE,
67
69
  get_environmental_data_near_point: MULTI_SOURCE,
68
70
  get_environmental_summary: MULTI_SOURCE,
package/src/tools.js CHANGED
@@ -17,27 +17,50 @@ export const tools = [
17
17
  // ═══════════════════════════════════════════════════════════════════
18
18
  // SPATIAL QUERIES — Query environmental data by geography
19
19
  // ═══════════════════════════════════════════════════════════════════
20
+ {
21
+ name: 'query_address',
22
+ description: `The recommended starting tool for most queries. Geocodes a US address AND queries environmental data at that location in a single call. Returns flood zones, wetlands, soils, critical habitat, contamination sites, and more — with plain-English interpretations (e.g., "High-risk flood zone. Flood insurance required."). No geometry in response — just properties and interpretations. Response is always small (<5KB). Use this FIRST when the user provides an address. Only use geocode_address separately if you need coordinates for other tools.`,
23
+ parameters: {
24
+ address: z.string().describe('US street address (e.g., "123 Main St, Houston TX")'),
25
+ layers: z.string().optional().describe('Comma-separated layer names. Defaults to: flood_zones, wetlands, soil_map_units, critical_habitat, protected_lands, brownfields, superfund, npdes_outfalls, sole_source_aquifers')
26
+ },
27
+ endpoint: '/query-address',
28
+ method: 'GET'
29
+ },
30
+ {
31
+ name: 'identify_features_at_point',
32
+ description: `Identify what environmental features exist at an exact lat/lng point. Returns ONLY properties (no geometry) with plain-English interpretations. Response is always small (<5KB). Use this when you already have coordinates. For addresses, use query_address instead (it geocodes + queries in one call). Returns flood zones, wetlands, soils, critical habitat, protected lands, brownfields, Superfund, NPDES outfalls, and sole source aquifers by default.`,
33
+ parameters: {
34
+ lat: z.number().describe('Latitude (WGS84)'),
35
+ lng: z.number().describe('Longitude (WGS84)'),
36
+ layers: z.string().optional().describe('Comma-separated layer names (e.g., "flood_zones,wetlands,soil_map_units"). Defaults to key regulatory layers.')
37
+ },
38
+ endpoint: '/spatial/point',
39
+ method: 'GET'
40
+ },
20
41
  {
21
42
  name: 'get_environmental_data_for_area',
22
- description: `Query all available US federal environmental and infrastructure data within a geographic area (polygon). Returns features from 28+ data sources including FEMA flood zones, NWI wetlands, USDA soils, USGS geology, EPA sites (Superfund, brownfields, TRI), USFWS critical habitat, DOT bridges, power plants, dams, mines, and more. Use this tool when someone asks about environmental conditions, site constraints, development feasibility, or regulatory concerns for a specific area. Accepts a GeoJSON polygon (e.g., a property boundary, project site, or any area of interest). This is the most comprehensive tool it returns everything available for the given area.`,
43
+ description: `Query all available US federal environmental and infrastructure data within a geographic area (polygon). Returns features from 28+ data sources. WARNING: responses can be very large (100KB-2MB+) in urban areas with full geometry. ALWAYS set geometry="none" unless the user specifically needs coordinates. Specify layers to reduce response size. For simple "what's at this location?" questions, use query_address or identify_features_at_point insteadthey're faster and return <5KB.`,
23
44
  parameters: {
24
45
  polygon: z.object({
25
46
  type: z.literal('Polygon'),
26
47
  coordinates: z.array(z.array(z.array(z.number())))
27
48
  }).describe('GeoJSON Polygon geometry defining the area of interest'),
28
- layers: z.array(z.string()).optional().describe('Optional array of specific layer names to query. If omitted, all layers are queried.')
49
+ layers: z.array(z.string()).optional().describe('Optional array of specific layer names to query. If omitted, all layers are queried.'),
50
+ geometry: z.enum(['none', 'simplified', 'full']).optional().describe('Geometry detail: "none" strips coordinates (smallest response), "simplified" reduces density, "full" returns complete geometry. Default: full. Use "none" when you only need properties.')
29
51
  },
30
52
  endpoint: '/spatial/in-polygon',
31
53
  method: 'POST'
32
54
  },
33
55
  {
34
56
  name: 'get_environmental_data_near_point',
35
- description: `Query all available US federal environmental and infrastructure data near a specific point (latitude/longitude). Returns features within a given radius from 28+ data sources including FEMA flood zones, NWI wetlands, USDA soils, USGS geology, EPA sites, endangered species habitat, bridges, dams, and more. Use this tool when someone asks "what's near this location?" or provides an address/coordinates and wants to know about environmental conditions in the vicinity. Great for quick site screening.`,
57
+ description: `Query environmental data near a lat/lng point within a radius. WARNING: responses can be very large (50KB-1MB+) with default settings. ALWAYS set geometry="none" and specify layers to keep responses manageable. For "what's AT this exact location?" use identify_features_at_point or query_address instead they return <5KB. Only use this tool when the user specifically needs data within a radius (e.g., "what EPA sites are within 2 miles?").`,
36
58
  parameters: {
37
59
  lat: z.number().describe('Latitude of the center point (WGS84)'),
38
60
  lng: z.number().describe('Longitude of the center point (WGS84)'),
39
- radius: z.number().optional().describe('Search radius in kilometers (default: 1)'),
40
- layers: z.string().optional().describe('Comma-separated layer names to query. If omitted, all layers are queried.')
61
+ radius: z.number().optional().describe('Search radius in kilometers (min: 0.01, default: 1)'),
62
+ layers: z.string().optional().describe('Comma-separated layer names to query. If omitted, all layers are queried.'),
63
+ geometry: z.enum(['none', 'simplified', 'full']).optional().describe('Geometry detail: "none" strips coordinates (smallest response), "simplified" reduces density, "full" returns complete geometry. Default: full. Use "none" when you only need properties.')
41
64
  },
42
65
  endpoint: '/spatial/near',
43
66
  method: 'GET'
@@ -57,10 +80,11 @@ export const tools = [
57
80
  },
58
81
  {
59
82
  name: 'get_environmental_data_in_bbox',
60
- description: `Query environmental data within a bounding box. Simpler than polygon query just provide west, south, east, north coordinates. Returns features from specified layers. Good for quick rectangular area searches when you don't have an exact polygon boundary.`,
83
+ description: `Query environmental data within a bounding box. WARNING: responses can be very large with full geometry. Set geometry="none" and specify layers to keep responses small. For point lookups, use identify_features_at_point instead.`,
61
84
  parameters: {
62
85
  bbox: z.string().describe('Bounding box as "west,south,east,north" in WGS84 coordinates'),
63
- layers: z.string().optional().describe('Comma-separated layer names to query')
86
+ layers: z.string().optional().describe('Comma-separated layer names to query'),
87
+ geometry: z.enum(['none', 'simplified', 'full']).optional().describe('Geometry detail: "none" strips coordinates (smallest response), "simplified" reduces density, "full" returns complete geometry. Default: full.')
64
88
  },
65
89
  endpoint: '/spatial/bbox',
66
90
  method: 'GET'
@@ -90,7 +114,8 @@ export const tools = [
90
114
  description: `Get features from a specific data layer within a bounding box. Use this tool when you need data from one specific source (e.g., just flood zones, or just wetlands) rather than all sources at once.`,
91
115
  parameters: {
92
116
  layerName: z.string().describe('The layer identifier (e.g., "flood_zones", "wetlands", "dem_elevation", "nlcd_land_cover", "contours", "building_footprints", "stream_gauges", "tide_stations", "weather_alerts", "air_quality")'),
93
- bbox: z.string().describe('Bounding box as "west,south,east,north" in WGS84 coordinates')
117
+ bbox: z.string().describe('Bounding box as "west,south,east,north" in WGS84 coordinates'),
118
+ geometry: z.enum(['none', 'simplified', 'full']).optional().describe('Geometry detail: "none" strips coordinates (smallest response), "simplified" reduces density, "full" returns complete geometry. Default: full.')
94
119
  },
95
120
  endpoint: '/layers/{layerName}/features',
96
121
  method: 'GET'