@pulses/stocky-mcp
v1.0.1
Published
A friendly MCP server for searching royalty-free stock images from Pexels and Unsplash
Readme
Stocky MCP Server - TypeScript Edition
A friendly MCP (Model Context Protocol) server for searching royalty-free stock images across Pexels and Unsplash APIs.
Features
- Multi-provider search: Search across Pexels and Unsplash simultaneously
- Detailed image information: Retrieve comprehensive metadata for any image
- Flexible downloads: Download images in multiple sizes or as base64 data
- Attribution control: Toggle attribution links via environment variable
- Proper TypeScript typing: Full type safety with Zod validation
- Native fetch: Uses Node.js built-in fetch for HTTP requests
Installation
npm installBuilding
npm run buildDevelopment
npm run devThis will compile TypeScript and run the server.
Configuration
Environment Variables
Set the following environment variables to enable the respective providers:
# Pexels API Key (get one at https://www.pexels.com/api/)
export PEXELS_API_KEY="your_pexels_api_key"
# Unsplash API Key (get one at https://unsplash.com/developers)
export UNSPLASH_ACCESS_KEY="your_unsplash_api_key"
# Optional: Enable attribution links in responses
export ENABLE_ATTRIBUTION_LINKS="true"At least one API key must be set to use the server.
Project Structure
src/
├── index.ts # Main entry point, server initialization
├── tools.ts # Tool registrations and StockImageManager
└── providers/
├── types.ts # TypeScript type definitions
├── pexels.ts # Pexels API provider implementation
└── unsplash.ts # Unsplash API provider implementationAvailable Tools
search_stock_images
Search for stock images across specified providers.
Parameters:
query(string, required): Search query stringproviders(array, optional): List of specific providers to search (["pexels", "unsplash"])per_page(number, optional): Number of results per page, default 20, max 50page(number, optional): Page number for pagination, default 1sort_by(string, optional): Sort order ('relevant' or 'newest'), default 'relevant'include_attribution(boolean, optional): Whether to include attribution links (defaults to ENABLE_ATTRIBUTION_LINKS env var)
Returns:
{
"results": [
{
"id": "pexels_12345",
"title": "Photo title or alt text",
"description": "Image description",
"url": "https://...",
"thumbnail": "https://...",
"width": 1920,
"height": 1080,
"photographer": "John Doe",
"photographer_url": "https://...",
"source": "Pexels",
"license": "Free to use, attribution appreciated",
"attribution_url": "https://...",
"tags": ["sunset", "beach"]
}
],
"total_results": 20,
"query": "sunset beach",
"page": 1,
"per_page": 20
}get_image_details
Get detailed information about a specific image.
Parameters:
id(string, required): Provider-prefixed image ID (e.g., "pexels_12345")include_attribution(boolean, optional): Whether to include attribution links
Returns:
{
"id": "pexels_12345",
"title": "Photo title",
"description": "Image description",
"url": "https://...",
"thumbnail": "https://...",
"width": 1920,
"height": 1080,
"photographer": "John Doe",
"photographer_url": "https://...",
"source": "Pexels",
"license": "Free to use, attribution appreciated",
"attribution_url": "https://...",
"tags": ["sunset", "beach"]
}download_image
Download an image to local storage or retrieve as base64 data.
Parameters:
image_id(string, required): Image ID in format provider_id (e.g., "pexels_123456")size(string, optional): Image size variant (thumbnail, small, medium, large, original), default "original"output_path(string, optional): Path to save the image locally
Returns:
When saving to disk:
{
"success": true,
"message": "Image downloaded successfully to /path/to/image.jpg",
"path": "/path/to/image.jpg",
"size": 245632,
"content_type": "image/jpeg"
}When returning base64:
{
"success": true,
"message": "Image data retrieved successfully",
"data": "base64_encoded_image_data...",
"size": 245632,
"content_type": "image/jpeg",
"encoding": "base64"
}Size Mapping
The server maps size parameters to the appropriate URLs for each provider:
Pexels Size Mapping
thumbnail→ src.mediumsmall→ src.mediummedium→ src.largelarge→ src.largeoriginal→ src.original (with size constraints removed)
Unsplash Size Mapping
thumbnail→ urls.smallsmall→ urls.smallmedium→ urls.regularlarge→ urls.regularoriginal→ urls.full
Running the Server
Direct execution
npm startWith npx
npx stocky-mcpAPI Keys
Getting a Pexels API Key
- Visit https://www.pexels.com/api/
- Click "Register" and create an account
- Navigate to your API settings
- Copy your API key
Getting an Unsplash API Key
- Visit https://unsplash.com/developers
- Click "Create an app"
- Follow the terms and accept them
- Copy your Access Key
Examples
Search for sunset images
{
"query": "sunset",
"per_page": 10,
"providers": ["pexels", "unsplash"]
}Get details for a specific image
{
"id": "pexels_123456"
}Download an image at medium size
{
"image_id": "unsplash_abc123",
"size": "medium",
"output_path": "/home/user/pictures/image.jpg"
}Download and get base64 data
{
"image_id": "pexels_789012",
"size": "large"
}License
Free to use under Unsplash License for Unsplash images, and per Pexels' free license for Pexels images.
Development Notes
- The server uses native Node.js
fetchfor HTTP requests (requires Node 18+) - All tools return JSON responses wrapped in MCP content blocks
- Input validation is performed using Zod schemas
- TypeScript strict mode is enabled for type safety
- Image size clamping:
per_pageis clamped to a maximum of 50 results
Troubleshooting
No results returned
- Ensure API keys are correctly set in environment variables
- Verify your search query is not empty
- Check that at least one API key is configured
Images not downloading
- Verify the image ID format (should start with "pexels_" or "unsplash_")
- Check that the output path is absolute (for reliable saving)
- Ensure the parent directory has write permissions
Attribution links not showing
- Set
ENABLE_ATTRIBUTION_LINKS=truein environment variables - Or pass
include_attribution: truewhen calling tools
TypeScript Configuration
The project uses modern TypeScript with:
- Target: ES2022
- Module resolution: Node16
- Strict mode enabled
- ES modules (
.mtsimports with.jsextensions)
