- Add polar stereographic coordinate transform (EPSG:3413/3031) in geo.py so geographic bboxes are properly converted to projected meters - Auto-detect image format: PNG for colormapped layers (preserves exact colors for query_point reverse-mapping), JPEG for true-color - get_imagery format parameter now defaults to "auto" instead of "jpeg" - Embed NDVI seasonal timelapse and polar stereo images in README - 96 tests passing
141 lines
5.2 KiB
Python
141 lines
5.2 KiB
Python
"""Fetch example images for the README via the mcgibs MCP server.
|
|
|
|
Uses the FastMCP in-process Client to call tools through the MCP protocol,
|
|
exactly as any MCP client would. Images are saved to docs/images/.
|
|
"""
|
|
|
|
import asyncio
|
|
import base64
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from fastmcp import Client
|
|
|
|
# Wire up the server module so the client is initialized
|
|
import mcgibs.server as server_module
|
|
from mcgibs.client import GIBSClient
|
|
from mcgibs.server import mcp
|
|
|
|
OUT = Path(__file__).parent.parent / "docs" / "images"
|
|
|
|
|
|
async def save_imagery(client: Client, filename: str, tool: str, params: dict) -> None:
|
|
"""Call an imagery tool and save the returned image to disk."""
|
|
print(f" Fetching {filename}...", file=sys.stderr)
|
|
result = await client.call_tool(tool, params)
|
|
|
|
# Find the ImageContent in the response
|
|
for content in result.content:
|
|
if content.type == "image":
|
|
img_bytes = base64.b64decode(content.data)
|
|
path = OUT / filename
|
|
path.write_bytes(img_bytes)
|
|
size_kb = len(img_bytes) / 1024
|
|
print(f" Saved {path} ({size_kb:.0f} KB)", file=sys.stderr)
|
|
return
|
|
|
|
# If we got text only (error case), print it
|
|
for content in result.content:
|
|
if content.type == "text":
|
|
print(f" Warning: {content.text[:200]}", file=sys.stderr)
|
|
|
|
|
|
async def main():
|
|
OUT.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Initialize GIBS client (normally done by middleware on first connection)
|
|
print("Initializing GIBS client...", file=sys.stderr)
|
|
gibs = GIBSClient()
|
|
await gibs.initialize()
|
|
server_module._client = gibs
|
|
print(f"Ready — {len(gibs.layer_index)} layers loaded", file=sys.stderr)
|
|
|
|
try:
|
|
async with Client(mcp) as client:
|
|
# 1. Amazon true color — natural satellite view
|
|
await save_imagery(client, "amazon-true-color.jpg", "get_imagery", {
|
|
"layer_id": "MODIS_Terra_CorrectedReflectance_TrueColor",
|
|
"date": "2025-08-01",
|
|
"place": "Amazon Rainforest",
|
|
"width": 1024,
|
|
"height": 768,
|
|
"format": "jpeg",
|
|
})
|
|
|
|
# 2. Global surface air temperature — scientific data product
|
|
await save_imagery(client, "temperature-global.jpg", "get_imagery", {
|
|
"layer_id": "AIRS_L3_Surface_Air_Temperature_Daily_Day",
|
|
"date": "2025-07-15",
|
|
"bbox": [-180, -90, 180, 90],
|
|
"width": 1024,
|
|
"height": 512,
|
|
"format": "jpeg",
|
|
})
|
|
|
|
# 3. Arctic sea ice comparison — March (max) vs September (min)
|
|
await save_imagery(
|
|
client, "arctic-ice-comparison.jpg", "compare_dates", {
|
|
"layer_id": "AMSRU2_Sea_Ice_Concentration_12km",
|
|
"date_before": "2025-03-01",
|
|
"date_after": "2025-09-01",
|
|
"bbox": [-180, 60, 180, 90],
|
|
},
|
|
)
|
|
|
|
# 4. Surface temperature colormap legend
|
|
await save_imagery(
|
|
client, "temperature-legend.png", "get_legend", {
|
|
"layer_id": "AIRS_L3_Surface_Air_Temperature_Daily_Day",
|
|
"orientation": "horizontal",
|
|
},
|
|
)
|
|
|
|
# 5. Colormap explanation (text, not image)
|
|
print(" Fetching temperature colormap explanation...", file=sys.stderr)
|
|
result = await client.call_tool(
|
|
"explain_layer_colormap",
|
|
{"layer_id": "AIRS_L3_Surface_Air_Temperature_Daily_Day"},
|
|
)
|
|
explanation = result.content[0].text
|
|
(OUT / "temperature-colormap.txt").write_text(explanation)
|
|
print(" Saved colormap explanation", file=sys.stderr)
|
|
|
|
# 6. Arctic sea ice in polar stereographic projection (PNG for clean colors)
|
|
await save_imagery(
|
|
client, "arctic-polar-stereo.png", "get_imagery", {
|
|
"layer_id": "AMSRU2_Sea_Ice_Concentration_12km",
|
|
"date": "2025-03-01",
|
|
"bbox": [-180, 60, 180, 90],
|
|
"width": 1024,
|
|
"height": 1024,
|
|
"projection": "3413",
|
|
},
|
|
)
|
|
|
|
# 7. NDVI time series — 3 frames (March, June, September)
|
|
# Use explicit bbox for the Great Plains (Texas panhandle → Dakotas)
|
|
# instead of geocoding, which returns a point-sized bbox.
|
|
plains_bbox = [-104, 35, -95, 45]
|
|
ndvi_dates = [
|
|
("2025-03-01", "ndvi-march.png"),
|
|
("2025-06-01", "ndvi-june.png"),
|
|
("2025-09-01", "ndvi-september.png"),
|
|
]
|
|
for ndvi_date, ndvi_name in ndvi_dates:
|
|
await save_imagery(client, ndvi_name, "get_imagery", {
|
|
"layer_id": "MODIS_Terra_NDVI_8Day",
|
|
"date": ndvi_date,
|
|
"bbox": plains_bbox,
|
|
"width": 768,
|
|
"height": 768,
|
|
})
|
|
|
|
finally:
|
|
await gibs.close()
|
|
server_module._client = None
|
|
|
|
print("Done!", file=sys.stderr)
|
|
|
|
|
|
asyncio.run(main())
|