Skip to main content
Glama

get_astronomy_picture_of_day

Retrieve NASA's Astronomy Picture of the Day to access daily space images with options for specific dates, random selections, or video thumbnails.

Instructions

Get NASA's astronomy picture of the day.

Args: date: Date of the image in YYYY-MM-DD format. If not specified, the current date is used. count: If specified, returns 'count' random images. Cannot be used with 'date'. thumbs: If True, returns the thumbnail URL for videos. If APOD is not a video, this parameter is ignored.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
dateNo
countNo
thumbsNo

Implementation Reference

  • The handler function that implements the 'get_astronomy_picture_of_day' tool. It fetches APOD data from the NASA API, handles single or multiple images, formats the response with title, explanation, URL, etc., and includes error handling.
    @mcp.tool()
    async def get_astronomy_picture_of_day(date: str = None, count: int = None, thumbs: bool = False) -> str:
        """Get NASA's astronomy picture of the day.
        
        Args:
            date: Date of the image in YYYY-MM-DD format. If not specified, the current date is used.
            count: If specified, returns 'count' random images. Cannot be used with 'date'.
            thumbs: If True, returns the thumbnail URL for videos. If APOD is not a video, this parameter is ignored.
        """
        params = {}
        
        if date:
            params["date"] = date
        if count:
            params["count"] = count
        if thumbs:
            params["thumbs"] = "true"
        
        url = f"{NASA_API_BASE}/planetary/apod"
        data = await make_nasa_request(url, params)
        
        if not data:
            return "Could not retrieve astronomy picture of the day data 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"):
             # APOD URL itself might point to an image, but the API response should be JSON
            return f"Received unexpected binary content from APOD API. URL: {data.get('url')}"
    
        try:
            # If count is specified, data will be a list
            if isinstance(data, list):
                result = []
                for item in data:
                    result.append(f"Date: {item.get('date', 'Unknown')}")
                    result.append(f"Title: {item.get('title', 'No title')}")
                    result.append(f"Explanation: {item.get('explanation', 'No explanation')}")
                    result.append(f"URL: {item.get('url', 'Not available')}")
                    if 'copyright' in item:
                        result.append(f"Copyright: {item.get('copyright', 'Unknown')}")
                    if thumbs and 'thumbnail_url' in item:
                        result.append(f"Thumbnail URL: {item.get('thumbnail_url', 'Not available')}")
                    result.append("-" * 40)
                
                return "n".join(result)
            else:
                # If it's a single image
                result = f"""
    Date: {data.get('date', 'Unknown')}
    Title: {data.get('title', 'No title')}
    Explanation: {data.get('explanation', 'No explanation')}
    URL: {data.get('url', 'Not available')}
    """
                if 'copyright' in data:
                    result += f"Copyright: {data.get('copyright', 'Unknown')}n"
                if thumbs and 'thumbnail_url' in data:
                    result += f"Thumbnail URL: {data.get('thumbnail_url', 'Not available')}n"
                
                return result
        except Exception as e:
            logger.error(f"Error processing APOD data: {str(e)}")
            return f"Error processing astronomy picture data: {str(e)}"
  • Shared helper function used by the tool (and others) to perform HTTP requests to NASA APIs, automatically adding the API key, handling JSON/binary responses, timeouts, redirects, and various errors.
    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)}
Behavior3/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 discloses behavioral traits: it retrieves data (implied read-only), handles defaults (current date if 'date' not specified), and describes parameter interactions (e.g., 'count' cannot be used with 'date'). However, it lacks details on rate limits, authentication needs, or error handling, which are important for a public API tool.

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 detailed Args. Every sentence earns its place by clarifying parameter usage. However, it could be slightly more concise by integrating the purpose and Args more seamlessly, and the structure is functional but not optimal for quick scanning.

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 complexity (3 parameters, no annotations, no output schema), the description is moderately complete. It explains parameters well and provides usage guidelines, but lacks output details (e.g., what data is returned) and broader context like API limitations or error cases. For a tool with no structured output, more information on return values would enhance completeness.

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

Parameters5/5

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

The schema description coverage is 0%, so the description must compensate fully. It adds significant meaning beyond the input schema by explaining each parameter's purpose, format (e.g., 'YYYY-MM-DD'), defaults, constraints (e.g., 'count' vs. 'date' exclusion), and behavior (e.g., 'thumbs' ignored for non-videos). This comprehensively covers all three parameters, providing essential context not in the schema.

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

Purpose4/5

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

The description clearly states the tool's purpose: 'Get NASA's astronomy picture of the day.' It specifies the verb 'Get' and the resource 'NASA's astronomy picture of the day,' which is distinct from sibling tools like those for asteroids, Mars rovers, or solar events. However, it does not explicitly differentiate from all siblings, as some might also retrieve images (e.g., get_earth_imagery), so it lacks full sibling differentiation.

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

Usage Guidelines4/5

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

The description provides clear context for usage through the Args section, explaining when to use parameters like 'date' for specific dates, 'count' for random images, and 'thumbs' for videos. It includes an exclusion rule: 'Cannot be used with 'date'' for 'count.' However, it does not explicitly state when to use this tool versus alternatives among siblings, such as for astronomy-specific images versus other NASA imagery tools.

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