Fetch script uses FastMCP Client to call tools through MCP protocol.
Includes Amazon true color, global temperature with legend,
and Arctic sea ice March vs September comparison.
Conversational examples now grounded in actual tool output.
Five new prompts guide LLMs through multi-tool workflows:
satellite_snapshot, climate_monitor, layer_deep_dive,
multi_layer_story, polar_watch. README documents all 11 tools,
5 resources, and 7 prompts with example conversations.
MIT license, project URLs, and updated classifiers for PyPI.
GIBS capabilities list .svg legend URLs, but the Anthropic API only
accepts raster image types. GIBS hosts PNG versions at the same path,
so we rewrite .svg → .png and validate content-type on both legend
fetch paths (direct URL and WMS GetLegendGraphic fallback).
Replace hand-rolled base64 dicts with FastMCP's Image() helper in
get_imagery, compare_dates, get_imagery_composite, and get_legend.
FastMCP handles base64 encoding and MIME type automatically.
Add Context progress reporting to imagery tools so MCP clients can
display fetch status (resolving location, fetching imagery, etc).
Add dynamic resources:
gibs://colormap/{layer_id} — colormap explanation text
gibs://dates/{layer_id} — date range + live DescribeDomains
Remove unused base64 import.
Tests: 79 total (32 new), covering LRU cache eviction, BBox
validation, _parse_rgb error handling, colormap ID extraction,
client retry logic, WMS response validation, dimension clamping,
geocode caching, classification colormaps, and scientific notation
interval parsing.
Shutdown: register atexit handler to close httpx connection pool
when the MCP server exits, since FastMCP Middleware has no
on_shutdown hook.
except (ValueError, Exception) was redundant since ValueError
already inherits from Exception. Simplified all 3 occurrences in
the bbox resolution error handlers.
Two bugs found via headless Claude CLI integration testing:
1. Colormap ID extraction: _detect_colormap returned the layer
identifier as colormap_id, but GIBS layers often share colormaps
under different filenames (e.g., AMSRU2_Sea_Ice_Concentration_12km
-> colormap AMSR2_Sea_Ice_Concentration.xml). Now parses the actual
filename from the metadata xlink:href.
2. Entries wrapper: GIBS v1.3 colormap XML nests ColorMapEntry elements
inside an <Entries> wrapper. The parser only searched direct children
of <ColorMap>, finding zero entries from live data. Now checks
Entries/ColorMapEntry first, falling back to direct children.
Updated test fixture to use the real <Entries> wrapper structure.
Address 20 findings from safety-critical review:
CRITICAL:
- C1: Replace ET.fromstring with defusedxml across all XML parsers
- C2: Fix client init failure leaving half-initialized state; clean
up HTTP client on startup failure so next connection can retry
HIGH:
- H1: Replace unbounded dicts with LRU caches (maxsize=500)
- H2: Move Nominatim rate limiter from module globals to per-instance
state on GIBSClient, eliminating shared mutable state
- H3: Validate _parse_rgb input, return (0,0,0) on malformed data
- H4: Add exponential backoff retry for capabilities loading
- H5: Invert WMS error detection to verify image content-type
- H6: Clamp image dimensions to 4096 max to prevent OOM
MEDIUM:
- M1: Convert images to RGB mode in compare_dates for RGBA safety
- M2: Narrow DescribeDomains XML matching to TimeDomain elements
- M3: Add BBox model_validator for coordinate range validation
- M4: Add ET.ParseError to colormap fetch exception handling
- M5: Replace bare except Exception with specific types in server
- M6: Catch ValueError from _resolve_bbox in imagery tools for
consistent error returns
- M7: Only cache successful geocoding lookups (no negative caching)
LOW:
- L3: Derive USER_AGENT version from package __version__
- L5: Remove unused start_date/end_date params from check_layer_dates