Skip to main content
Glama

get_mars_rover_manifest

Retrieve mission manifests for Mars rovers to access landing dates, operational status, photo counts, and detailed mission timelines.

Instructions

Get the mission manifest for a Mars rover (Curiosity, Opportunity, Spirit). Provides mission details like landing/launch dates, status, max sol/date, total photos, and photo counts per sol.

Args: rover_name: Name of the rover (curiosity, opportunity, spirit).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
rover_nameYes

Implementation Reference

  • The handler function implementing the get_mars_rover_manifest tool. It validates the rover name, fetches the manifest from NASA's Mars Rover Photos API, and formats the mission details including status, dates, total photos, and photo counts per sol (showing latest 5).
    async def get_mars_rover_manifest(rover_name: str) -> str:
        """Get the mission manifest for a Mars rover (Curiosity, Opportunity, Spirit).
        Provides mission details like landing/launch dates, status, max sol/date, total photos, and photo counts per sol.
        
        Args:
            rover_name: Name of the rover (curiosity, opportunity, spirit).
        """
        rover_name = rover_name.lower()
        if rover_name not in ROVER_CAMERAS:
            return f"Invalid rover name. Available rovers: {', '.join(ROVER_CAMERAS.keys())}"
            
        url = f"{NASA_API_BASE}/mars-photos/api/v1/manifests/{rover_name}"
        data = await make_nasa_request(url)
        
        if not data:
            return f"Could not retrieve mission manifest for {rover_name} due to a connection error."
        
        # Check for error response (must be a dictionary)
        if isinstance(data, dict) and "error" in data:
            return f"API Error: {data.get('error')} - Details: {data.get('details', 'N/A')}"
        if isinstance(data, dict) and data.get("binary_content"):
            return f"Received unexpected binary content from Mars Rover Manifest API. URL: {data.get('url')}"
        
        # Response should be a dictionary containing 'photo_manifest'
        if not isinstance(data, dict) or "photo_manifest" not in data:
            logger.error(f"Unexpected response format from Mars Rover Manifest API: {data}")
            return "Received unexpected data format from Mars Rover Manifest API."
    
        try:
            manifest = data.get("photo_manifest", {})
            result = [
                f"Mission Manifest for Rover: {manifest.get('name', 'Unknown')}",
                f"Status: {manifest.get('status', 'Unknown')}",
                f"Launch Date: {manifest.get('launch_date', 'Unknown')}",
                f"Landing Date: {manifest.get('landing_date', 'Unknown')}",
                f"Max Sol: {manifest.get('max_sol', 'Unknown')}",
                f"Max Earth Date: {manifest.get('max_date', 'Unknown')}",
                f"Total Photos: {manifest.get('total_photos', 'Unknown')}",
                "nPhoto Summary per Sol (showing latest 5 sols with photos):"
            ]
            
            photos_per_sol = manifest.get('photos', [])
            # Sort by sol descending to show latest first
            photos_per_sol_sorted = sorted(photos_per_sol, key=lambda x: x.get('sol', -1), reverse=True)
            
            display_limit = 5
            count = 0
            for sol_info in photos_per_sol_sorted:
                if count >= display_limit:
                    result.append(f"n... and {len(photos_per_sol) - display_limit} more sols with photos.")
                    break
                result.append(f"  Sol {sol_info.get('sol', 'N/A')}: {sol_info.get('total_photos', 0)} photos")
                result.append(f"    Cameras: {', '.join(sol_info.get('cameras', []))}")
                count += 1
                
            return "n".join(result)
        except Exception as e:
            logger.error(f"Error processing Mars Rover Manifest data: {str(e)}")
            return f"Error processing Mars Rover Manifest data: {str(e)}"
  • Helper dictionary defining valid Mars rovers and their camera types, used for input validation in the get_mars_rover_manifest and get_mars_rover_photos tools.
    ROVER_CAMERAS = {
        "curiosity": ["FHAZ", "RHAZ", "MAST", "CHEMCAM", "MAHLI", "MARDI", "NAVCAM"],
        "opportunity": ["FHAZ", "RHAZ", "NAVCAM", "PANCAM", "MINITES"],
        "spirit": ["FHAZ", "RHAZ", "NAVCAM", "PANCAM", "MINITES"]
    }
  • Shared helper function to make HTTP requests to NASA APIs, handle JSON/binary responses, errors, and API key inclusion. Used by get_mars_rover_manifest to fetch the manifest data.
    async def make_nasa_request(url: str, params: dict = None) -> Union[dict[str, Any], List[Any], None]:
        """Make a request to the NASA API with proper error handling.
        Handles both JSON and binary (image) responses.
        """
        
        logger.info(f"Making request to: {url} with params: {params}")
        
        if params is None:
            params = {}
        
        # Ensure API key is included in parameters
        if "api_key" not in params:
            params["api_key"] = API_KEY
        
        async with httpx.AsyncClient() as client:
            try:
                response = await client.get(url, params=params, timeout=30.0, follow_redirects=True)
                response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
    
                content_type = response.headers.get("Content-Type", "").lower()
                
                if "application/json" in content_type:
                    try:
                        return response.json()
                    except json.JSONDecodeError as json_err:
                        logger.error(f"JSON decode error for URL {response.url}: {json_err}")
                        logger.error(f"Response text: {response.text[:500]}") # Log beginning of text
                        return {"error": "Failed to decode JSON response", "details": str(json_err)}
                elif content_type.startswith("image/"):
                    logger.info(f"Received binary image content ({content_type}) from {response.url}")
                    # Return a dictionary indicating binary content was received
                    return {
                        "binary_content": True, 
                        "content_type": content_type,
                        "url": str(response.url) # Return the final URL after redirects
                    }
                else:
                    # Handle other unexpected content types
                    logger.warning(f"Unexpected content type '{content_type}' received from {response.url}")
                    return {"error": f"Unexpected content type: {content_type}", "content": response.text[:500]}
    
            except httpx.HTTPStatusError as http_err:
                logger.error(f"HTTP error occurred: {http_err} - {http_err.response.status_code} for URL {http_err.request.url}")
                try:
                    # Try to get more details from response body if possible
                    error_details = http_err.response.json()
                except Exception:
                    error_details = http_err.response.text[:500]
                return {"error": f"HTTP error: {http_err.response.status_code}", "details": error_details}
            except httpx.RequestError as req_err:
                logger.error(f"Request error occurred: {req_err} for URL {req_err.request.url}")
                return {"error": "Request failed", "details": str(req_err)}
            except Exception as e:
                logger.error(f"An unexpected error occurred: {str(e)}")
                return {"error": "An unexpected error occurred", "details": str(e)}
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It describes the data returned (mission details) but lacks behavioral traits such as whether this is a read-only operation, potential rate limits, authentication needs, or error handling. The description does not contradict annotations, but it fails to disclose key operational aspects beyond the basic function.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded, starting with the core purpose followed by details and parameter explanation. Every sentence adds value, though the structure could be slightly more streamlined by integrating the parameter details more seamlessly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the low complexity (1 parameter, no output schema, no annotations), the description covers the basic purpose and parameter semantics adequately. However, it lacks details on behavioral aspects (e.g., read-only nature, error cases) and does not fully compensate for the absence of annotations and output schema, leaving gaps in operational context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage and 1 parameter, the description compensates by explaining the parameter's purpose ('Name of the rover') and providing valid values (curiosity, opportunity, spirit). This adds meaningful context beyond the bare schema, though it could specify format constraints (e.g., lowercase).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Get the mission manifest') and resource ('Mars rover'), listing the exact rovers (Curiosity, Opportunity, Spirit) and detailing the mission information provided (landing/launch dates, status, etc.). This distinguishes it from sibling tools like get_mars_rover_photos, which focuses on photos rather than manifest data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by specifying the rover names and the type of data returned, but it does not explicitly state when to use this tool versus alternatives (e.g., get_mars_rover_photos for photos instead of manifest details). No exclusions or prerequisites are mentioned, leaving some ambiguity for the agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AnCode666/nasa-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server