Chuk MCP STAC
OfficialProvides access to satellite imagery through the Earth Search STAC catalog hosted on Amazon Web Services (AWS), enabling search, download, and processing of satellite bands from various missions such as Sentinel-2 and Landsat.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Chuk MCP STAC search for Sentinel-2 scenes near Paris with <10% cloud cover"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Chuk MCP STAC
Satellite Imagery Discovery & Retrieval MCP Server - A comprehensive Model Context Protocol (MCP) server for searching STAC catalogs, downloading satellite bands, and creating composites.
This is a demonstration project provided as-is for learning and testing purposes.
Features
This MCP server provides access to satellite imagery through STAC (SpatioTemporal Asset Catalog) APIs via twenty-one tools.
All tools return fully-typed Pydantic v2 models for type safety, validation, and excellent IDE support. All tools support output_mode="text" for human-readable output alongside the default JSON.
1. Catalog Discovery (stac_list_catalogs)
List available STAC catalogs:
Earth Search (AWS) and Planetary Computer (Microsoft)
Shows default catalog and available endpoints
2. Collection Browsing (stac_list_collections)
Browse collections in a catalog:
List all available satellite collections
Spatial and temporal extents
Collection descriptions and metadata
3. Scene Search (stac_search)
Search for satellite scenes:
Bounding box spatial queries
Date range filtering
Cloud cover thresholds
Collection filtering (Sentinel-2, Landsat, etc.)
Configurable result limits
4. Scene Details (stac_describe_scene)
Get detailed metadata for a scene:
Available bands and assets
CRS and projection info
Cloud cover, datetime, spatial extent
Filters out metadata-only assets
5. Scene Preview (stac_preview)
Get a preview/thumbnail URL for a scene:
Returns
rendered_previeworthumbnailasset URLPrefers rendered previews over thumbnails
Fast visual browsing without downloading full bands
6. Band Download (stac_download_bands)
Download specific bands from a scene:
Any combination of bands (red, green, blue, nir, etc.)
Hardware band aliases supported (B04, B08, SR_B4, etc.)
Optional bbox cropping in EPSG:4326
Output as GeoTIFF or PNG (auto-stretched)
SCL-based cloud masking (Sentinel-2 only)
7. RGB Composite (stac_download_rgb)
Download true-color RGB composites:
Convenience wrapper for red, green, blue bands
Automatic band resolution matching
PNG output for inline LLM rendering
8. Custom Composite (stac_download_composite)
Create multi-band composites:
Any band combination (e.g., false-color infrared: nir, red, green)
Named composites for easy identification
Cloud masking and PNG output support
9. Spectral Index (stac_compute_index)
Compute spectral indices for a scene:
NDVI, NDWI, NDBI, EVI, SAVI, BSI
Automatically selects required bands
Cloud masking (masked pixels → NaN)
Output as float32 GeoTIFF or stretched PNG
10. Mosaic (stac_mosaic)
Merge multiple scenes into a single raster:
Combines overlapping scenes
Standard merge (last) or quality-weighted (best pixel via SCL)
Per-scene cloud masking before merge
11. Time Series (stac_time_series)
Extract temporal band data:
Searches scenes across a date range
Downloads bands for each date
Concurrent downloads for performance
Cloud cover filtering
12. Server Status (stac_status)
Check server configuration:
Server version and storage provider
Default catalog
Artifact store availability
13. Capabilities (stac_capabilities)
List full server capabilities for LLM workflow planning:
Available catalogs and collections
Spectral indices with required bands
Band mappings by satellite platform
Tool count
14. Size Estimation (stac_estimate_size)
Estimate download size before committing to a full download:
Reads only COG headers (no pixel data transferred)
Per-band dimensions, dtype, and byte estimates
Warnings for large downloads (>=500MB, >=1GB)
15. Collection Intelligence (stac_describe_collection)
Get detailed collection metadata with LLM-friendly guidance:
Band wavelengths and resolutions
Recommended composite recipes
Supported spectral indices
Cloud masking info and usage guidance
16. Conformance Checking (stac_get_conformance)
Check which STAC API features a catalog supports:
Parses conformance URIs into feature flags
Core, item_search, filter, sort, fields, query, collections
17. Find Scene Pairs (stac_find_pairs)
Find before/after scene pairs for change detection:
Separate before and after date ranges
Computes spatial overlap percentage per pair
Caches all found scenes for follow-up download
18. Coverage Check (stac_coverage_check)
Verify cached scenes fully cover a target area:
Rasterizes bounding box into a 100x100 grid
Returns coverage percentage and uncovered areas
Ensures full spatial coverage before download
19. Queryable Properties (stac_queryables)
Fetch queryable properties from a STAC API:
Catalog-level or collection-scoped queryables
Property names, types, descriptions, and enum values
Enables advanced CQL2 filter construction
20. Temporal Composite (stac_temporal_composite)
Combine multiple scenes via per-pixel statistics:
Methods: median, mean, max, min
Reduces cloud contamination in time series
SCL-based cloud masking per scene before compositing
21. Zonal Statistics (stac_zonal_stats)
Read a raster's values within zones — the inference step after a fetch:
Per-zone
n_valid / mean / std / min / max / median / p10 / p90Zones as points +
buffer_m(circular) or GeoJSON polygons, in any CRSOptional
background_mannulus → a local z-score (anomaly readout) for cropmark / feature detection
Related MCP server: Planetary Computer MCP Server
Installation
Using uvx (Recommended - No Installation Required!)
uvx chuk-mcp-stacUsing uv (Recommended for Development)
# Install from PyPI
uv pip install chuk-mcp-stac
# Or clone and install from source
git clone <repository-url>
cd chuk-mcp-stac
uv sync --devUsing pip (Traditional)
pip install chuk-mcp-stacUsage
With Claude Desktop
Option 1: Run Locally with uvx
MacOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%/Claude/claude_desktop_config.json
{
"mcpServers": {
"stac": {
"command": "uvx",
"args": ["chuk-mcp-stac"]
}
}
}Option 2: Run Locally with pip
{
"mcpServers": {
"stac": {
"command": "chuk-mcp-stac"
}
}
}Standalone
Run the server directly:
# With uvx (recommended - always latest version)
uvx chuk-mcp-stac
# With uvx in HTTP mode
uvx chuk-mcp-stac http
# Or if installed locally
chuk-mcp-stac
chuk-mcp-stac httpOr with uv/Python:
# STDIO mode (default, for MCP clients)
uv run chuk-mcp-stac
# or: python -m chuk_mcp_stac.server
# HTTP mode (for web access)
uv run chuk-mcp-stac http
# or: python -m chuk_mcp_stac.server httpSTDIO mode is for MCP clients like Claude Desktop and mcp-cli. HTTP mode runs a web server on http://localhost:8002 for HTTP-based MCP clients.
Example Usage
Once configured, you can ask Claude questions like:
"Search for Sentinel-2 imagery over London from last month"
"Download an RGB composite of that scene"
"Show me a false-color infrared view using NIR, red, and green bands"
"Compute the NDVI for this scene with cloud masking"
"Create a mosaic of these overlapping scenes"
"Get a time series of NDVI data for this farm over the growing season"
"What collections are available on Earth Search?"
"Describe the Sentinel-2 collection — what bands and composites are available?"
"How big would downloading 4 bands from that scene be?"
"What STAC API features does Earth Search support?"
Demo Scripts
The examples/ directory contains 19 runnable demos covering all 21 tools. Each script is self-contained and produces a PNG output in examples/output/.
Core Tool Demos
Script | Network? | Tools Demonstrated |
| No |
|
| Yes |
|
| Yes |
|
| Yes |
|
| Yes |
|
| Yes |
|
| Yes |
|
| Yes |
|
| Yes |
|
Real-World Showcase Demos
Script | Location | What It Shows |
| California, USA | Park Fire burn scar — before/after RGB, NDVI, false-colour SWIR composite |
| Lincolnshire, UK | Storm Babet flooding — NDWI water index before/after with cloud masking |
| Yorkshire, UK | Holderness coast retreat — 2019 vs 2024 NDWI coastline comparison |
| Cambridgeshire, UK | Wheat phenology — cloud-masked NDVI across growing season |
| Dubai, UAE | Urban expansion — 2022 vs 2024 NDBI built-up index |
| Las Vegas, USA | F1 race infrastructure — summer vs race week NDBI comparison |
| Rondônia, Brazil | Dry season NDVI time series tracking deforestation |
| Chad/Nigeria | Seasonal water extent — NDWI wet vs dry season |
| Singapore | Port activity — RGB time series across 6 months |
| Mont Blanc, Alps | Snow cover — custom NDSI winter vs summer |
cd examples
python capabilities_demo.py # no network required
python colchester_from_space.py # full search → download → render pipeline
python wildfire_scar_demo.py # before/after burn scar comparisonTool Reference
All tools accept an optional output_mode parameter ("json" default, or "text" for human-readable output).
Download tools that produce GeoTIFF output automatically generate a PNG preview (preview_ref in the response).
stac_search
{
"bbox": [0.85, 51.85, 0.95, 51.92], # [west, south, east, north]
"collection": "sentinel-2-c1-l2a", # optional
"date_range": "2024-06-01/2024-08-31", # optional
"max_cloud_cover": 20, # 0-100, optional
"max_items": 10, # optional
"catalog": "earth_search" # optional
}stac_download_bands
{
"scene_id": "S2B_...", # from search results
"bands": ["red", "green", "blue", "nir"], # common names or aliases (B04, SR_B4)
"bbox": [0.85, 51.85, 0.95, 51.92], # optional crop
"output_format": "geotiff", # "geotiff" or "png"
"cloud_mask": false # Sentinel-2 only
}stac_download_rgb
{
"scene_id": "S2B_...",
"bbox": [0.85, 51.85, 0.95, 51.92], # optional crop
"output_format": "png", # "geotiff" or "png"
"cloud_mask": false # Sentinel-2 only
}stac_download_composite
{
"scene_id": "S2B_...",
"bands": ["nir", "red", "green"], # false-color infrared
"composite_name": "false_color_ir", # optional label
"bbox": [0.85, 51.85, 0.95, 51.92], # optional crop
"output_format": "geotiff", # "geotiff" or "png"
"cloud_mask": false # Sentinel-2 only
}stac_compute_index
{
"scene_id": "S2B_...",
"index_name": "ndvi", # ndvi, ndwi, ndbi, evi, savi, bsi
"bbox": [0.85, 51.85, 0.95, 51.92], # optional crop
"cloud_mask": true, # mask clouds with NaN
"output_format": "geotiff" # "geotiff" or "png"
}stac_mosaic
{
"scene_ids": ["S2B_001", "S2B_002"],
"bands": ["red", "green", "blue"],
"bbox": [0.85, 51.85, 0.95, 51.92], # optional
"method": "last", # "last" or "quality" (SCL-based)
"output_format": "geotiff", # "geotiff" or "png"
"cloud_mask": false # per-scene masking before merge
}stac_time_series
{
"bbox": [0.85, 51.85, 0.95, 51.92],
"bands": ["red", "nir"],
"date_range": "2024-01-01/2024-12-31",
"collection": "sentinel-2-c1-l2a", # optional
"max_cloud_cover": 10, # optional
"max_items": 50, # optional
"catalog": "earth_search" # optional
}stac_estimate_size
{
"scene_id": "S2B_...",
"bands": ["red", "green", "blue", "nir"],
"bbox": [0.85, 51.85, 0.95, 51.92] # optional crop
}stac_describe_collection
{
"collection_id": "sentinel-2-l2a",
"catalog": "earth_search", # optional
"output_mode": "text" # optional: "json" or "text"
}stac_get_conformance
{
"catalog": "earth_search", # optional
"output_mode": "json" # optional: "json" or "text"
}Development
Setup
# Clone the repository
git clone <repository-url>
cd chuk-mcp-stac
# Install with uv (recommended)
uv sync --dev
# Or with pip
pip install -e ".[dev]"Running Tests
make test # Run tests
make test-cov # Run tests with coverage
make coverage-report # Show coverage reportCode Quality
make lint # Run linters
make format # Auto-format code
make typecheck # Run type checking
make security # Run security checks
make check # Run all checksBuilding
make build # Build package
make docker-build # Build Docker imageDeployment
Fly.io
Deploy to Fly.io with a single command:
# First time setup
fly launch
# Deploy updates
fly deployDocker
# Build the image
docker build -t chuk-mcp-stac .
# Run the container
docker run -p 8002:8002 chuk-mcp-stacArchitecture
Built on top of chuk-mcp-server, this server uses:
Async-First: Native async/await with sync rasterio wrapped in
asyncio.to_thread()Type-Safe: Pydantic v2 models with
extra="forbid"for all responsesEfficient I/O: Cloud-Optimized GeoTIFF (COG) reading with windowed access
Smart Caching: LRU scene cache (200 entries), TTL client cache (300s), in-memory raster cache (100 MB LRU)
Band Resolution Matching: Automatic bilinear resampling when bands differ in resolution
Band Aliases: Hardware names (B04, SR_B4) resolved to common names at entry
Artifact Storage: Pluggable storage via chuk-artifacts (memory, filesystem, S3)
CRS Handling: Automatic EPSG:4326 to native CRS reprojection for bbox queries
Cloud Masking: SCL-based masking for Sentinel-2 (integer → 0, float → NaN)
Spectral Indices: NDVI, NDWI, NDBI, EVI, SAVI, BSI with automatic band selection
PNG Output: 2nd-98th percentile stretch for visual inspection and LLM rendering
Auto-Preview: PNG preview auto-generated alongside every GeoTIFF download (
preview_ref)Temporal Compositing: Pixel-by-pixel statistical composites (median, mean, max, min)
Quality Mosaics: SCL-based best-pixel selection for quality-weighted merges
Progress Callbacks: Optional progress reporting for long-running operations
PC Auth: Automatic Planetary Computer asset signing when package is installed
Dual Output: All 21 tools support
output_mode="text"for human-readable responses
See ARCHITECTURE.md for design principles and data flow diagrams. See SPEC.md for the full tool specification with parameter tables. See ROADMAP.md for development status and planned features.
Supported Catalogs
Catalog | Collections | URL |
Earth Search (AWS) | Sentinel-2, Landsat, NAIP, MODIS | earth-search.aws.element84.com |
Planetary Computer (Microsoft) | Sentinel-2, Landsat, MODIS | planetarycomputer.microsoft.com |
USGS Landsat Look | Landsat | landsatlook.usgs.gov |
Also supports Sentinel-1 SAR (VV/VH) and Copernicus DEM GLO-30 collections.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Fork the repository
Create your feature branch (
git checkout -b feature/amazing-feature)Commit your changes (
git commit -m 'Add amazing feature')Push to the branch (
git push origin feature/amazing-feature)Open a Pull Request
License
Apache License 2.0 - See LICENSE for details.
Acknowledgments
STAC Spec for the SpatioTemporal Asset Catalog specification
pystac-client for the STAC client library
rasterio for raster data I/O
Model Context Protocol for the MCP specification
Anthropic for Claude and MCP support
Available Tools
24 toolsstac_capabilitiesA
List server capabilities: catalogs, collections, and band info.
Returns a comprehensive overview of what this server can do, including supported catalogs, satellite collections, band names per platform, and available spectral indices with required bands.
Args: output_mode: Response format - "json" (default) or "text"
Returns: JSON with catalogs, collections, band mappings, and spectral indices
Tips for LLMs: - Call this FIRST to understand what the server can do before planning any analysis workflow - Use band_mappings to know which band names to pass to download tools - Use spectral_indices to see which indices are available and what bands they require - Typical workflow: stac_capabilities → stac_search → stac_describe_scene → stac_download_bands or stac_compute_index - Collections: sentinel-2-l2a (optical, 10m), landsat-c2-l2 (optical, 30m), sentinel-1-grd (SAR radar, 10m), cop-dem-glo-30 (elevation, 30m)
Example: caps = await stac_capabilities()
Inputs: output_mode.
stac_compute_indexA
Compute a spectral index (e.g., NDVI, NDWI) for a scene.
Automatically downloads the required bands, computes the index formula, and stores the result as a single-band float32 raster.
Supported indices:
ndvi: Vegetation (NIR - Red) / (NIR + Red)
ndwi: Water (Green - NIR) / (Green + NIR)
ndbi: Built-up (SWIR16 - NIR) / (SWIR16 + NIR)
evi: Enhanced Vegetation 2.5*(NIR - Red) / (NIR + 6Red - 7.5Blue + 1)
savi: Soil-Adjusted Vegetation ((NIR - Red) / (NIR + Red + 0.5)) * 1.5
bsi: Bare Soil ((SWIR16 + Red) - (NIR + Blue)) / ((SWIR16 + Red) + (NIR + Blue))
Args: scene_id: Scene identifier from a previous search index_name: Index to compute (ndvi, ndwi, ndbi, evi, savi, bsi) bbox: Optional crop bbox in EPSG:4326 [west, south, east, north] cloud_mask: Apply SCL-based cloud masking before computation (Sentinel-2 only) output_format: Output format - "geotiff" (default) or "png" output_mode: Response format - "json" (default) or "text"
Returns: JSON with artifact_ref and value_range for the computed index
Tips for LLMs: - Use stac_capabilities to see all available indices and required bands - Interpretation guide: - NDVI: >0.6 dense vegetation, 0.2-0.6 moderate, <0.2 bare/water - NDWI: >0 water, <0 land; useful for flood mapping - NDBI: >0 built-up, <0 natural land cover - EVI: similar to NDVI but corrects for atmospheric and soil effects - SAVI: like NDVI but better in areas with sparse vegetation - BSI: >0 bare soil, <0 vegetated - Only works for optical collections (Sentinel-2, Landsat) - Enable cloud_mask=True for cleaner results with Sentinel-2 data - For temporal change analysis, compute the same index on multiple dates and compare value_range
Example: ndvi = await stac_compute_index( scene_id="S2B_...", index_name="ndvi", bbox=[0.85, 51.85, 0.95, 51.92] )
Inputs: scene_id (required), index_name (required), bbox, cloud_mask, +2 more.
stac_coverage_checkA
Check if cached scenes fully cover a requested bounding box.
Rasterizes the target bbox into a grid and checks which cells are covered by the provided scenes. Useful for planning mosaics to ensure gap-free coverage.
Args: bbox: Target bounding box [west, south, east, north] in EPSG:4326 scene_ids: Scene identifiers (must be cached from prior stac_search calls) output_mode: Response format - "json" (default) or "text"
Returns: JSON with coverage percentage and uncovered areas
Tips for LLMs: - Call this before stac_mosaic to verify scenes fully cover your area of interest - If coverage is less than 100%, search for more scenes or widen the date range to find additional tiles - Scenes must have been found by a prior stac_search call
Example: check = await stac_coverage_check( bbox=[0.8, 51.8, 1.0, 51.95], scene_ids=["S2B_...", "S2A_..."] )
Inputs: bbox (required), scene_ids (required), output_mode.
stac_describe_collectionA
Get detailed information about a STAC collection.
Returns band wavelengths, recommended composites, supported spectral indices, cloud masking info, and LLM-friendly usage guidance.
For known collections (Sentinel-2, Landsat, Sentinel-1, DEM), provides rich metadata including band names needed for download tools. Unknown collections still return live STAC metadata.
Args: collection_id: Collection identifier. Options: sentinel-2-l2a, sentinel-2-c1-l2a, landsat-c2-l2, sentinel-1-grd, cop-dem-glo-30 catalog: Catalog name (default: earth_search). Options: earth_search, planetary_computer, usgs output_mode: Response format - "json" (default) or "text"
Returns: JSON with band details, composites, spectral indices, and guidance
Tips for LLMs: - Call this to discover band names before using stac_download_bands - The composites field lists pre-defined band combinations (e.g., true_color = [red, green, blue]) - The spectral_indices field shows which indices this collection supports - The llm_guidance field contains domain-specific usage advice - Check cloud_mask_band — if None, the collection is non-optical (SAR radar or DEM) and cloud_mask=True will fail
Example: detail = await stac_describe_collection( collection_id="sentinel-2-l2a" )
Inputs: collection_id (required), catalog, output_mode.
stac_describe_sceneA
Get detailed information about a specific scene.
Shows all available assets/bands, properties, CRS, and download URLs. The scene must have been returned by a previous stac_search call.
Args: scene_id: Scene identifier from a search result (use scene_id from stac_search) output_mode: Response format - "json" (default) or "text"
Returns: JSON with full scene details including all assets, CRS, and properties
Tips for LLMs: - Call this after stac_search to see available bands before downloading - The assets list shows every downloadable band and its resolution - Use the band keys (e.g., red, nir, scl) in stac_download_bands - Check cloud_cover to decide if the scene is usable
Example: detail = await stac_describe_scene( scene_id="S2B_MSIL2A_20240715T105629_N0510_R094_T31UCR_20240715T143301" )
Inputs: scene_id (required), output_mode.
stac_download_bandsA
Download specific bands from a scene as a GeoTIFF or PNG.
Reads band COGs via HTTP, windows to the requested bbox, and stores the result in chuk-artifacts. The bbox should be in EPSG:4326 — CRS reprojection to the raster's native CRS is handled automatically.
Args: scene_id: Scene identifier from a previous stac_search call bands: Band names to download. Common names: - Sentinel-2: red, green, blue, nir, swir16, swir22, rededge1-3, scl - Landsat: red, green, blue, nir08, swir16, swir22, coastal, qa_pixel - Sentinel-1: vv, vh - DEM: data bbox: Optional crop bbox in EPSG:4326 [west, south, east, north]. Strongly recommended to avoid downloading full tiles output_format: "geotiff" (default, lossless, for analysis) or "png" (8-bit lossy with percentile stretch, for preview/display) cloud_mask: Apply SCL-based cloud masking (Sentinel-2 only). Masked pixels become 0 (integer) or NaN (float) output_mode: Response format - "json" (default) or "text"
Returns: JSON with artifact_ref, shape, dtype, and optional preview_ref
Tips for LLMs: - Use stac_describe_scene first to see available band names - Always provide a bbox to limit download size - Use output_format="png" when the user wants to see the image - GeoTIFF preserves full radiometric precision for analysis - A PNG preview is auto-generated alongside GeoTIFF downloads - For RGB visualisation, prefer stac_download_rgb (simpler) - For spectral indices, prefer stac_compute_index (automatic)
Example: result = await stac_download_bands( scene_id="S2B_...", bands=["red", "nir"], bbox=[0.85, 51.85, 0.95, 51.92] )
Inputs: bands (required), scene_id (required), bbox, cloud_mask, +2 more.
stac_download_compositeA
Download a multi-band composite from a scene.
Creates a composite from any combination of bands. Band order determines RGB channel mapping (first=R, second=G, third=B).
Args: scene_id: Scene identifier from a previous stac_search call bands: Band names for the composite (order = R,G,B channels). Common recipes: - ["nir", "red", "green"] — false colour infrared (vegetation=red) - ["swir16", "nir", "red"] — agriculture (crops=bright green) - ["swir16", "swir22", "red"] — geology/minerals composite_name: Label for the composite (e.g., "false_color_ir") bbox: Optional crop bbox in EPSG:4326 [west, south, east, north] output_format: "geotiff" (default, lossless) or "png" (8-bit preview) cloud_mask: Apply SCL-based cloud masking (Sentinel-2 only) output_mode: Response format - "json" (default) or "text"
Returns: JSON with artifact_ref for the composite
Tips for LLMs: - Use stac_describe_collection to see pre-defined composite recipes - Band order matters: first band → Red, second → Green, third → Blue - For true-colour RGB, use stac_download_rgb instead (simpler) - For single-value analysis, use stac_compute_index (e.g., NDVI)
Example: false_color = await stac_download_composite( scene_id="S2B_...", bands=["nir", "red", "green"], composite_name="false_color_ir" )
Inputs: bands (required), scene_id (required), bbox, cloud_mask, +3 more.
stac_download_rgbA
Download a true-color RGB composite from a scene.
Convenience wrapper around stac_download_bands that automatically selects red, green, blue bands. This is the simplest way to get a visual satellite image.
Args: scene_id: Scene identifier from a previous stac_search call bbox: Optional crop bbox in EPSG:4326 [west, south, east, north]. Strongly recommended to avoid downloading full tiles output_format: "geotiff" (default, lossless) or "png" (8-bit lossy, suitable for inline display by LLMs) cloud_mask: Apply SCL-based cloud masking (Sentinel-2 only) output_mode: Response format - "json" (default) or "text"
Returns: JSON with artifact_ref for the RGB composite
Tips for LLMs: - Use output_format="png" when the user wants to see the image — PNG can be rendered inline - GeoTIFF preserves full 16-bit precision but cannot be displayed inline - For false-color composites (e.g., NIR/Red/Green), use stac_download_composite instead - Only works for optical collections (Sentinel-2, Landsat) that have red, green, blue bands
Example: rgb = await stac_download_rgb(scene_id="S2B_...", output_format="png")
Inputs: scene_id (required), bbox, cloud_mask, output_mode, +1 more.
stac_estimate_sizeA
Estimate download size for bands from a scene (no pixel data read).
Reads only COG headers to determine dimensions, dtype, and estimated file size. Use this before large downloads to understand how much data will be transferred.
Args: scene_id: Scene identifier from a previous search bands: Band names to estimate (e.g., ["red", "green", "blue", "nir"]) bbox: Optional crop bbox in EPSG:4326 [west, south, east, north] output_mode: Response format - "json" (default) or "text"
Returns: JSON with per-band size details and total estimate
Tips for LLMs: - Call this BEFORE large downloads to check feasibility - If estimated_mb > 500, suggest a smaller bbox or fewer bands - No pixel data is read — only COG headers, so this is very fast - Use the per-band breakdown to see which bands are largest (e.g., 10m bands are ~4x larger than 20m bands) - Useful for planning stac_mosaic or stac_temporal_composite where multiple scenes multiply the total data volume
Example: estimate = await stac_estimate_size( scene_id="S2B_...", bands=["red", "nir"], bbox=[0.85, 51.85, 0.95, 51.92] )
Inputs: bands (required), scene_id (required), bbox, output_mode.
stac_find_pairsA
Find before/after scene pairs for change detection.
Searches two date ranges and matches scenes by spatial overlap, useful for detecting changes between time periods (e.g., flood damage, urban growth, deforestation, seasonal vegetation change).
Args: bbox: Bounding box [west, south, east, north] in EPSG:4326 before_range: Before date range "YYYY-MM-DD/YYYY-MM-DD" after_range: After date range "YYYY-MM-DD/YYYY-MM-DD" collection: STAC collection (default: sentinel-2-l2a). Options: sentinel-2-l2a, sentinel-2-c1-l2a, landsat-c2-l2, sentinel-1-grd, cop-dem-glo-30 max_cloud_cover: Maximum cloud cover percentage 0-100 (default: 20). Ignored for non-optical collections (sentinel-1-grd, cop-dem-glo-30). catalog: Catalog name (default: earth_search). Options: earth_search, planetary_computer, usgs output_mode: Response format - "json" (default) or "text"
Returns: JSON with matched scene pairs sorted by overlap percentage
Tips for LLMs: - Best for change detection workflows: find pairs, then download the same bands for before/after scenes and compare - For flood mapping: use sentinel-1-grd (SAR sees through clouds) with before_range = dry season, after_range = flood event - For vegetation change: use sentinel-2-l2a, then compute NDVI for each scene in the pair - Higher overlap_percent means better spatial coverage for comparison - Follow up with stac_download_bands or stac_compute_index on each scene in the pair
Example: pairs = await stac_find_pairs( bbox=[0.8, 51.8, 1.0, 51.95], before_range="2024-01-01/2024-03-31", after_range="2024-07-01/2024-09-30" )
Inputs: bbox (required), after_range (required), before_range (required), catalog, +3 more.
stac_get_artifactA
Retrieve a stored artifact and save it as a local file for viewing.
Downloads the artifact bytes from the artifact store and writes them to a local file. Returns the file path so the image can be opened in any viewer.
Args: artifact_ref: Artifact ID from a previous download tool call (the artifact_ref or preview_ref value) output_mode: Response format - "json" (default) or "text"
Returns: JSON with file_path, mime type, size, and artifact metadata
Tips for LLMs: - Use the preview_ref (PNG) from download results for quick viewing - Use the artifact_ref (GeoTIFF) for full-resolution geospatial data - The file is saved to a temporary directory and can be opened with any image viewer or GIS application - PNG files can be opened with: open <file_path> (macOS) - GeoTIFF files can be opened with QGIS, rasterio, or similar
Example: result = await stac_get_artifact( artifact_ref="a7c666e6555548aea2d5351cc65bf173" ) # Returns: {"file_path": "/tmp/stac_artifacts/a7c666...png", ...}
Inputs: artifact_ref (required), output_mode.
stac_get_conformanceA
Check which STAC API features a catalog supports.
Reads the catalog's conformance URIs and matches them against known STAC API conformance classes to determine feature support (core, item_search, filter, sort, fields, query, collections).
Args: catalog: Catalog name (default: earth_search). Options: earth_search, planetary_computer, usgs output_mode: Response format - "json" (default) or "text"
Returns: JSON with feature support flags and raw conformance URIs
Tips for LLMs: - Rarely needed — most workflows don't require conformance checking - Useful for debugging when a catalog doesn't support expected features - Check for "query" support if advanced filtering is needed
Example: conformance = await stac_get_conformance(catalog="earth_search")
Inputs: catalog, output_mode.
stac_list_catalogsA
List all known STAC catalogs.
Returns pre-configured catalog endpoints that can be searched. Each catalog hosts different satellite collections.
Args: output_mode: Response format - "json" (default) or "text"
Returns: JSON with catalog names and endpoint URLs
Tips for LLMs: - Use stac_capabilities instead for a full overview including collections, bands, and indices - Default catalog is earth_search (AWS Element 84) - planetary_computer requires no API key (auto-authenticated)
Example: catalogs = await stac_list_catalogs()
Inputs: output_mode.
stac_list_collectionsA
List available collections in a STAC catalog.
Queries the catalog's live API to discover all hosted collections with titles, descriptions, and spatial/temporal extents.
Args: catalog: Catalog name (default: earth_search). Options: earth_search, planetary_computer, usgs output_mode: Response format - "json" (default) or "text"
Returns: JSON list of collections with titles, descriptions, and extents
Tips for LLMs: - Use this to discover what data is available in a specific catalog - For detailed band/composite info on a collection, follow up with stac_describe_collection - Different catalogs host different collections — if a collection isn't found, try another catalog
Example: collections = await stac_list_collections(catalog="earth_search")
Inputs: catalog, output_mode.
stac_mapARead-only
Visualise STAC scene search results as a multi-layer footprint map. Scenes appear as bounding-box polygons, grouped by collection, with cloud cover, acquisition date, and thumbnail URL in the popup. Run stac_search first, then pass the scene_ids here.
Inputs: basemap, scene_ids.
stac_mosaicA
Create a mosaic from multiple scenes.
Combines overlapping scenes into a single seamless raster. Useful when your area of interest spans multiple satellite tiles.
Args: scene_ids: List of scene identifiers to mosaic (from stac_search) bands: Bands to include (e.g., ["red", "green", "blue"]) bbox: Output bounding box [west, south, east, north] in EPSG:4326. Defaults to union of all scenes if not specified output_format: "geotiff" (default, lossless) or "png" (8-bit preview) cloud_mask: Apply SCL-based cloud masking per scene before merge (Sentinel-2 only) method: Merge method: - "last" (default): later scenes overwrite earlier in overlap areas - "quality": SCL-based best-pixel selection — picks the clearest pixel from overlapping scenes (Sentinel-2 only) output_mode: Response format - "json" (default) or "text"
Returns: JSON with artifact_ref for the mosaic raster
Tips for LLMs: - Use stac_coverage_check first to verify scenes cover the target area - Use method="quality" for cloud-free mosaics from Sentinel-2 data - Use method="last" for quick mosaics or non-optical data - For temporal compositing (e.g., seasonal median), use stac_temporal_composite instead
Example: mosaic = await stac_mosaic( scene_ids=["S2B_001", "S2B_002"], bands=["red", "green", "blue"], method="quality" )
Inputs: bands (required), scene_ids (required), bbox, method, +3 more.
stac_pairs_mapARead-only
Visualise before/after scene pairs from stac_find_pairs as a two-layer map. Blue = before, red = after. Toggle layers to compare footprint coverage between time periods.
Inputs: basemap, after_scene_ids, before_scene_ids.
stac_previewA
Get a preview/thumbnail URL for a scene.
Returns the URL of the scene's thumbnail or rendered preview image. Much faster than downloading full bands — useful for quick browsing.
The scene must have been returned by a previous stac_search call.
Args: scene_id: Scene identifier from a search result (use scene_id from stac_search) output_mode: Response format - "json" (default) or "text"
Returns: JSON with preview_url for the scene's thumbnail
Tips for LLMs: - Use for quick visual checks before committing to full band downloads - The preview URL is a remote image that can be displayed directly - Not all scenes have thumbnails — check for errors in the response
Example: preview = await stac_preview(scene_id="S2B_...")
Inputs: scene_id (required), output_mode.
stac_queryablesA
Fetch queryable properties from a STAC API.
Returns the properties that can be used in search queries, including their types and allowed values. Useful for understanding what filtering options are available.
Args: catalog: Catalog name (default: earth_search). Options: earth_search, planetary_computer, usgs collection: Optional collection to scope queryables (e.g., "sentinel-2-l2a" for collection-specific properties) output_mode: Response format - "json" (default) or "text"
Returns: JSON with queryable property names, types, and descriptions
Tips for LLMs: - Rarely needed — stac_search handles common filters automatically - Useful when debugging why searches return unexpected results - Different catalogs support different queryable properties
Example: queryables = await stac_queryables( catalog="earth_search", collection="sentinel-2-l2a" )
Inputs: catalog, collection, output_mode.
stac_searchA
Search for satellite scenes matching spatial and temporal criteria.
This is the primary entry point for finding satellite imagery. Results are cached for follow-up describe/download operations.
Args: bbox: Bounding box [west, south, east, north] in EPSG:4326. Example: [-0.7, 52.7, 0.5, 53.7] for Lincolnshire, UK collection: STAC collection (default: sentinel-2-l2a). Options: - sentinel-2-l2a: Optical imagery, 10-20m resolution, 13 bands - sentinel-2-c1-l2a: Reprocessed Sentinel-2 archive - landsat-c2-l2: Optical imagery, 30m resolution, 11 bands - sentinel-1-grd: SAR radar, 10m, sees through clouds (VV/VH) - cop-dem-glo-30: Global elevation data, 30m date_range: Date range as "YYYY-MM-DD/YYYY-MM-DD" (optional). Omit for cop-dem-glo-30 (no temporal dimension) max_cloud_cover: Maximum cloud cover percentage 0-100 (default: 20). Ignored for non-optical collections (sentinel-1-grd, cop-dem-glo-30). Increase to 30-50 if getting zero results max_items: Maximum results to return (default: 10) catalog: Catalog name (default: earth_search). Options: earth_search, planetary_computer, usgs output_mode: Response format - "json" (default) or "text"
Returns: JSON with matching scenes sorted by cloud cover (optical) or date
Tips for LLMs: - Typical workflow: stac_search → stac_describe_scene → stac_download_bands - For cloudy regions (e.g., UK autumn), increase max_cloud_cover to 50 or use sentinel-1-grd (SAR radar, not affected by clouds) - For flood mapping: use sentinel-1-grd (water appears dark in VV/VH) - For vegetation analysis: use sentinel-2-l2a with NDVI index - For elevation/terrain: use cop-dem-glo-30 (no date_range needed) - If zero results, check the hints field for suggestions (try different catalog, increase cloud cover, widen date range) - Scenes are cached — use scene_id in subsequent describe/download calls
Example: results = await stac_search( bbox=[0.8, 51.8, 1.0, 51.95], date_range="2024-06-01/2024-08-31", max_cloud_cover=10 )
Inputs: bbox (required), catalog, max_items, collection, +3 more.
stac_statusA
Get server status and configuration.
Returns information about the server version, available catalogs, and artifact store status. Use this to verify the server is running and check storage configuration.
Args: output_mode: Response format - "json" (default) or "text"
Returns: JSON with server status including version, storage provider, and default catalog
Tips for LLMs: - Call stac_capabilities instead if you need to plan a workflow (it returns collections, bands, and indices too) - Check artifact_store_available before attempting downloads
Example: status = await stac_status()
Inputs: output_mode.
stac_temporal_compositeA
Create a temporal composite by combining multiple scenes statistically.
Searches for scenes in the date range, downloads bands from each, then combines them pixel-by-pixel using a statistical method. Useful for creating cloud-free composites from cloudy time series.
Args: bbox: Area of interest [west, south, east, north] in EPSG:4326 bands: Bands to composite (e.g., ["red", "green", "blue"]) date_range: Date range "YYYY-MM-DD/YYYY-MM-DD" method: Statistical method - "median" (default), "mean", "max", "min" collection: STAC collection (default: sentinel-2-l2a) max_cloud_cover: Maximum cloud cover 0-100 (default: 20) max_items: Maximum scenes (default: 10) catalog: Catalog name (default: earth_search) cloud_mask: Apply SCL cloud masking per scene before compositing output_format: Output format - "geotiff" (default) or "png" output_mode: Response format - "json" (default) or "text"
Returns: JSON with artifact_ref for the temporal composite
Tips for LLMs: - Method selection: - "median" (default): best for cloud-free composites — robust to outliers from clouds/shadows - "mean": smooth average, good for general baselines - "max": captures peak values (e.g., peak NDVI in a growing season) - "min": captures minimum values (e.g., lowest water extent) - Enable cloud_mask=True with Sentinel-2 for best results — masks clouds before compositing so they don't affect the statistics - Use a 2-3 month date range for seasonal composites - For per-date outputs instead of a single composite, use stac_time_series - Cloud cover filter is automatically skipped for non-optical collections (sentinel-1-grd, cop-dem-glo-30) - max_items defaults to 10 — increase for denser temporal sampling
Example: composite = await stac_temporal_composite( bbox=[0.85, 51.85, 0.95, 51.92], bands=["red", "green", "blue"], date_range="2024-06-01/2024-08-31", method="median" )
Inputs: bbox (required), bands (required), date_range (required), method, +7 more.
stac_time_seriesA
Extract a time series of band data over an area.
Searches for all scenes in the date range, downloads the requested bands for each, and returns references to the full temporal stack.
Args: bbox: Area of interest [west, south, east, north] bands: Bands to extract (e.g., ["red", "nir"]) date_range: Date range "YYYY-MM-DD/YYYY-MM-DD" collection: STAC collection (default: sentinel-2-l2a) max_cloud_cover: Maximum cloud cover 0-100 (default: 20) max_items: Maximum scenes to include (default: 50) catalog: Catalog name (default: earth_search) output_mode: Response format - "json" (default) or "text"
Returns: JSON with per-date artifact references
Tips for LLMs: - Use for monitoring change over time (vegetation growth, flood extent, urban expansion) - Pair with stac_compute_index on each date's artifact for temporal index analysis (e.g., NDVI over a growing season) - Keep bbox small — each date downloads full band data - Use max_cloud_cover=10 for cleaner optical time series - For a single cloud-free image from a date range, use stac_temporal_composite with method="median" instead - max_items limits the number of dates; set higher for dense temporal sampling or lower to reduce download volume - Cloud cover filter is automatically skipped for non-optical collections (sentinel-1-grd, cop-dem-glo-30)
Example: ts = await stac_time_series( bbox=[0.85, 51.85, 0.95, 51.92], bands=["red", "nir"], date_range="2024-01-01/2024-12-31", max_cloud_cover=10 )
Inputs: bbox (required), bands (required), date_range (required), catalog, +4 more.
stac_zonal_statsA
Read out a raster's values within zones — the inference step after a fetch.
Given a stored raster artifact (e.g. an NDVI index from stac_compute_index, or any GeoTIFF from stac_download_bands) and target zones, return per-zone statistics (n_valid, mean, std, min, max, median, p10, p90).
Zones are either circular buffers around points, or GeoJSON polygons:
points: [[x, y], ...] centres in
zones_crs, each summarised withinbuffer_m.geojson: a geometry / Feature / FeatureCollection (polygons) in
zones_crs.
Pass background_m (> buffer_m) to also get a LOCAL ANOMALY readout: each
point's mean is compared to the surrounding annulus (buffer_m..background_m)
and reported as a z-score, with anomalous set when |z| >= z_threshold. This
is the direct "is the signal at this location anomalous vs its surroundings?"
answer — e.g. a cropmark/soil-mark over a buried feature in an NDVI raster.
Args: artifact_id: A GeoTIFF raster artifact (NOT a PNG preview). points: Zone centres [[x, y], ...] in zones_crs (e.g. BNG eastings/northings). buffer_m: Circular zone radius in metres (raster must be projected). background_m: Outer annulus radius in metres → enables the z-score readout. geojson: Alternative polygon zones (geometry/Feature/FeatureCollection). zones_crs: CRS of points/geojson, e.g. "EPSG:27700" (BNG) or "EPSG:4326". labels: Optional labels for points (e.g. HER refs). band: 1-based band index to read. z_threshold: |z| at/above which a point is flagged anomalous (default 2.0). output_mode: "json" or "text".
Returns: Per-zone statistics, plus a local z-score when background_m is given.
Inputs: artifact_id (required), band, labels, points, +6 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 24 tools
Each tool serves a distinct purpose: capabilities overview, search, metadata description, various download modes (bands, RGB, composites), index computation, mosaicking, temporal compositing, time series extraction, zonal statistics, change detection pairs, coverage checking, size estimation, preview, artifact retrieval, and conformance checking. No two tools have overlapping functionality that would confuse an agent.
All tool names start with 'stac_' and use lowercase with underscores. However, there is inconsistency: many use verb_noun (e.g., stac_compute_index, stac_download_bands), while others use just nouns (e.g., stac_capabilities, stac_search, stac_map). The pattern is generally clear but not perfectly uniform.
With 24 tools, the server covers the full range of satellite imagery operations from discovery to analysis. While slightly on the higher side, each tool serves a specific need in the workflow, and the count is appropriate for the domain's complexity.
The tool surface covers the complete lifecycle: capabilities discovery, search, metadata inspection, multiple download options (bands, composites, RGB), index computation, mosaicking, temporal compositing, time series, change detection, zonal statistics, size estimation, and preview. No obvious gaps for a STAC client.
Maintenance
Related MCP Connectors
Geospatial AI MCP server — satellite imagery, embeddings, weather, GNS governance
MCP server for the GDEX (Geoscience Data Exchange) data portal: datasets, files, metrics, subsetting
Sentinel Hub MCP — satellite / earth-observation statistics as JSON (sentinel-hub.com).
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceA Model Context Protocol server that enables efficient discovery and retrieval of NASA Earth Data for geospatial analysis.26BSD 3-Clause
- AlicenseAqualityDmaintenanceA Python MCP server that provides unified access to satellite and geospatial data through natural language queries, with automatic place name geocoding and support for raster, vector, and Zarr formats.24Apache 2.0
- FlicenseNot gradedqualityFmaintenanceMCP server for a VEDA STAC catalog, providing a tool to call and interactive React UI to view STAC collections.-
- AlicenseNot gradedqualityDmaintenanceEnables discovery, analysis, and explanation of open satellite data through MCP, with support for STAC catalogs and NASA GIBS.1MIT