Skip to main content
Glama
tonybentley

ENC Charts MCP Server

by tonybentley
README.md
# ENC Charts MCP Server

[![npm version](https://badge.fury.io/js/enc-charts-mcp.svg)](https://www.npmjs.com/package/enc-charts-mcp)

An MCP (Model Context Protocol) server for Electronic Navigational Charts (ENC) data, providing programmatic access to NOAA electronic navigational charts with S-57 format parsing capabilities.

## Overview

This MCP server enables AI assistants to access and analyze electronic navigational charts from NOAA. It automatically downloads, caches, and parses S-57 format chart data, making it available through a standardized API. The server supports coordinate-based chart discovery, feature extraction, and navigation-focused queries.

## Features

- **S-57 Chart Parsing**: Full support for IHO S-57 format electronic navigational charts
- **NOAA Integration**: Automatic chart discovery and downloading from NOAA REST APIs
- **Coordinate-Based Queries**: Find and retrieve charts based on GPS coordinates
- **Smart Caching**: Efficient local caching with configurable size and age limits
- **Feature Filtering**: Extract specific navigation features (lights, buoys, depths, etc.)
- **172 Object Classes**: Complete support for S-57 object catalog
- **Depth Analysis**: Filter features by depth ranges for navigation safety
- **Spatial Queries**: Bounding box filtering for area-specific data

## Prerequisites

- **Node.js**: Version 18 or higher
- **Python**: Version 3.7 or higher (for S-57 parsing)
- **GDAL Python Bindings**: Required for chart data parsing

## Installation

Install the MCP server globally via npm:

```bash
npm install -g enc-charts-mcp
```

### Installing GDAL Dependencies

The server requires GDAL Python bindings for S-57 chart parsing:

**macOS:**
```bash
# Using Homebrew
brew install gdal
pip3 install gdal==$(gdal-config --version)
```

**Ubuntu/Debian:**
```bash
sudo apt-get update
sudo apt-get install gdal-bin libgdal-dev
pip3 install gdal==$(gdal-config --version)
```

**Windows:**
```bash
# Using conda (recommended)
conda install -c conda-forge gdal
```

### Verify Installation

```bash
# Check if the server is installed
enc-charts-mcp --version

# Test GDAL availability
python3 -c "from osgeo import ogr; print('GDAL installed successfully')"
```

## Configuration

### Environment Variables

The server supports the following environment variables:

| Variable | Description | Default |
|----------|-------------|---------|
| `ENC_CACHE_DIR` | Directory for chart cache | `./cache/charts/` |
| `ENC_CACHE_MAX_SIZE_GB` | Maximum cache size in GB | `10` |
| `ENC_CACHE_MAX_AGE_DAYS` | Cache expiration in days | `7` |

### Claude Desktop Integration

Add the following to your Claude Desktop configuration file:

**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`  
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "enc-charts": {
      "command": "npx",
      "args": ["enc-charts-mcp"],
      "transport": {
        "type": "stdio"
      },
      "env": {
        "ENC_CACHE_DIR": "~/.enc-charts/cache",
        "ENC_CACHE_MAX_SIZE_GB": "20",
        "ENC_CACHE_MAX_AGE_DAYS": "14"
      }
    }
  }
}
```

**Note:** Adjust the cache directory path based on your preferences. The server will automatically create the directory if it doesn't exist.

## Quick Start

After installation and configuration, restart Claude Desktop. You can then use the ENC charts tools in your conversations:

1. **Find charts for a location:**
   ```
   Use the get_chart tool with coordinates: 
   lat: 37.8, lon: -122.5 (San Francisco Bay)
   ```

2. **Search for charts in an area:**
   ```
   Use search_charts with a bounding box to find all charts 
   between San Diego and Los Angeles
   ```

3. **Get navigation features:**
   ```
   Get all lights and buoys from chart US5CA12M
   ```

## Available Tools

### get_chart

Retrieve chart features for a specific area by chart ID or coordinates.

**Parameters:**
- `chartId` (string, optional): Chart identifier (e.g., "US5CA12M")
- `coordinates` (object, optional): GPS coordinates
  - `lat` (number): Latitude (-90 to 90)
  - `lon` (number): Longitude (-180 to 180)
- `boundingBox` (object, optional): Geographic bounds filter
  - `minLat`, `maxLat`, `minLon`, `maxLon` (numbers)
- `featureTypes` (array, optional): S-57 object classes to include
- `depthRange` (object, optional): Depth filter in meters
  - `min`, `max` (numbers)
- `includeNearby` (boolean, optional): Include nearby features
- `limit` (integer, optional): Maximum features to return (default: 100, max: 1000)
- `offset` (integer, optional): Number of features to skip for pagination (default: 0)

**Example Request:**
```json
{
  "coordinates": { "lat": 37.8, "lon": -122.5 },
  "featureTypes": ["LIGHTS", "BOYLAT", "DEPARE"],
  "depthRange": { "min": 0, "max": 20 }
}
```

**Example Response:**
```json
{
  "chartId": "US5CA12M",
  "features": [
    {
      "id": "LIGHTS.123",
      "type": "LIGHTS",
      "geometry": {
        "type": "Point",
        "coordinates": [-122.5295, 37.8156]
      },
      "properties": {
        "COLOUR": ["1"],
        "LITCHR": 8,
        "SIGPER": 4,
        "VALNMR": 18
      }
    }
  ],
  "featureCount": 42,
  "totalFeatures": 150,
  "hasMore": true,
  "limit": 100,
  "offset": 0,
  "source": "NOAA ENC"
}
```

### search_charts

Search available charts by various criteria.

**Parameters:**
- `query` (string, optional): Search by name or area
- `scale` (object, optional): Scale range filter
  - `min`, `max` (numbers)
- `boundingBox` (object, optional): Geographic search area
- `format` (string, optional): Chart format ("S-57" or "S-101")
- `limit` (integer, optional): Maximum charts to return (default: 50, max: 100)
- `offset` (integer, optional): Number of charts to skip for pagination (default: 0)

### get_chart_metadata

Get detailed information about a specific chart.

**Parameters:**
- `chartId` (string, optional): Chart identifier
- `coordinates` (object, optional): GPS coordinates to find chart

### get_object_classes

Get information about S-57 object classes and their representations.

**Parameters:**
- `category` (string, optional): Filter by category
  - Options: "navAids", "depths", "areas", "infrastructure", "natural", "hazards"
- `search` (string, optional): Search by acronym or description
- `includeAttributes` (boolean, optional): Include standard attributes


## Data Sources

### NOAA ENC Online

The server integrates with NOAA's Electronic Navigational Chart services:

- **XML Product Catalog**: Charts metadata from `https://www.charts.noaa.gov/ENCs/ENCProdCat.xml`
- **Chart Downloads**: Individual S-57 format ZIP files from `https://www.charts.noaa.gov/ENCs/`
- **Update Frequency**: Weekly for most charts
- **Coverage**: US waters and territories
- **No Authentication Required**: All NOAA resources are publicly accessible

Charts are automatically downloaded on-demand when queried by coordinates and cached locally for performance. The XML catalog is cached for 24 hours to reduce API calls.

## How It Works

1. **Chart Discovery**: The server queries NOAA's XML product catalog to find charts based on coordinates or search criteria
2. **Automatic Download**: Charts are downloaded on-demand from NOAA when requested
3. **Local Caching**: Downloaded charts are cached locally to improve performance
4. **S-57 Parsing**: Chart data is parsed from S-57 format using GDAL Python bindings
5. **Feature Extraction**: Navigation features (lights, buoys, depths, etc.) are extracted and returned as GeoJSON

## S-57 Object Classes

The server supports all 172 standard S-57 object classes. Key categories include:

### Navigation Aids
- `LIGHTS` - All lighted aids (lighthouses, beacons, lit buoys)
- `BOYLAT` - Lateral buoys (port/starboard markers)
- `BOYSAW` - Safe water buoys
- `BCNLAT` - Lateral beacons
- `DAYMAR` - Day marks

### Depth Information
- `DEPARE` - Depth areas with ranges
- `DEPCNT` - Depth contour lines
- `SOUNDG` - Individual soundings
- `DRGARE` - Dredged areas

### Areas & Boundaries
- `FAIRWY` - Navigation channels
- `ANCHRG` - Anchorage areas
- `RESARE` - Restricted areas
- `TSSLPT` - Traffic separation schemes

### Hazards
- `OBSTRN` - Underwater obstructions
- `WRECKS` - Shipwrecks
- `ROCKS` - Rocks and reefs

## Usage Tips

### Efficient Chart Queries

1. **Use Feature Filtering**: Specify `featureTypes` to reduce response size
2. **Apply Bounding Boxes**: Limit geographic scope when possible
3. **Leverage Pagination**: Use `limit` and `offset` for large datasets
4. **Cache Warming**: Frequently accessed areas benefit from pre-downloading

### Common Feature Types

- **Navigation Aids**: `LIGHTS`, `BOYLAT`, `BOYSAW`, `BCNLAT`
- **Depths**: `DEPARE`, `DEPCNT`, `SOUNDG`
- **Hazards**: `OBSTRN`, `WRECKS`, `ROCKS`
- **Areas**: `FAIRWY`, `ANCHRG`, `RESARE`

## Common Use Cases

### 1. Navigation Planning

Find charts and extract navigation aids for route planning:

```json
// Get charts for Golden Gate area
{
  "coordinates": { "lat": 37.8199, "lon": -122.4783 },
  "featureTypes": ["LIGHTS", "BOYLAT", "BOYSAW", "BCNLAT"],
  "includeNearby": true
}
```

### 2. Anchorage Analysis

Find suitable anchoring spots with depth information:

```json
// Search for anchorages with specific depth range
{
  "chartId": "US5CA12M",
  "featureTypes": ["DEPARE", "ANCHRG", "SOUNDG"],
  "depthRange": { "min": 5, "max": 15 },
  "boundingBox": {
    "minLat": 37.8,
    "maxLat": 37.82,
    "minLon": -122.52,
    "maxLon": -122.5
  }
}
```

### 3. Hazard Detection

Identify navigation hazards in an area:

```json
// Get all hazards near a route
{
  "coordinates": { "lat": 32.7157, "lon": -117.1611 },
  "featureTypes": ["OBSTRN", "WRECKS", "ROCKS", "UWTROC"],
  "includeNearby": true
}
```

### 4. Chart Discovery

Find all available charts for a region:

```json
// Search charts between San Diego and Los Angeles
{
  "boundingBox": {
    "minLat": 32.5,
    "maxLat": 34.0,
    "minLon": -118.5,
    "maxLon": -117.0
  },
  "scale": { "max": 50000 }  // Detailed charts only
}
```

## Troubleshooting

### GDAL Installation Issues

**"GDAL Python bindings not found"**
- Ensure Python 3 is in your PATH
- Match GDAL versions exactly: `pip install gdal==$(gdal-config --version)`
- On macOS, use Homebrew: `brew install gdal`
- On Windows, use conda for easier installation

**"Failed to parse S-57 chart data"**
- Verify GDAL is properly installed: `python3 -c "from osgeo import ogr"`
- Check that Python 3 is in your PATH (the server specifically uses `python3`)
- Some charts may require newer GDAL versions
- Run `npm run gdal:validate` to check your installation

### Claude Desktop Issues

**Server not appearing in Claude**
1. Ensure the package is installed: `npm list -g enc-charts-mcp`
2. Check your config file path is correct
3. Restart Claude Desktop after configuration changes
4. Verify the npx command works: `npx enc-charts-mcp --version`

**"No charts found for coordinates"**
- Verify coordinates are in US waters (NOAA coverage area)
- Check internet connection for NOAA API access
- Try different coordinates or use a known chart ID

### Cache Issues

**Clearing the cache**
```bash
# Default cache location
rm -rf ~/.enc-charts/cache/*

# Or your custom cache directory
rm -rf $ENC_CACHE_DIR/*
```

**Disk space issues**
- Adjust `ENC_CACHE_MAX_SIZE_GB` in your config
- Charts can be 10-100MB each
- Consider storing cache on a drive with more space

## Development

### Running Locally

```bash
# Clone the repository
git clone https://github.com/tonybentley/enc-charts-mcp.git
cd enc-charts-mcp

# Install dependencies
npm install

# Build the project
npm run build

# Run in development mode (with hot reload)
npm run dev

# Run production build
npm start
```

### Development Commands

- `npm run dev` - Run in development mode with hot reload
- `npm run build` - Build TypeScript to JavaScript
- `npm run test` - Run unit tests
- `npm run test:e2e` - Run end-to-end tests
- `npm run test:all` - Run all test suites
- `npm run lint` - Run ESLint
- `npm run typecheck` - Run TypeScript type checking
- `npm run format` - Format code with Prettier

### GDAL Validation

- `npm run gdal:detect` - Check if GDAL is properly installed
- `npm run gdal:validate` - Validate GDAL installation and environment
- `npm run test:integration:check` - Verify GDAL before running integration tests

## Performance Considerations

- Charts can be 10-100MB each
- Initial downloads may take time
- Cache warming recommended for frequently accessed areas
- Spatial queries optimized for bounding boxes

### Pagination

To prevent response size issues, the `get_chart` and `search_charts` tools implement pagination:

- **get_chart**: Returns up to 100 features by default (max: 1000)
- **search_charts**: Returns up to 50 charts by default (max: 100)

Use the `limit` and `offset` parameters to page through large result sets:

```json
// First page
{ "chartId": "US5CA12M", "limit": 100, "offset": 0 }

// Next page
{ "chartId": "US5CA12M", "limit": 100, "offset": 100 }
```

The response includes pagination metadata:
- `totalFeatures` or `totalCount`: Total number of available items
- `hasMore`: Boolean indicating if more results exist
- `limit`: Number of items returned
- `offset`: Number of items skipped

## License

ISC

## Source Code

The source code is available on [GitHub](https://github.com/tonybentley/enc-charts-mcp).

## Contributing

Contributions are welcome! Please open an issue or submit a pull request on GitHub.

## Acknowledgments

- NOAA for providing free electronic navigational charts
- IHO for the S-57 standard specification
- GDAL contributors for S-57 format support