MCP server exposing ISRO's Bhoonidhi EO portal to AI agents, over the bhoonidhi-downloader SDK
Strong tool definitions with comprehensive descriptions (avg 250+ chars) and well-structured schemas. All 9 tools have explicit input schemas with typed parameters and descriptions. Tool names follow verb_noun convention (list_, search_, resolve_, save_, show_, remove_, preview_, auth_). Output shapes are documented in code comments. Key gaps: no enum constraints on satellite/sensor/product parameters (invites hallucination), no pagination support despite MAX_RESULTS cap, missing error recovery guidance in descriptions, no tool annotations (readOnlyHint/destructiveHint), and parameter relationships (e.g., mutually exclusive AOI params) underdocumented in descriptions themselves.
Report whether a Bhoonidhi login is configured for downloads and cart. Never asks for or returns a password or token. If credentials are set in the server's environment (BHOONIDHI_USERNAME / BHOONIDHI_PASSWORD) it establishes the session so the answer matches what a download or cart action would find.
List every satellite and sensor the Bhoonidhi portal supports. Returns the vocabulary of valid satellites, sensors, and exact search tokens, with each product's resolution and date coverage. Call this to discover what can be searched. Set refresh=True to bypass the local cache.
List every saved query as compact summaries. Returns each saved query's slug, name, date range, satellites, area of interest, scene count, and a plain-English availability summary — but not the full scene lists (call show_query for one query's scenes). Use this to find the slug for a query the user saved earlier.
Dry-run a download for a search: show what would be fetched, no login. Takes the same arguments as search_scenes, plus out_dir (where files would go) and force (preview re-downloading files already present). It runs the search and predicts, per scene, what a real download would do: would_download (staged, ready), may_404 (open data but archived — attempted but may fail until requested on the portal), already_here / already_elsewhere (a matching file exists), or skipped_on_order / skipped_priced (needs the portal). Use this before telling a user to download, so they know how many scenes are actually fetchable. Nothing is downloaded and no login is used. File sizes are not known until a download starts (the portal exposes them only in the download response headers), and interrupted downloads cannot be resumed — both are stated in the result's disclaimers.
search_scenes and preview_download accept free-form 'satellite', 'sensor', 'product' strings without enum constraints. LLMs will hallucinate invalid values; should return enum list from list_archive or validate against vocabulary with actionable error messages.
Mutually exclusive AOI parameters (bounding box vs point+radius) are documented in tool description but NOT in individual parameter descriptions. LLMs cannot parse this constraint from prose; should add explicit 'mutually exclusive with lat/lon/radius_km' to minx/maxx/miny/maxy descriptions.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) in schema. remove_query is destructive, search_scenes is read-only, save_query is write, these should be explicitly marked for agent safety and planning.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 62 | 2026-07-28+ | v2 |
Delete a saved query by slug. Give the slug from save_query or list_queries. Removes the saved query from disk; the scenes themselves are unaffected. Returns status="not_found" if no query has that slug.
Resolve a place name to a centroid and bounding box. Turns a place like "Shillong" or "Loktak Lake" into latitude/longitude and a bounding box (minx, miny, maxx, maxy) that search_scenes can use as its area of interest. Returns found=False when the place can't be resolved.
Persist a search as a saved query and return a reusable slug. Takes the same arguments as search_scenes, plus an optional name and description. Unlike search_scenes (which is stateless and leaves nothing behind), this saves the search on the portal so it can be acted on later: the returned slug is what downloading and cart staging key off. Call this once the user has confirmed a search returns the scenes they want, then hand the slug to the bhd CLI (download / cart) until those actions land in-server. Returns status="ok" with the slug and the shaped saved query. If the satellite is ambiguous or the request is invalid, returns the same status="ambiguous_satellite" / "invalid_request" shapes as search_scenes, and saves nothing.
Search Bhoonidhi scenes for a satellite over an area and date range. The satellite may be a casual name ("Sentinel-2", "cartosat"); it is matched to the portal's exact tokens, and a constellation expands to all its platforms. Dates are ISO (YYYY-MM-DD). Give the area either as a bounding box (minx/maxx/miny/maxy) or a point with radius (lat/lon/radius_km) — typically from resolve_location. sensor narrows to one sensor on the matched satellite(s) (e.g. "SSAR", "LISS3"); product further narrows to one product under that sensor (e.g. "GCOV", "L2C-Chlorophyll") — see list_archive for the exact sensor/product names each satellite carries. The search is stateless and needs no login. If the satellite name is ambiguous, returns status="ambiguous_satellite" with candidate names instead of guessing. Each scene carries an "availability": Ready (downloadable now), Archived (open data but may need a portal request first), OnOrder (must be requested), or Priced (must be purchased). The result includes a plain-English "summary" of these counts and a "how_to_act" block. Tell the user clearly when scenes are Archived, OnOrder, or Priced and what each needs. This search is stateless: to act on these scenes, call save_query with the same arguments to persist them and get a <slug>, then download_query (open data) or cart_add (on-order / priced) on that slug — both need a login (see auth_status). Downloads cannot be resumed if interrupted (the portal has no range support).
Return one saved query by slug, with its scenes. Give the slug from save_query or list_queries. Returns the full saved query: its selections, area of interest, date range, and shaped scenes with availability. Returns status="not_found" if no query has that slug.
search_scenes and preview_download cap results at MAX_RESULTS (50) but do not expose pagination (limit, offset, next_cursor). Large result sets are truncated silently; agent cannot iterate. Should add limit/offset params and return total count.
Error responses in code (e.g., 'ambiguous_satellite', 'invalid_request', 'not_found') are documented in tool descriptions but lack recovery guidance. Should include 'Call list_archive to see valid satellites' or 'Try resolve_location first' in error shapes.