Skip to main content

🌍 Geospatial MCP Server

PyPI version License: MIT Python 3.10+ MCP Standard Tests

A zero-dependency (no GDAL/C++ build hell) Model Context Protocol (MCP) server that equips AI Agents (Claude, Cursor, Antigravity) with deterministic spatial analysis, GeoJSON auto-repair, and accurate projected metric calculations.

Topology Auto-Repair Comparison

Demo


⚡ The Problem It Solves

Large Language Models (LLMs) are notoriously bad at spatial reasoning and Cartesian mathematics:

  • Geometry Hallucination: Self-intersecting polygons (bow-tie / figure-8 errors) and unclosed coordinate rings crash downstream GIS pipelines and map renderers.
  • Scale Distortion: Treating spherical WGS84 geographic coordinates (latitude/longitude degrees) as flat Euclidean planes results in catastrophic area and perimeter errors (often 30% to 500% off depending on latitude).
  • Topology Blindness: Inability to deterministically resolve point-in-polygon containment, spatial intersection surfaces, separation distances, and metric buffering.

geospatial-mcp bridges this gap by providing a lightweight, high-performance, GEOS-backed C-extension engine without heavy GIS infrastructure overhead.


🚀 Quickstart (30 Seconds)

Option 1: Run with UVX (Recommended, Zero Install)

No local repository clone or manual environment setup required:

{
  "mcpServers": {
    "geospatial": {
      "command": "uvx",
      "args": ["geospatial-mcp"]
    }
  }
}

Option 2: Local Installation & Development

  1. Clone and create virtual environment:

    git clone https://github.com/your-org/geospatial-mcp.git
    cd geospatial-mcp
    
    python -m venv .venv
    # Windows (PowerShell):
    .\.venv\Scripts\Activate.ps1
    # Linux / macOS:
    source .venv/bin/activate
    
  2. Install package in editable mode:

    pip install -e .
    pip install pytest
    
  3. Configure MCP Client (Claude Desktop / Cursor / Antigravity):

    {
      "mcpServers": {
        "geospatial": {
          "command": "python",
          "args": ["-m", "geospatial_mcp.server"],
          "cwd": "/path/to/geospatial-mcp"
        }
      }
    }
    

🛠️ Tools Reference

