MCP server for agents¶
copernicus-ems can run as a Model Context Protocol
server, so an LLM agent such as Claude can answer questions like "Which
floods were mapped in Italy this year, and how did the one in Emilia-Romagna
evolve?" from the published layers, not from memory.
pip install 'copernicus-ems[mcp]'
copernicus-ems mcp # stdio; --dir to choose the data directory
copernicus-ems-mcp --transport streamable-http --port 8768 # HTTP, at /mcp
Connect it¶
For an agent that reaches its tools over the network, serve the
streamable-HTTP transport. The MCP endpoint is /mcp, and GET /health
answers {"status": "ok", "server": "copernicus-ems", "version": …}
for the healthcheck. Every option has an environment variable, so a
compose file needs no command line:
copernicus-ems-mcp:
image: ghcr.io/astral-sh/uv:python3.13-bookworm-slim
command: uvx --from 'copernicus-ems[mcp]~=0.7.0' copernicus-ems-mcp
environment:
COPERNICUS_EMS_MCP_TRANSPORT: streamable-http
COPERNICUS_EMS_MCP_HOST: 0.0.0.0 # listen inside the container
COPERNICUS_EMS_MCP_PORT: "8768"
COPERNICUS_EMS_MCP_ALLOWED_HOSTS: copernicus-ems-mcp:*,localhost:*
COPERNICUS_EMS_DATA_DIR: /data # layers and exports persist here
volumes:
- ems-data:/data
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8768/health')"]
| Variable | Flag | Default |
|---|---|---|
COPERNICUS_EMS_MCP_TRANSPORT |
--transport |
stdio (or streamable-http) |
COPERNICUS_EMS_MCP_HOST |
--host |
127.0.0.1 |
COPERNICUS_EMS_MCP_PORT |
--port |
8768 |
COPERNICUS_EMS_MCP_ALLOWED_HOSTS |
--allowed-host (repeatable) |
none |
COPERNICUS_EMS_DATA_DIR |
--dir |
the user cache |
Flags win over the environment. On a 0.0.0.0 bind, set
COPERNICUS_EMS_MCP_ALLOWED_HOSTS to the names clients use: only those
Host headers are accepted, which guards against DNS rebinding. The
server has no authentication of its own: keep it on an internal
network. copernicus-ems mcp takes the same options.
Tools¶
| Tool | Returns |
|---|---|
list_activations(country, categories, since, until, limit) |
activations newest first: code, name, category, event time, countries |
activation_summary(code, hazard) |
per product: type, observed time, event km², observed (AOI) km², bbox; per AOI: largest and latest delineation |
compare_products(code, aoi_number, hazard) |
one AOI's products in time order, with the change from the previous product of the same type |
export_observed_events(code, hazard, with_masks, file_format) |
writes GeoJSON or GeoParquet files (events, observation masks) and returns their paths |
find_scenes(code, aoi_number, days, sensors, max_cloud_cover, min_coverage, per_product) |
per product: the images it was made from, and the open Sentinel-1/2 passes over its AOI with time gap, AOI coverage, cloud cover, download URLs (details) |
hazard is flood (default), landslide or all. All tools are
read-only towards Rapid Mapping; only export_observed_events writes, in
<data directory>/exports/.
A prompt, situation_report(code), asks the agent for a factual report
built only from these tools.
Design¶
- Facts, not geometry. EMSR664 is 6,334 polygons; its
activation_summaryis about 4 KB of JSON. Geometry goes to files, for GIS tools, throughexport_observed_events. - Numbers are computed, never generated. Areas are geodesic, from the
layers (the
geomodule); the model only picks the calls and writes the prose. - The semantics travel with the server. Its instructions tell the agent
what the data means: outside the AOIs is unknown, not dry;
observed_timeis when the water was seen; products of one AOI are not summed; a grading map (GRA) after a delineation (DEL) is not the flood receding, so changes are only computed within one product type. - Errors an agent can act on: a bad code, date or AOI comes back as a tool error saying what was expected.
- Cached: layers are read from the data directory after the first call, as everywhere else in the library.
Example¶
On EMSR664 (Emilia-Romagna, May 2023), compare_products("EMSR664", 1):
| Product | Type | Observed | Event km² | Change |
|---|---|---|---|---|
| AOI01_DEL_PRODUCT | DEL | 17 May 16:56 | 87.92 | — |
| AOI01_DEL_MONIT01 | DEL | 18 May 16:55 | 112.06 | +24.14 |
| AOI01_DEL_MONIT02 | DEL | 20 May 05:19 | 87.69 | −24.37 |
| AOI01_DEL_MONIT03 | DEL | 21 May 16:50 | 44.74 | −42.95 |
| AOI01_GRA_PRODUCT | GRA | 22 May 10:27 | 7.70 | — |
Contains modified Copernicus Emergency Management Service information, © European Union.