search_images
Find royalty-free stock images from Pixabay for projects, presentations, or design work. Search photos, illustrations, and vector graphics by query, 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
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| reasoning | Yes | ||
| image_type | No | all | |
| orientation | No | all | |
| max_results | No |
Input Schema (JSON Schema)
{
"properties": {
"image_type": {
"default": "all",
"enum": [
"all",
"photo",
"illustration",
"vector"
],
"title": "Image Type",
"type": "string"
},
"max_results": {
"default": 10,
"title": "Max Results",
"type": "integer"
},
"orientation": {
"default": "all",
"enum": [
"all",
"horizontal",
"vertical"
],
"title": "Orientation",
"type": "string"
},
"query": {
"title": "Query",
"type": "string"
},
"reasoning": {
"title": "Reasoning",
"type": "string"
}
},
"required": [
"query",
"reasoning"
],
"type": "object"
}
Implementation Reference
- src/searxng_mcp/server.py:384-537 (handler)MCP tool handler function for 'search_images'. Defines input schema via Annotated types, handles API key check with fallback to web search, calls PixabayClient, formats and returns results with usage tracking.@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
- src/searxng_mcp/images.py:45-125 (helper)PixabayClient.search_images method: core logic for querying Pixabay API, parsing responses, and returning list of StockImage objects. 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
- src/searxng_mcp/images.py:13-29 (helper)StockImage dataclass: defines the structure for individual 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
- src/searxng_mcp/server.py:25-36 (registration)Import of PixabayClient and global instantiation used by the search_images handler.from .images import PixabayClient from .registry import PackageInfo, PackageRegistryClient from .search import SearxSearcher from .service_health import ServiceHealthChecker from .tracking import get_tracker mcp = FastMCP("web-research-assistant") searcher = SearxSearcher() crawler_client = CrawlerClient() registry_client = PackageRegistryClient() github_client = GitHubClient() pixabay_client = PixabayClient()