All tools are exposed via standard MCP transports (stdio) and feature robust input tolerance: they natively accept standard GeoJSON strings, raw coordinate arrays, GeoJSON dictionaries, Feature / FeatureCollection objects, and Markdown-wrapped JSON (```json) without crashing.

1. validate_and_repair_geometry

Validates topological compliance against OGC Simple Features standards. If topological defects exist (e.g., self-intersecting bow-tie polygons or unclosed linear rings), it extracts the exact cause of failure and automatically heals the geometry into a compliant GeoJSON object with RFC 7946 normalized ring winding.

  • Parameters:
    • geojson (str | dict | list, required): GeoJSON geometry, Feature, FeatureCollection, or raw coordinate array.
  • Returns:
    • is_valid (bool): Whether the original geometry was topologically valid.
    • error_reason (str | null): Exact topological defect description if invalid (e.g. Self-intersection[1 1] or Points of LinearRing do not form a closed linestring).
    • repaired_geojson (dict | null): Compliant, self-healed GeoJSON geometry.

Example Call

{
  "name": "validate_and_repair_geometry",
  "arguments": {
    "geojson": {
      "type": "Polygon",
      "coordinates": [[[0, 0], [2, 2], [2, 0], [0, 2], [0, 0]]]
    }
  }
}

Response

{
  "is_valid": false,
  "error_reason": "Self-intersection[1 1]",
  "repaired_geojson": {
    "type": "MultiPolygon",
    "coordinates": [
      [[[0.0, 0.0], [1.0, 1.0], [0.0, 2.0], [0.0, 0.0]]],
      [[[1.0, 1.0], [2.0, 0.0], [2.0, 2.0], [1.0, 1.0]]]
    ]
  }
}

2. calculate_accurate_metrics

Eliminates spherical degree distortion by deriving the optimal local UTM projection zone (EPSG:32601-32660 for Northern hemisphere or EPSG:32701-32760 for Southern hemisphere) from the polygon centroid, projecting to a planar Cartesian coordinate system via PyProj, and calculating distortion-free surface area and perimeter.

  • Parameters:
    • geojson (str | dict | list, required): Polygon or MultiPolygon GeoJSON.
    • unit / target_unit (str, optional, default "sq_meters"): Desired unit ("sq_meters", "sq_kilometers", or "hectares"). Fully backwards-compatible with dual alias parsing.
  • Returns:
    • area (float): Planar area in the requested unit.
    • perimeter_meters (float): Total boundary length in meters.
    • unit (str): Target unit used.
    • projected_epsg (int): EPSG integer code of the metric UTM projection applied (e.g. 32651).

Example Call

{
  "name": "calculate_accurate_metrics",
  "arguments": {
    "geojson": {
      "type": "Polygon",
      "coordinates": [[[121.47, 31.23], [121.48, 31.23], [121.48, 31.24], [121.47, 31.24], [121.47, 31.23]]]
    },
    "unit": "hectares"
  }
}

Response

{
  "area": 105.74,
  "perimeter_meters": 4118.62,
  "unit": "hectares",
  "projected_epsg": 32651
}

3. check_spatial_relationship

Evaluates topological relationship predicates between two geometries (contains, within, intersects, disjoint). Automatically returns the shared intersection area in $m^2$ if overlapping, or the minimum metric separation distance in meters if disjoint.

  • Parameters:
    • geom_a (str | dict | list, required): First spatial object.
    • geom_b (str | dict | list, required): Second spatial object.
    • predicate (str, optional, default "intersects"): Predicate to evaluate ("contains", "within", "intersects", "disjoint").
  • Returns:
    • result (bool): Boolean verdict for the requested predicate.
    • details (dict): Quantitative measurements including intersection_area_sq_meters, distance_meters, and projected_epsg.

Example Call

{
  "name": "check_spatial_relationship",
  "arguments": {
    "geom_a": {"type": "Polygon", "coordinates": [[[0, 0], [2, 0], [2, 2], [0, 2], [0, 0]]]},
    "geom_b": {"type": "Polygon", "coordinates": [[[1, 1], [3, 1], [3, 3], [1, 3], [1, 1]]]},
    "predicate": "intersects"
  }
}

Response

{
  "result": true,
  "details": {
    "predicate": "intersects",
    "projected_epsg": 32631,
    "intersection_area_sq_meters": 12285149372.45,
    "distance_meters": 0.0
  }
}

4. generate_buffer

Constructs an accurate metric buffer (expansion or erosion) in the local UTM coordinate system, auto-heals any resulting self-intersections, and projects back to standard EPSG:4326 WGS84 GeoJSON.

  • Parameters:
    • geojson (str | dict | list, required): Input geometry.
    • distance_meters (float, required): Buffer radius in meters (positive expands, negative erodes).
    • quad_segs (int, optional, default 8): Quadrant segments for circular arc approximation.
  • Returns:
    • buffered_geojson (dict | null): Normalized RFC 7946 GeoJSON dictionary in EPSG:4326.

Example Call

{
  "name": "generate_buffer",
  "arguments": {
    "geojson": {"type": "Point", "coordinates": [121.5, 31.2]},
    "distance_meters": 500.0,
    "quad_segs": 16
  }
}

🏗️ Architecture & Project Structure

geospatial-mcp is designed to be completely decoupled from bulky C/C++ GIS frameworks:

geospatial-mcp/
├── pyproject.toml              # Hatchling packaging and dependency constraints
├── README.md                   # Complete architectural guide and tool references
├── src/
│   └── geospatial_mcp/
│       ├── __init__.py         # Package root
│       ├── server.py           # FastMCP service instance & tool entrypoints
│       ├── core/               # Pure C-extension geometry engine
│       │   ├── __init__.py
│       │   ├── projection.py   # Dynamic UTM zone deduction & CRS reprojector
│       │   └── geometry.py     # Topology validation, metric calculations, relations & buffer
│       └── models.py           # Pydantic v2 schemas (unit / target_unit alias support)
└── tests/
    ├── __init__.py
    ├── test_geometry.py        # Core geometry, projection, bowtie repair, equator tests
    └── test_server.py          # FastMCP tool invocation, input tolerance, & error tests

Why Zero GDAL?

Traditional GIS tools bundle GDAL, PROJ C libraries, and Python wrappers (Fiona, GeoPandas) that create:

  • Massive container image sizes (> 1.5 GB).
  • Platform-dependent C++ build failures and DLL hell on Windows / macOS.
  • Potential process segmentation faults during concurrent execution.

geospatial-mcp uses pure shapely>=2.0 (which packages standalone GEOS C libraries as pre-compiled wheels) and pyproj. It installs in seconds via pip or uvx with zero compilation steps.


🛡️ Fault Tolerance & Defensive Engineering

  1. Unclosed Linear Rings: In RFC 7946, polygon exterior and interior rings must be closed (first coordinate identical to last coordinate). If an unclosed ring is passed, the engine flags it (is_valid=False), describes the error, and automatically closes the ring during repair.
  2. Malformed JSON / Syntax Errors: Broken JSON strings, unclosed brackets, or invalid geometry types return structured, friendly JSON error responses with diagnostic hints rather than crashing the MCP server.
  3. Hemisphere & Longitude Aware: Automatically maps any coordinate on Earth into its corresponding UTM Zone (1 through 60) and applies EPSG:326xx for $lat \ge 0^\circ$ (North) and EPSG:327xx for $lat < 0^\circ$ (South), with seamless handling for geometries crossing the equator.
  4. Dual Access Output Models: All output objects implement BaseResultModel, permitting both object attribute access (res.area) and dictionary key access (res['area']).

🧪 Testing & Verification

The suite includes 20 comprehensive unit tests covering critical GIS boundary scenarios:

# Run tests with pytest
pytest -v

Verified Scenarios

  • Bow-tie Self-Intersection Repair: Resolves figure-8 polygons into valid OGC MultiPolygons.
  • Unclosed Ring Auto-Healing: Detects unclosed coordinate arrays and normalizes them.
  • Equator Crossing & Multi-Longitude UTM: Precision reprojection across latitude $0^\circ$ and longitudinal zones (Shanghai UTM 51N, Rio de Janeiro UTM 23S).
  • Unit Conversions: Metric validation across square meters, square kilometers, and hectares.
  • Spatial Predicates: Accurate metric distance on separation, intersection surface area on overlap.
  • Parameter Alias Compatibility: Identical resolution whether calling with unit or target_unit.
  • Stdio Protocol Handshake: Seamless MCP initialize JSON-RPC handshake verification.

📄 License

MIT License. Free for open-source and commercial use.

Metadata

Release files for geospatial-mcp 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for geospatial-mcp 0.1.0
File Size Uploaded
geospatial_mcp-0.1.0.tar.gz 415.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for geospatial-mcp 0.1.0
File Interpreter ABI Platform
geospatial_mcp-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 432.5 kB

Release files / geospatial_mcp-0.1.0.tar.gz

Download URL geospatial_mcp-0.1.0.tar.gz
Size 415.8 kB
Tags Source
SHA-256 checksum
How to use checksums
161ab3421051b9fc9924dc1ff06d9dbe2ececa175140303b685275503beebecf
BLAKE2b-256 checksum
How to use checksums
88f877cf4346f1b55cef3620e932b70a98a8960747c190c314873b6c7eaba301
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / geospatial_mcp-0.1.0-py3-none-any.whl

Download URL geospatial_mcp-0.1.0-py3-none-any.whl
Size 16.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f60df3b40a609d9e30c74c0fecfacb7ad533e2d673eb8f4ca258ad3234f9652e
BLAKE2b-256 checksum
How to use checksums
3025d4de6174b66bfbad68411b1ef98846f0c85f7483de4042fede4f948f8957
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page