9 Commits

Author SHA1 Message Date
82ae699c07 Add MCP prompts, README, LICENSE, and PyPI metadata
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.
2026-02-19 11:32:17 -07:00
4a5035ca52 Fix legend images: rewrite GIBS SVG URLs to PNG for API compatibility
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).
2026-02-18 18:53:15 -07:00
db6ed2f550 Use FastMCP Image type, Context progress, and dynamic resources
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.
2026-02-18 18:30:32 -07:00
d13ba744d3 Add Hamilton fix test coverage and graceful shutdown
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.
2026-02-18 18:19:21 -07:00
c2d54e7d59 Fix redundant except clause: ValueError is subclass of Exception
except (ValueError, Exception) was redundant since ValueError
already inherits from Exception. Simplified all 3 occurrences in
the bbox resolution error handlers.
2026-02-18 18:15:41 -07:00
31dff49351 Fix colormap parsing against live GIBS API
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.
2026-02-18 15:47:52 -07:00
d163ade9a4 Harden codebase from Hamilton code review findings
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
2026-02-18 15:14:02 -07:00
f7fad32a9e Implement mcgibs FastMCP server for NASA GIBS
Complete implementation of all modules:
- constants.py: GIBS API endpoints, projections, TileMatrixSet defs
- models.py: Pydantic models for layers, colormaps, geocoding
- geo.py: Nominatim geocoding with rate limiting and caching
- capabilities.py: WMTS GetCapabilities XML parser with search
- colormaps.py: Colormap v1.3 parser with natural-language summaries
- client.py: Async GIBS HTTP client wrapping all API interactions
- server.py: FastMCP 3.0 tools, resources, and prompts

11 MCP tools, 3 resources, 2 prompts. 47 tests, all passing.
2026-02-18 14:55:41 -07:00
648c145e14 Initial project skeleton
pyproject.toml with FastMCP 3.0, Pillow, src-layout, and mcgibs script entry point.
2026-02-18 14:41:44 -07:00