Skip to main content
Glama

stac-eo-mcp

CI PyPI Python License: MIT MCP server Downloads Ruff uv

An MCP server that lets AI agents (Claude Desktop, Claude Code, Cursor) search satellite imagery in STAC catalogs and measure vegetation, water and burn indices on Sentinel-2 scenes, without downloading whole images.

Ask "How green was Villa Borghese in Rome during 2025?" and the agent finds the scenes, reads only the pixels inside your area, masks clouds and answers with numbers, a map and a trend.

Features

  • Two public catalogs: Microsoft Planetary Computer (assets signed automatically) and Element84 Earth Search. No account or API key needed.

  • Windowed reads: only the bbox is read from Cloud-Optimized GeoTIFFs with odc-stac, at 10 m in the scene's UTM grid.

  • Correct reflectance: applies the Sentinel-2 processing baseline 04.00 offset (−1000 DN), from asset metadata when present, otherwise from the baseline. Both catalogs give identical numbers for the same scene.

  • Cloud masking with SCL, reported as valid_pixel_pct. Tile cloud cover often differs from your area (a "9.7% cloudy" tile can be 100% cloudy over your bbox), so this matters.

  • LLM-friendly output: statistics, dates and file paths only; never raster arrays. Footprints are simplified. Errors say what went wrong and what to try next.

  • Safe by default: area and scene-count limits stop accidental large downloads.

Related MCP server: groundstation

Tools

Tool

What it does

list_collections(catalog?)

Collections in a catalog, with one-sentence descriptions

search_scenes(collection, bbox, date_range, max_cloud_cover?, limit?, catalog?)

Scenes newest first: id, date, cloud cover, footprint, preview link

get_scene_details(collection, item_id, catalog?)

Key metadata and the list of assets

compute_index(item_id, index, bbox, save?, catalog?)

NDVI / NDWI / NBR on one scene: min, max, mean, std, % valid pixels; optional PNG / GeoTIFF

time_series(index, bbox, date_range, max_cloud_cover?, catalog?)

Mean index per acquisition date, cloudy dates skipped with a reason, plus a trend summary

Resources: stac://indices (formulas, bands, interpretation, cloud mask classes) and stac://catalogs (catalogs, defaults and limits). Prompt: analyze_vegetation(bbox, months=6), a guided vegetation analysis.

Conventions: bbox is [west, south, east, north] in WGS84 degrees; date_range is "YYYY-MM-DD/YYYY-MM-DD".

Install

Requires uv. The server runs locally over stdio; nothing to deploy.

uvx stac-eo-mcp   # runs the server (it waits for an MCP client on stdin)

Claude Desktop

Add to claude_desktop_config.json (Settings → Developer → Edit Config):

{
  "mcpServers": {
    "stac-eo-mcp": {
      "command": "uvx",
      "args": ["stac-eo-mcp"],
      "env": {
        "STAC_EO_MCP_OUTPUT_DIR": "/Users/you/stac-eo-mcp-output"
      }
    }
  }
}

If Claude Desktop cannot find uvx, use its full path (which uvx).

Claude Code

claude mcp add stac-eo-mcp -- uvx stac-eo-mcp
# with options:
claude mcp add stac-eo-mcp -e STAC_EO_MCP_CATALOG=earth-search -- uvx stac-eo-mcp

Cursor

.cursor/mcp.json:

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

Configuration

All optional, via environment variables:

Variable

Default

Meaning

STAC_EO_MCP_CATALOG

planetary-computer

Default catalog (planetary-computer or earth-search)

STAC_EO_MCP_OUTPUT_DIR

~/stac-eo-mcp-output

Where PNG / GeoTIFF files are written

STAC_EO_MCP_MAX_AREA_KM2

100

Largest bbox for pixel reads

STAC_EO_MCP_MAX_SCENES

24

Most dates read by time_series (more are sampled evenly)

STAC_EO_MCP_MAX_SEARCH_LIMIT

50

Most scenes returned by search_scenes

STAC_EO_MCP_LOG_LEVEL

INFO

Log level; logs go to stderr only

Example conversation

You: How did vegetation in Villa Borghese, Rome (bbox 12.47, 41.905, 12.50, 41.925) change during 2025?

Claude calls time_series(index="ndvi", bbox=[12.47, 41.905, 12.5, 41.925], date_range="2025-01-01/2025-12-31")

Claude: I analysed 24 of the 51 Sentinel-2 dates in 2025 (sampled evenly); 22 had enough clear pixels. Mean NDVI stays between 0.28 and 0.39, typical of a park mixed with city blocks:

Date

Mean NDVI

2025-01-04

0.37

2025-05-01

0.35

2025-07-03

0.28 (minimum)

2025-09-28

0.35

2025-11-05

0.39 (maximum)

The summer dip and autumn recovery is the usual Mediterranean pattern: dry-season stress in July, regrowth after the autumn rains. 10 July and 16 October were skipped (fully cloudy over the park even though the tiles reported under 30% cloud).

You: Show me the map for the end of July.

Claude calls search_scenes(...), then compute_index(item_id="S2A_MSIL2A_20250730T100051_R122_T33TTG_20250730T153414", index="ndvi", bbox=[...], save="png")

