search_photos
Find high-quality photos on Unsplash using search terms, with options to filter by orientation and content safety. Returns base64-encoded images.
Instructions
Search for photos on Unsplash. Returns base64-encoded images.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search term for photos | |
| page | No | Page number (default: 1) | |
| per_page | No | Number of photos per page (default: 10, max: 30) | |
| orientation | No | Filter by orientation | |
| content_filter | No | Content safety filter |
Implementation Reference
- src/index.ts:184-296 (handler)The main handler function that executes the search_photos tool logic. It queries the Unsplash API with search parameters (query, page, per_page, orientation, content_filter), handles the response, and returns either base64-encoded images or JSON metadata depending on the response format setting.
private async searchPhotos(args: any) { try { const { query, page = 1, per_page = 10, orientation, content_filter = "low" } = args; const searchParams = new URLSearchParams({ query, page: page.toString(), per_page: per_page.toString(), content_filter, }); if (orientation) { searchParams.append("orientation", orientation); } const response = await fetch( `${UNSPLASH_API_URL}/search/photos?${searchParams}`, { headers: { Authorization: `Client-ID ${this.accessKey}`, }, } ); if (!response.ok) { throw new Error(`Unsplash API error: ${response.status} ${response.statusText}`); } const data: UnsplashSearchResponse = await response.json(); if (this.responseFormat === 'text') { // Return JSON with URLs const formattedResults = data.results.map((photo) => ({ id: photo.id, description: photo.description || photo.alt_description || "No description", urls: photo.urls, user: { name: photo.user.name, username: photo.user.username, }, dimensions: { width: photo.width, height: photo.height, }, likes: photo.likes, color: photo.color, created_at: photo.created_at, })); return { content: [ { type: "text", text: JSON.stringify({ total: data.total, total_pages: data.total_pages, current_page: page, per_page, results: formattedResults, }, null, 2), }, ], }; } else { // Return base64 encoded images with metadata const contentItems: Array<{ type: "text"; text: string } | { type: "image"; data: string; mimeType: string }> = [ { type: "text", text: `Found ${data.total} photos (page ${page}/${data.total_pages}):`, } ]; for (const photo of data.results) { try { // Add metadata as JSON using original Unsplash API response contentItems.push({ type: "text", text: JSON.stringify(photo, null, 2), }); // Add the actual image const imageData = await this.fetchImageAsBase64(photo.urls.regular); contentItems.push({ type: "image", data: imageData.base64, mimeType: imageData.mimeType, }); } catch (error) { // If image fetch fails, return error info contentItems.push({ type: "text", text: `Failed to fetch image ${photo.id}: ${error instanceof Error ? error.message : 'Unknown error'}`, }); } } return { content: contentItems, }; } } catch (error) { return { content: [ { type: "text", text: `Error searching photos: ${error instanceof Error ? error.message : "Unknown error"}`, }, ], isError: true, }; } } - src/index.ts:118-148 (schema)Input schema definition for the search_photos tool, defining parameters: query (required string), page (optional number), per_page (1-30), orientation (landscape/portrait/squarish), and content_filter (low/high).
inputSchema: { type: "object", properties: { query: { type: "string", description: "Search term for photos", }, page: { type: "number", description: "Page number (default: 1)", minimum: 1, }, per_page: { type: "number", description: "Number of photos per page (default: 10, max: 30)", minimum: 1, maximum: 30, }, orientation: { type: "string", description: "Filter by orientation", enum: ["landscape", "portrait", "squarish"], }, content_filter: { type: "string", description: "Content safety filter", enum: ["low", "high"], }, }, required: ["query"], }, - src/index.ts:112-152 (registration)Tool registration via ListToolsRequestSchema handler that defines the search_photos tool with its name, description, and inputSchema.
this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "search_photos", description: `Search for photos on Unsplash. Returns ${this.responseFormat === 'image' ? 'base64-encoded images' : 'photo URLs and metadata as JSON'}.`, inputSchema: { type: "object", properties: { query: { type: "string", description: "Search term for photos", }, page: { type: "number", description: "Page number (default: 1)", minimum: 1, }, per_page: { type: "number", description: "Number of photos per page (default: 10, max: 30)", minimum: 1, maximum: 30, }, orientation: { type: "string", description: "Filter by orientation", enum: ["landscape", "portrait", "squarish"], }, content_filter: { type: "string", description: "Content safety filter", enum: ["low", "high"], }, }, required: ["query"], }, }, ], }; }); - src/index.ts:157-158 (handler)Routing logic that dispatches to the searchPhotos handler when the tool name matches 'search_photos'.
if (name === "search_photos") { return await this.searchPhotos(args); - src/index.ts:165-182 (helper)Helper function fetchImageAsBase64 that fetches an image from a URL and converts it to base64 encoding, used by searchPhotos to return image content.
private async fetchImageAsBase64(url: string): Promise<{base64: string, mimeType: string}> { try { const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch image: ${response.status}`); } const arrayBuffer = await response.arrayBuffer(); const base64 = Buffer.from(arrayBuffer).toString('base64'); // Determine MIME type from URL or response headers const contentType = response.headers.get('content-type') || 'image/jpeg'; return { base64, mimeType: contentType }; } catch (error) { throw new Error(`Error fetching image: ${error instanceof Error ? error.message : 'Unknown error'}`); } }