Skip to main content
Glama

get_asteroids_feed

Retrieve near-Earth asteroid data for specified date ranges to monitor potential close approaches and track space objects.

Instructions

Get a list of asteroids based on their closest approach date to Earth.

Args: start_date: Start date for asteroid search in YYYY-MM-DD format. end_date: End date for asteroid search in YYYY-MM-DD format. The Feed date limit is only 7 Days. If not specified, 7 days after start_date is used.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
start_dateYes
end_dateNo

Implementation Reference

  • The handler function for the 'get_asteroids_feed' tool. It queries the NASA NEO Feed API for asteroids within a date range, processes the response to extract details like ID, name, diameter, hazardous status, approach date, distance, and velocity, and returns a formatted string summary.
    async def get_asteroids_feed(start_date: str, end_date: str = None) -> str:
        """Get a list of asteroids based on their closest approach date to Earth.
        
        Args:
            start_date: Start date for asteroid search in YYYY-MM-DD format.
            end_date: End date for asteroid search in YYYY-MM-DD format. 
            The Feed date limit is only 7 Days. If not specified, 7 days after start_date is used.
        """
        params = {
            "start_date": start_date
        }
        
        if end_date:
            params["end_date"] = end_date
        
        url = f"{NASA_API_BASE}/neo/rest/v1/feed"
        data = await make_nasa_request(url, params)
        
        if not data:
            return "Could not retrieve asteroid 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"):
            return f"Received unexpected binary content from Asteroids Feed API. URL: {data.get('url')}"
    
        try:
            element_count = data.get('element_count', 0)
            near_earth_objects = data.get('near_earth_objects', {})
            
            result = [f"Total asteroids found: {element_count}"]
            
            for date_str, asteroids in near_earth_objects.items():
                result.append(f"nDate: {date_str}")
                result.append(f"Number of asteroids: {len(asteroids)}")
                
                for asteroid in asteroids:
                    result.append(f"n  ID: {asteroid.get('id', 'Unknown')}")
                    result.append(f"  Name: {asteroid.get('name', 'Unknown')}")
                    result.append(f"  Estimated diameter (min): {asteroid.get('estimated_diameter', {}).get('kilometers', {}).get('estimated_diameter_min', 'Unknown')} km")
                    result.append(f"  Estimated diameter (max): {asteroid.get('estimated_diameter', {}).get('kilometers', {}).get('estimated_diameter_max', 'Unknown')} km")
                    result.append(f"  Potentially hazardous: {'Yes' if asteroid.get('is_potentially_hazardous_asteroid', False) else 'No'}")
                    
                    # Information about closest approach
                    close_approaches = asteroid.get('close_approach_data', [])
                    if close_approaches:
                        approach = close_approaches[0]
                        result.append(f"  Approach date: {approach.get('close_approach_date_full', 'Unknown')}")
                        result.append(f"  Distance (km): {approach.get('miss_distance', {}).get('kilometers', 'Unknown')}")
                        result.append(f"  Relative velocity (km/h): {approach.get('relative_velocity', {}).get('kilometers_per_hour', 'Unknown')}")
            
            return "n".join(result)
        except Exception as e:
            logger.error(f"Error processing Asteroids Feed data: {str(e)}")
            return f"Error processing asteroid data: {str(e)}"
  • Shared helper function used by get_asteroids_feed (and other tools) to make HTTP requests to NASA APIs, handle JSON/binary responses, errors, and add the API key.
    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)}
  • The @mcp.tool() decorator registers the get_asteroids_feed function as an MCP tool, using its signature and docstring for schema.
    async def get_asteroids_feed(start_date: str, end_date: str = None) -> str:
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 discloses the 7-day limit for the feed, which is a useful behavioral constraint. However, it lacks details on other traits such as rate limits, authentication needs, error handling, or the format of the returned list (e.g., pagination, data fields). For a tool with no annotations, this leaves significant gaps in understanding its behavior.

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: the first sentence states the purpose clearly, followed by a structured 'Args:' section that explains parameters efficiently. There's no wasted text, and the information is organized for quick comprehension, though it could be slightly more polished in formatting.

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 no annotations, no output schema, and 0% schema description coverage, the description provides basic context like purpose and parameter semantics. However, it's incomplete for a tool that likely returns a list of asteroids: it doesn't describe the output format, potential errors, or other behavioral aspects. For a data retrieval tool, this leaves the agent with insufficient information to fully understand what to expect.

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?

Schema description coverage is 0%, so the description must compensate. It adds meaningful semantics: 'start_date' and 'end_date' are defined as dates for asteroid search in YYYY-MM-DD format, and it explains that the 'end_date' defaults to 7 days after 'start_date' if not specified, with a 7-day limit. This clarifies usage beyond the bare schema, though it doesn't cover all potential edge cases or validation rules.

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 a list of asteroids based on their closest approach date to Earth.' It specifies the verb ('Get'), resource ('list of asteroids'), and key criterion ('closest approach date to Earth'). However, it doesn't explicitly differentiate from siblings like 'browse_asteroids' or 'get_asteroid_lookup,' which might offer different asteroid-related functionalities.

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 mentioning the date-based search and a 7-day limit, suggesting it's for retrieving asteroids approaching Earth within a specific timeframe. However, it doesn't provide explicit guidance on when to use this tool versus alternatives like 'browse_asteroids' or 'get_asteroid_lookup,' nor does it specify exclusions or prerequisites beyond the date constraints.

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