jaapmoolenaar.nl / laravel-unsplash-mcp
Unsplash MCP tools for Laravel
Package info
github.com/JaapMoolenaar/laravel-unsplash-mcp
pkg:composer/jaapmoolenaar.nl/laravel-unsplash-mcp
Requires
- php: ^8.4
- laravel/mcp: >=0.1
Requires (Dev)
- laravel/framework: ^13.0
- laravel/pint: ^1.29
- orchestra/testbench: ^11.0
- pestphp/pest: ^4.6
Suggests
- statamic/cms: Required to use the statamic registrar with import-unsplash-photo
This package is auto-updated.
Last update: 2026-05-21 08:17:32 UTC
README
A Laravel package that exposes Unsplash photo search and import as an MCP (Model Context Protocol) server. Designed for use with Statamic: an AI assistant can search Unsplash, pick a photo, and download it directly into the Statamic asset library — including attribution metadata.
Requirements
- PHP 8.4+
- Laravel 13+
laravel/mcp≥ 0.1
Installation
composer require jaapmoolenaar.nl/laravel-unsplash-mcp
The service provider is auto-discovered and registers the MCP server automatically.
Configuration
Add your Unsplash API access key to your .env:
UNSPLASH_ACCESS_KEY=your-unsplash-access-key
You can get an access key by creating an application at unsplash.com/developers.
Optionally publish the config file if you need to customise it:
php artisan vendor:publish --tag=unsplash-mcp-config
All environment variables
| Variable | Default | Description |
|---|---|---|
UNSPLASH_ACCESS_KEY |
— | Your Unsplash API access key (required) |
UNSPLASH_REGISTRAR |
disk |
Default registrar used by import-unsplash-photo |
UNSPLASH_TEMP_DISK |
local |
Temporary disk used while downloading before moving |
UNSPLASH_DISK |
public |
Target disk for the disk registrar |
UNSPLASH_STATAMIC_CONTAINER |
assets |
Asset container handle for the statamic registrar |
MCP Server
The package registers a local MCP server named unsplash with two tools:
search-unsplash
Search Unsplash for photos by keyword. Returns paginated results with photo IDs, image URLs, descriptions, and photographer attribution.
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | Yes | Search keyword or phrase (max 50 characters) |
page |
integer | No | Page number (minimum 1, default 1) |
per_page |
integer | No | Results per page (maximum 30, default 10) |
order_by |
string | No | Sort by relevant (default) or latest |
orientation |
string | No | Filter by landscape, portrait, or squarish |
Example response:
{
"total": 1420,
"total_pages": 142,
"results": [
{
"id": "abc123xyz",
"description": "A beautiful nature photo",
"alt_description": "green trees in a forest",
"urls": {
"regular": "https://images.unsplash.com/photo-abc123?w=1080",
"small": "https://images.unsplash.com/photo-abc123?w=400",
"thumb": "https://images.unsplash.com/photo-abc123?w=200"
},
"link": "https://unsplash.com/photos/abc123xyz",
"photographer": "Jane Doe",
"photographer_url": "https://unsplash.com/@janedoe"
}
]
}
import-unsplash-photo
Downloads a photo (by ID from search-unsplash) and stores it using the configured registrar. Use the registrar parameter to control where the photo ends up.
| Parameter | Type | Required | Description |
|---|---|---|---|
photo_id |
string | Yes | The Unsplash photo ID (from search-unsplash results) |
basename |
string | No | Base filename without extension (default: unsplash-{photo_id}) |
registrar |
string | No | Storage target: disk or statamic (default: UNSPLASH_REGISTRAR) |
Example response:
{
"filename": "my-photo.jpg",
"url": "https://example.com/storage/my-photo.jpg",
"photographer": "Jane Doe"
}
Note: The download flow follows the Unsplash API guidelines by triggering the required download event before saving the image.
Registrars
disk — stores the photo on the Laravel disk configured by UNSPLASH_DISK (defaults to public).
statamic — stores the photo in the Statamic asset container configured by UNSPLASH_STATAMIC_CONTAINER (defaults to assets) and writes Unsplash attribution as asset metadata:
unsplash_id: abc123xyz unsplash_photographer: Jane Doe unsplash_photographer_url: https://unsplash.com/@janedoe unsplash_photo_url: https://unsplash.com/photos/abc123xyz unsplash_photo_cdn_url: https://images.unsplash.com/photo-abc123
Requires statamic/cms to be installed.
Connecting an MCP client
The service provider registers the MCP server automatically. How you connect an AI client depends on the transport.
Stdio: desktop AI tools (recommended)
Desktop tools like Claude Code, Cursor, and VS Code connect to MCP servers over stdio. It should start the server with:
php artisan mcp:start unsplash
You can configure your client to run that command.
For Claude Code, add this to .mcp.json in your project root:
{
"mcpServers": {
"unsplash": {
"type": "stdio",
"command": "php",
"args": ["artisan", "mcp:start", "unsplash"]
}
}
}
HTTP: web-based clients
If your client connects over HTTP, publish the AI routes file and register the server:
php artisan vendor:publish --tag=ai-routes
Then add to routes/ai.php:
use Laravel\Mcp\Facades\Mcp; Mcp::web('/mcp/unsplash', \JaapMoolenaar\UnsplashMcp\UnsplashServer::class);
The server is then reachable at POST /mcp/unsplash.
Usage with an AI assistant
Once the MCP server is active, an AI assistant (e.g. Claude) connected to your Laravel app can:
- Call
search-unsplashto find photos matching a description. - Pick a result from the list.
- Call
import-unsplash-photowith the chosenid— passregistrar=statamicto import directly into the Statamic asset library. - Tell you the filename — open the Statamic CP, go to Assets, and select it for the desired field (e.g. a hero image).
Development
Running the tests
composer test
Tests use Pest and Orchestra Testbench. HTTP calls are intercepted with Http::fake() and storage is isolated with Storage::fake('public').
Code style
This package uses Laravel Pint with the laravel preset.
composer lint # fix issues composer lint:check # dry-run (useful for CI)