Skip to main content
Glama
CupOfOwls

Kroger MCP Server

get_product_images

Retrieve product images from specific perspectives like front or back to visually inspect grocery items before purchase. Use after get_product_details to identify available angles.

Instructions

    Get an image for a specific product from the requested perspective.
    
    Use get_product_details first to see what perspectives are available (typically "front", "back", "left", "right").
    
    Args:
        product_id: The unique product identifier
        perspective: The image perspective to retrieve (default: "front")
        location_id: Store location ID (uses preferred if not provided)
    
    Returns:
        The product image from the requested perspective
    

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
product_idYes
perspectiveNofront
location_idNo

Implementation Reference

  • The handler function for the 'get_product_images' tool. It fetches product details from the Kroger API, finds the requested perspective image URL preferring larger sizes, downloads the image, and returns it as a FastMCP Image object. Handles errors and location preferences.
    @mcp.tool()
    async def get_product_images(
        product_id: str,
        perspective: str = "front",
        location_id: Optional[str] = None,
        ctx: Context = None
    ) -> Image:
        """
        Get an image for a specific product from the requested perspective.
        
        Use get_product_details first to see what perspectives are available (typically "front", "back", "left", "right").
        
        Args:
            product_id: The unique product identifier
            perspective: The image perspective to retrieve (default: "front")
            location_id: Store location ID (uses preferred if not provided)
        
        Returns:
            The product image from the requested perspective
        """
        # Use preferred location if none provided
        if not location_id:
            location_id = get_preferred_location_id()
            if not location_id:
                return {
                    "success": False,
                    "error": "No location_id provided and no preferred location set. Use set_preferred_location first."
                }
        
        if ctx:
            await ctx.info(f"Fetching images for product {product_id} at location {location_id}")
        
        client = get_client_credentials_client()
        
        try:
            # Get product details to extract image URLs
            product_details = client.product.get_product(
                product_id=product_id,
                location_id=location_id
            )
            
            if not product_details or "data" not in product_details:
                return {
                    "success": False,
                    "message": f"Product {product_id} not found"
                }
            
            product = product_details["data"]
            
            # Check if images are available
            if "images" not in product or not product["images"]:
                return {
                    "success": False,
                    "message": f"No images available for product {product_id}"
                }
            
            # Find the requested perspective image
            perspective_image = None
            available_perspectives = []
            
            for img_data in product["images"]:
                img_perspective = img_data.get("perspective", "unknown")
                available_perspectives.append(img_perspective)
                
                # Skip if not the requested perspective
                if img_perspective != perspective:
                    continue
                    
                if not img_data.get("sizes"):
                    continue
                
                # Find the best image size (prefer large, fallback to xlarge or other available)
                img_url = None
                size_preference = ["large", "xlarge", "medium", "small", "thumbnail"]
                
                # Create a map of available sizes for quick lookup
                available_sizes = {size.get("size"): size.get("url") for size in img_data.get("sizes", []) if size.get("size") and size.get("url")}
                
                # Select best size based on preference order
                for size in size_preference:
                    if size in available_sizes:
                        img_url = available_sizes[size]
                        break
                
                if img_url:
                    try:
                        if ctx:
                            await ctx.info(f"Downloading {perspective} image from {img_url}")
                        
                        # Download image
                        response = requests.get(img_url)
                        response.raise_for_status()
                        
                        # Create Image object
                        perspective_image = Image(
                            data=response.content,
                            format="jpeg"  # Kroger images are typically JPEG
                        )
                        break
                    except Exception as e:
                        if ctx:
                            await ctx.warning(f"Failed to download {perspective} image: {str(e)}")
            
            # If the requested perspective wasn't found
            if not perspective_image:
                available_str = ", ".join(available_perspectives) if available_perspectives else "none"
                return {
                    "success": False,
                    "message": f"No image found for perspective '{perspective}'. Available perspectives: {available_str}"
                }
            
            return perspective_image
        
        except Exception as e:
            if ctx:
                await ctx.error(f"Error getting product images: {str(e)}")
            return {
                "success": False,
                "error": str(e)
            }
  • Registration of product tools (including get_product_images) by calling register_tools on the MCP server instance in the main server setup.
    product_tools.register_tools(mcp)
  • The register_tools function in product_tools module that defines and registers the get_product_images tool using @mcp.tool() decorator.
    def register_tools(mcp):
Behavior3/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. It adequately describes the core operation (retrieving images) and mentions the default perspective behavior, but doesn't cover important aspects like authentication requirements, rate limits, error conditions, or response format details beyond stating it returns 'The product image.'

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

Conciseness5/5

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

The description is efficiently structured with a purpose statement, usage guidance, parameter explanations, and return value description in just 4 sentences. Each sentence adds clear value, and the information is front-loaded with the most important guidance appearing immediately after the purpose statement.

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

Completeness4/5

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

For a read-only tool with 3 parameters and no output schema, the description provides good coverage of purpose, usage workflow, parameter meanings, and return type. The main gap is lack of behavioral details like authentication, error handling, or image format specifics, but given the tool's relative simplicity and clear sibling relationships, it's reasonably complete.

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, the description provides essential semantic context for all 3 parameters: product_id as 'unique product identifier,' perspective with default value and typical examples, and location_id with its fallback behavior. This compensates well for the schema's lack of descriptions, though it doesn't specify format constraints or validation rules.

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 an image') and resource ('for a specific product from the requested perspective'), distinguishing it from sibling tools like get_product_details which provides metadata rather than images. The verb+resource combination is precise and unambiguous.

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

Usage Guidelines5/5

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

The description explicitly provides when-to-use guidance by directing users to 'Use get_product_details first to see what perspectives are available,' creating a clear workflow dependency. It also distinguishes this tool from get_product_details by specifying this retrieves images while that tool shows available perspectives.

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/CupOfOwls/kroger-mcp'

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