# Buffer, merge, clip or simplify features

> Index of the TerraLab docs for agents: [llms.txt](https://terra-lab.ai/docs/llms.txt). Every docs page is also served as markdown: add .md to its URL.

One GIS operation on a set of features: buffer, union, dissolve, intersection, difference, clip or simplify, returned as a file.

| | |
| --- | --- |
| REST | `POST https://mcp.terra-lab.ai/v1/tools/process_geometry` |
| MCP tool | `process_geometry` on `https://mcp.terra-lab.ai/mcp` |
| Group | Map data |

## Request

```bash
curl -X POST https://mcp.terra-lab.ai/v1/tools/process_geometry \
  -H "Authorization: Bearer $TERRALAB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation":"buffer","geojson":{"type":"LineString","coordinates":[[6.12,45.9],[6.13,45.905]]},"radius_m":200}'
```

```python
import os
import requests

response = requests.post(
    "https://mcp.terra-lab.ai/v1/tools/process_geometry",
    headers={"Authorization": f"Bearer {os.environ['TERRALAB_API_KEY']}"},
    json={
        "operation": "buffer",
        "geojson": {
            "type": "LineString",
            "coordinates": [[6.12, 45.9], [6.13, 45.905]],
        },
        "radius_m": 200,
    },
    timeout=120,
)
response.raise_for_status()
print(response.json()["structuredContent"])
```

```javascript
const response = await fetch('https://mcp.terra-lab.ai/v1/tools/process_geometry', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TERRALAB_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "operation": "buffer",
    "geojson": {
      "type": "LineString",
      "coordinates": [
        [
          6.12,
          45.9
        ],
        [
          6.13,
          45.905
        ]
      ]
    },
    "radius_m": 200
  }),
});
const data = await response.json();
console.log(data.structuredContent);
```

Other valid request bodies:

```json
{"operation":"clip","url":"https://mcp.terra-lab.ai/dl/geojson/TOKEN/buildings.geojson","area":{"place":"Annecy","radius_m":150}}
```

## Parameters

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

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `operation` | string | Yes | The operation to apply. One of `"buffer"`, `"union"`, `"intersection"`, `"difference"`, `"clip"`, `"simplify"`, `"centroid"`, `"area_length"`. |
| `file` | object | No | A file uploaded in the conversation (GeoJSON, KML, KMZ, GPX, zipped Shapefile, CSV or WKT). |
| `file.download_url` | string | Yes |  |
| `file.file_id` | string | Yes |  |
| `file.file_name` | string | No |  |
| `file.mime_type` | string | No |  |
| `url` | string | No | A public http(s) link to the features, or a TerraLab download link from an earlier answer. |
| `geojson` | object | No | The features as a GeoJSON FeatureCollection, Feature or geometry in WGS 84 (longitude, latitude). |
| `with_file` | object | No | For intersection, difference and clip: the second layer, uploaded in the conversation. |
| `with_file.download_url` | string | Yes |  |
| `with_file.file_id` | string | Yes |  |
| `with_file.file_name` | string | No |  |
| `with_file.mime_type` | string | No |  |
| `with_url` | string | No | For intersection, difference and clip: a link to the second layer, or a TerraLab download link. |
| `with_geojson` | object | No | For intersection, difference and clip: the second layer as GeoJSON in WGS 84. Only its polygons count. |
| `area` | object | No | For clip: the area to keep, as a bbox or a place with a radius (its bounding box is used). The place the user asks about, not the user's own location. |
| `area.bbox` | array of number | No | [west, south, east, north] in decimal degrees (WGS 84). Exactly 4 items. |
| `area.place` | string or object | No | A place name or address, or a point. |
| `area.radius_m` | number | No | Radius around the place in metres. From 1 to 100000. |
| `radius_m` | number | No | For buffer: the distance in metres (convert km or miles first). From 0.1 to 100000. |
| `tolerance_m` | number | No | For simplify: the largest allowed shift of the outline in metres. From 0.01 to 100000. |
| `dissolve_field` | string | No | For union: dissolve into one feature per value of this field instead of one feature. |
| `formats` | array of string | No | Download formats. All five by default. |
| `title` | string | No | Name for the map and the output files. |

## 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.

```json
{
  "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](https://terra-lab.ai/docs/errors).

## Description for agents

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

> Use this when the user wants to apply one GIS operation to a set of features (an uploaded file, a link, inline GeoJSON, or a download link from another TerraLab answer) and get the result as a file: buffer every feature by radius_m, union (dissolve all features into one, or one per value of dissolve_field), intersection or difference with a second layer, clip to a second layer or to an area (place, place with radius_m, or bbox), simplify by tolerance_m, centroid of each feature, or area_length (adds area_m2, perimeter_m and length_m to each feature, geodesic). Overlays run in WGS 84 degrees; buffer, simplify and centroid in a local equidistant projection. Up to 20,000 features and 100,000 vertices (10,000 for buffer). Returns the feature count, geometry types, total area or length, a map and GeoJSON, KML, Shapefile zip, GeoPackage and CSV downloads. Not for one distance or the area of a shape drawn in the chat: that is measure. Not for reading or converting a file without changing its geometry: that is open_gis_file. Not for styling layers, print layouts or chaining steps on the layers of a QGIS project the user has open: TerraLab AI Agent in QGIS does that. Never use the user's current location unless they type it. Download links build their file when opened; no file is saved. Never pass these links to open_gis_file: list every format the user needs in formats, in this one call. TerraLab reads the file or link to answer and keeps no copy.


Source: https://terra-lab.ai/docs/api/process_geometry · Updated 2026-10-27
