Skip to content

Imagery and land

Markdown

Sentinel-2 index and change

NDVI, NDWI, NBR or NDBI statistics and a map for an area on one date, or the change between two dates, from cloud-masked Sentinel-2 scenes.

RESTPOST https://mcp.terra-lab.ai/v1/tools/get_satellite_index
MCP toolget_satellite_index on https://mcp.terra-lab.ai/mcp
GroupImagery and land

Request

curl -X POST https://mcp.terra-lab.ai/v1/tools/get_satellite_index \
  -H "Authorization: Bearer $TERRALAB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"area":{"place":"Central Park, New York","radius_m":1500},"index":"ndvi","date":"2026-07-15","compare_date":"2026-01-15"}'
import os
import requests

response = requests.post(
    "https://mcp.terra-lab.ai/v1/tools/get_satellite_index",
    headers={"Authorization": f"Bearer {os.environ['TERRALAB_API_KEY']}"},
    json={
        "area": {
            "place": "Central Park, New York",
            "radius_m": 1500,
        },
        "index": "ndvi",
        "date": "2026-07-15",
        "compare_date": "2026-01-15",
    },
    timeout=120,
)
response.raise_for_status()
print(response.json()["structuredContent"])
const response = await fetch('https://mcp.terra-lab.ai/v1/tools/get_satellite_index', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TERRALAB_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "area": {
      "place": "Central Park, New York",
      "radius_m": 1500
    },
    "index": "ndvi",
    "date": "2026-07-15",
    "compare_date": "2026-01-15"
  }),
});
const data = await response.json();
console.log(data.structuredContent);

Other valid request bodies:

{"area":{"place":"Lahaina, Maui","radius_m":3000},"index":"nbr","date":"2023-07-01","compare_date":"2023-08-15"}
{"area":{"place":"Central Park, New York","radius_m":1500},"index":"ndvi","date":"2025-01-01","end_date":"2025-12-31"}

Parameters

A JSON object in the request body; in an MCP client, the arguments of the tool call.

NameTypeRequiredDescription
areaobjectNoThe area: a bbox, or a place (name, address or coordinates) with an optional radius in metres. The place the user asks about, not the user's own location.
area.bboxarray of numberNo[west, south, east, north] in decimal degrees (WGS 84). Exactly 4 items.
area.placestring or objectNoA place name or address, or a point.
area.radius_mnumberNoRadius around the place in metres. From 1 to 100000.
indexstringNondvi (B08, B04): vegetation; ndwi (B03, B08): open water; nbr (B08, B12): burn scars; ndbi (B11, B08): built-up land. One of "ndvi", "ndwi", "nbr", "ndbi". Default "ndvi".
datestringNoThe day to analyse, YYYY-MM-DD; left out, today with window_days 30 (a recent index). With compare_date, one of the two days.
compare_datestringNoThe other day for a change, YYYY-MM-DD, before or after date. The change is always the later minus the earlier.
window_daysnumberNoDays either side of each date in which to look for the clearest scene. From 0 to 45. Default 15.
zones_urlstringNoFor the index of each polygon (parcels, fields, districts) on one date: a public link to the polygons, or a TerraLab download link. The zones' extent replaces area.
zones_geojsonobjectNoThe zones as a GeoJSON FeatureCollection, Feature or polygon in WGS 84, instead of zones_url.
zones_fileobjectNoThe zones as a file uploaded in the conversation (GeoJSON, KML, KMZ, GPX, zipped Shapefile, CSV or WKT).
zones_file.download_urlstringYes
zones_file.file_idstringYes
zones_file.file_namestringNo
zones_file.mime_typestringNo
name_fieldstringNoWith zones: the attribute that names each zone. Left out: name, label or id when present. Up to 80 characters.
end_datestringNoFor a time series: the last day, YYYY-MM-DD, with date as the first. One row per month (at most 12 months a call), no GeoTIFF.
stepstringNoFor a time series. month: the clearest scene of each month. scene: the 12 least cloudy scenes of the range, one per day. One of "month", "scene". Default "month".

Response

structuredContent holds the result, content the same result as text for a model, and isError is true when the tool refused the request or failed; then structuredContent.code, message and hint say what to change.

{
  "structuredContent": {
    "sources": [{ "name": "...", "licence": "...", "url": "..." }],
    "downloads": [{ "label": "...", "format": "...", "url": "...", "name": "..." }]
  },
  "content": [{ "type": "text", "text": "..." }],
  "isError": false
}

Every result lists its sources with their licence. File results come as downloads: each link builds its file when opened.

Errors

A missing key answers 401, an empty balance 402, too many calls 429. A call that fails or finds nothing is not counted. See Errors and rate limits.

Description for agents

The text the server gives an agent to decide when to call this tool:

Use this when the user wants numbers or a change map from Sentinel-2 spectral indices: NDVI (vegetation, greenness, crops), NDWI (open water), NBR (burn scars, fire severity) or NDBI (built-up land), for an area on one date, or the change between two dates ("how much greener in July than in January", "burn scar after the fire"). Give area (or zones) and date (left out: the clearest scene of the last 30 days), and compare_date for a change. For each date it takes the clearest Copernicus Sentinel-2 L2A scene over the area within window_days (default 15), masks cloud, shadow and snow with the scene classification, and names each scene id, date and cloud cover. One date: mean, median and percentiles. Two dates: the later minus the earlier index, five classes (strong loss, loss, stable, gain, strong gain) with their area in hectares. Returns a float32 GeoTIFF (UTM, 10 m) and a coloured map. Time series (seasonal cycle, trend, "is this loss real or seasonal"): give date and end_date for one row per month, up to 12 months a call (mean, min, max, clear share, scene id) and a CSV; each month read counts as one scene. Per polygon (zonal statistics of an index): give zones_url, zones_geojson or zones_file with one date for the mean, min, max and clear share of each zone, as rows and as the zones with these attributes; the extent of the zones is the area. Areas up to 20 x 20 km (radius_m 9,500 or less). Not for a plain picture or a single NDVI image file (get_satellite_image), live weather, or to explain what an index is. Never use the user's current location unless they type it. Download links build their file when opened; no file is saved. The user opens the file in QGIS or any GIS: this server cannot load it into the user's own QGIS or any app on their computer. Never pass these links to open_gis_file.

Updated 2026-11-15