Claude: 30 July is 91% clear, mean NDVI 0.32 (max 0.90 on the park's tree cover, negative on the Tiber). Map saved to ~/stac-eo-mcp-output/S2A_MSIL2A_20250730T…_ndvi_c75d9e23.png.

Other questions that work well:

  • "Find Sentinel-2 scenes under 10% cloud over Lake Trasimeno in August 2025 and compute NDWI on the clearest one."

  • "Compare NBR before and after a wildfire": two compute_index calls; dNBR = NBRpre − NBRpost.

  • "Which collections does Earth Search have?"

How it works

agent ──MCP/stdio──▶ server.py ──▶ analysis.py ──▶ catalog.py  (pystac-client: search, signing, band names)
                                         │
                                         ├──────▶ raster.py   (odc-stac window read, PNG/GeoTIFF)
                                         └──────▶ indices.py  (numpy: reflectance, SCL mask, stats)
  • models.py validates inputs (WGS84 bbox, ISO dates, limits) and defines compact outputs.

  • indices.py is pure numpy and fully unit-tested on synthetic arrays.

  • Blocking I/O runs in worker threads; time_series reads up to 4 scenes in parallel.

  • Where two Sentinel-2 tiles overlap, time_series keeps one scene per day (best bbox coverage, then lowest cloud cover).

Development

git clone https://github.com/bbrauzzi/stac-eo-mcp && cd stac-eo-mcp
uv sync
uv run pytest            # fast tests (no network)
uv run pytest -m slow    # live tests against both catalogs (~1-2 min)
uv run ruff check . && uv run ruff format --check .
npx @modelcontextprotocol/inspector -e STAC_EO_MCP_OUTPUT_DIR=/tmp/out uv run stac-eo-mcp  # MCP Inspector (pass env with -e)
uv run python scripts/make_readme_figures.py             # regenerate the README figures

Limitations

  • Indices are Sentinel-2 L2A only; search and details work on any collection.

  • Bounding boxes crossing the antimeridian are not supported.

  • The mask keeps snow/ice pixels (SCL class 11); exclude snowy periods for vegetation work.

License

MIT. Sentinel-2 data: Copernicus Sentinel data, processed by ESA.

Available Tools

5 tools
compute_indexA
Idempotent

Compute NDVI, NDWI or NBR on one Sentinel-2 L2A scene, reading only the bbox window.

Clouds, shadows and no-data are masked with the SCL layer. Returns min, max, mean, std
and the share of valid pixels, plus file paths when `save` is set. No raster data is
returned. Area is limited (default 100 km²).

Inputs: bbox (required), index (required), item_id (required), save, +1 more. Returns: bbox, note, index, stats, +4 more

get_scene_detailsB
Read-onlyIdempotent

Key metadata and the list of assets (bands, previews, metadata files) of one scene.

Inputs: item_id (required), collection (required), catalog. Returns: id, bbox, assets, datetime, +2 more

list_collectionsA
Read-onlyIdempotent

List the collections available in a STAC catalog, with a one-sentence description.

Use the returned ids as `collection` in search_scenes and get_scene_details.

Inputs: catalog. Returns: result

search_scenesA
Read-onlyIdempotent

Search scenes intersecting a bbox in a date range, newest first.

Returns id, date, cloud cover, a simplified footprint and a preview image link. Cloud cover is for the whole tile, not the bbox.

Inputs: bbox (required), collection (required), date_range (required), limit, +2 more. Returns: scenes, catalog, returned, collection

time_seriesA
Read-onlyIdempotent

Mean of an index over a bbox for each Sentinel-2 acquisition date in a range.

One scene per day, cloudy dates skipped with a reason, sampled evenly when there are more dates than the server limit (default 24). Includes a summary (mean, min/max date, change from first to last). Can take 10-60 s for long ranges.

Inputs: bbox (required), index (required), date_range (required), catalog, +1 more. Returns: bbox, note, index, points, +5 more

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4/5.0

    Scored across 5 tools

    Disambiguation5/5

    Each tool targets a distinct stage of the STAC workflow: catalog browsing, scene search, scene metadata, single-scene index computation, and multi-date time series. The only potential overlap is compute_index vs. time_series, but their scopes (one scene vs. a date range) and descriptions make the boundary clear.

    Naming Consistency4/5

    Four of five names follow a clear verb_noun pattern (list_collections, search_scenes, get_scene_details, compute_index). The outlier is time_series, a noun phrase with no verb, but it remains readable and predictable in context.

    Tool Count5/5

    Five tools are well-scoped for a focused STAC/EO server, covering discovery, retrieval, and two levels of analysis without filler. Each tool earns its place and the surface is neither thin nor bloated.

    Completeness4/5

    The core read-only EO workflow is covered: collections, scene search, scene details, and index computation/aggregation. Minor gaps exist, such as no dedicated collection-detail tool, no explicit cloud-cover filter in search_scenes, and no asset download/read tool.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      C
      maintenance
      Enables AI assistants to search and access geospatial datasets through STAC (SpatioTemporal Asset Catalog) APIs. Supports querying satellite imagery, weather data, and other geospatial assets with spatial, temporal, and attribute filters.
      11
      20
      MIT
    • F
      license
      B
      quality
      D
      maintenance
      A Python MCP server for discovering and analyzing Sentinel-2 L2A imagery, enabling AI agents to search scenes, check quality, and compute spectral indices like NDVI, NDWI, and NBR from remote COG windows.
      4
      -
    • F
      license
      Not graded
      quality
      D
      maintenance
      Turns the AWS Registry of Open Data and public STAC catalogs into agent-callable tools for dataset search, STAC queries, and NDVI/NDBI/land-cover analysis on Sentinel-2 imagery.
      -