Skip to main content
Glama
elad12390

Web Research Assistant

by elad12390

search_images

Find royalty-free stock images from Pixabay for projects, presentations, or design work. Search photos, illustrations, and vector graphics with filters for type and orientation.

Instructions

Search for high-quality stock images using Pixabay.

Returns royalty-free images that are safe to use. Perfect for finding photos,
illustrations, and vector graphics for projects, presentations, or design work.

Image Types:
- 'photo': Real photographs
- 'illustration': Digital illustrations and artwork
- 'vector': Vector graphics (SVG format available)
- 'all': All types (default)

Examples:
- search_images("mountain landscape", image_type="photo")
- search_images("business icons", image_type="vector")
- search_images("technology background", orientation="horizontal")

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes
reasoningYes
image_typeNoall
orientationNoall
max_resultsNo

Implementation Reference

  • MCP tool handler for 'search_images'. Handles input validation via Annotated types (schema), calls PixabayClient for API search or falls back to SearxNG web search if no API key. Formats and returns image results.
    @mcp.tool()
    async def search_images(
        query: Annotated[
            str,
            "What to search for (e.g., 'sunset beach', 'office workspace', 'technology abstract')",
        ],
        reasoning: Annotated[str, "Why you're searching for images (required for analytics)"],
        image_type: Annotated[
            Literal["all", "photo", "illustration", "vector"],
            "Type of image to search for",
        ] = "all",
        orientation: Annotated[
            Literal["all", "horizontal", "vertical"],
            "Image orientation preference",
        ] = "all",
        max_results: Annotated[int, "Maximum number of results (1-20)"] = 10,
    ) -> str:
        """
        Search for high-quality stock images using Pixabay.
    
        Returns royalty-free images that are safe to use. Perfect for finding photos,
        illustrations, and vector graphics for projects, presentations, or design work.
    
        Image Types:
        - 'photo': Real photographs
        - 'illustration': Digital illustrations and artwork
        - 'vector': Vector graphics (SVG format available)
        - 'all': All types (default)
    
        Examples:
        - search_images("mountain landscape", image_type="photo")
        - search_images("business icons", image_type="vector")
        - search_images("technology background", orientation="horizontal")
        """
        start_time = time.time()
        success = False
        error_msg = None
        result = ""
    
        try:
            # Check if API key is configured
            if not pixabay_client.has_api_key():
                # Fallback: Use web search for images instead
                fallback_results = await searcher.search(
                    f"{query} stock photo free",
                    category="images",
                    max_results=max_results,
                )
    
                if fallback_results:
                    lines = [
                        f"Image Search Results for: {query}",
                        "(Using web search - configure PIXABAY_API_KEY for better stock photo results)",
                        "─" * 70,
                        "",
                    ]
                    for idx, hit in enumerate(fallback_results, 1):
                        lines.append(f"{idx}. {hit.title}")
                        lines.append(f"   {hit.url}")
                        if hit.snippet:
                            lines.append(f"   {hit.snippet[:100]}")
                        lines.append("")
    
                    lines.extend(
                        [
                            "─" * 70,
                            "For better stock photo results with resolution info:",
                            "1. Get a free API key from: https://pixabay.com/api/docs/",
                            "2. Set: PIXABAY_API_KEY=your_key_here",
                        ]
                    )
                    result = clamp_text("\n".join(lines), MAX_RESPONSE_CHARS)
                    success = True  # Mark as success since we provided useful results
                else:
                    result = (
                        "⚠️ Pixabay API key not configured and web search returned no results.\n\n"
                        "To enable full image search:\n"
                        "1. Get a free API key from: https://pixabay.com/api/docs/\n"
                        "2. Set the environment variable: PIXABAY_API_KEY=your_key_here\n"
                        "3. Restart the MCP server"
                    )
                    error_msg = "API key not configured"
                    success = False
            else:
                max_results = max(1, min(max_results, 20))
    
                images = await pixabay_client.search_images(
                    query=query,
                    image_type=image_type,
                    orientation=orientation,
                    per_page=max_results,
                )
    
                if not images:
                    result = f"No images found for '{query}'.\n\nTry:\n- Different search terms\n- Broader keywords\n- Different image type or orientation"
                else:
                    # Format results
                    lines = [
                        f"Stock Images for: {query}",
                        f"Type: {image_type.title()} | Orientation: {orientation.title()} | Found: {len(images)} images",
                        "─" * 70,
                        "",
                    ]
    
                    for idx, img in enumerate(images, 1):
                        lines.append(f"{idx}. {img.tags}")
                        lines.append(
                            f"   Resolution: {img.width}x{img.height} | 👁️ {img.views:,} | ⬇️ {img.downloads:,} | ❤️ {img.likes:,}"
                        )
                        lines.append(f"   By: {img.user}")
                        lines.append(f"   Preview: {img.preview_url}")
                        lines.append(f"   Large: {img.large_url}")
                        if img.full_url != img.large_url:
                            lines.append(f"   Full HD: {img.full_url}")
                        lines.append("")
    
                    result = clamp_text("\n".join(lines), MAX_RESPONSE_CHARS)
    
                success = True
    
        except ValueError as exc:
            # API key not configured
            error_msg = str(exc)
            result = f"⚠️ {exc}\n\nPlease configure your Pixabay API key as described above."
        except httpx.HTTPStatusError as exc:
            error_msg = f"HTTP {exc.response.status_code}"
            if exc.response.status_code == 400:
                result = f"Invalid search parameters for '{query}'. Please check your search terms and filters."
            elif exc.response.status_code == 429:
                result = "Rate limit exceeded. Please wait a moment and try again."
            else:
                result = f"Failed to search images: HTTP {exc.response.status_code}"
        except Exception as exc:  # noqa: BLE001
            error_msg = str(exc)
            result = f"Image search failed for '{query}': {exc}"
        finally:
            # Track usage
            response_time = (time.time() - start_time) * 1000
            tracker.track_usage(
                tool_name="search_images",
                reasoning=reasoning,
                parameters={
                    "query": query,
                    "image_type": image_type,
                    "orientation": orientation,
                    "max_results": max_results,
                },
                response_time_ms=response_time,
                success=success,
                error_message=error_msg,
                response_size=len(result.encode("utf-8")),
            )
    
        return result
  • Core helper method in PixabayClient that performs the actual API call to Pixabay and parses results into StockImage dataclass instances. Called by the MCP handler.
    async def search_images(
        self,
        query: str,
        *,
        image_type: Literal["all", "photo", "illustration", "vector"] = "all",
        orientation: Literal["all", "horizontal", "vertical"] = "all",
        category: str = "",
        min_width: int = 0,
        min_height: int = 0,
        colors: str = "",
        safe_search: bool = True,
        per_page: int = 20,
        page: int = 1,
    ) -> list[StockImage]:
        """
        Search for stock images on Pixabay.
    
        Args:
            query: Search term
            image_type: Type of image (all, photo, illustration, vector)
            orientation: Image orientation (all, horizontal, vertical)
            category: Category filter (backgrounds, fashion, nature, science, etc.)
            min_width: Minimum image width in pixels
            min_height: Minimum image height in pixels
            colors: Filter by color (red, orange, yellow, green, turquoise, blue, etc.)
            safe_search: Enable safe search
            per_page: Images per page (3-200)
            page: Page number
    
        Returns:
            List of StockImage objects
        """
        if not self.has_api_key():
            raise ValueError("Pixabay API key not configured")
    
        params = {
            "key": self.api_key,
            "q": query,
            "image_type": image_type,
            "per_page": min(200, max(3, per_page)),
            "page": page,
            "safesearch": "true" if safe_search else "false",
        }
    
        # Add optional filters
        if orientation != "all":
            params["orientation"] = orientation
        if category:
            params["category"] = category
        if min_width > 0:
            params["min_width"] = min_width
        if min_height > 0:
            params["min_height"] = min_height
        if colors:
            params["colors"] = colors
    
        async with httpx.AsyncClient(timeout=self.timeout, headers=self._headers) as client:
            response = await client.get(self.BASE_URL, params=params)
            response.raise_for_status()
            data = response.json()
    
        images = []
        for hit in data.get("hits", []):
            images.append(
                StockImage(
                    id=hit["id"],
                    preview_url=hit["previewURL"],
                    large_url=hit["largeImageURL"],
                    full_url=hit.get("fullHDURL") or hit["largeImageURL"],
                    width=hit["imageWidth"],
                    height=hit["imageHeight"],
                    views=hit["views"],
                    downloads=hit["downloads"],
                    likes=hit["likes"],
                    tags=hit["tags"],
                    user=hit["user"],
                    user_id=hit["user_id"],
                )
            )
    
        return images
  • Dataclass defining the structure of individual stock image results returned by the search.
    @dataclass(slots=True)
    class StockImage:
        """Represents a stock image result from Pixabay."""
    
        id: int
        preview_url: str
        large_url: str
        full_url: str
        width: int
        height: int
        views: int
        downloads: int
        likes: int
        tags: str
        user: str
        user_id: int
  • The @mcp.tool() decorator registers the search_images function as an MCP tool.
    @mcp.tool()
  • Global PixabayClient instance used by the search_images handler.
    pixabay_client = PixabayClient()

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/elad12390/web-research-assistant'

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