@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