{
  "markdown": "# stock-image-mcp\n\n<!-- mcp-name: io.github.Hasilt/images-mcp -->\n\nAn MCP server that lets Claude Code (or any MCP-compatible agent) search and\ndownload stock images by tool call — useful for sourcing images while writing\nSEO blog posts or other content.\n\n## Providers\n\n| Provider        | API type              | Requires key | Default rate limit                                |\n| --------------- | --------------------- | ------------ | ------------------------------------------------- |\n| Unsplash        | Official              | Yes          | 50/hr demo, 5000/hr production                    |\n| Pexels          | Official              | Yes          | 200/hr                                            |\n| Pixabay         | Official              | Yes          | 100 req/60s                                       |\n| Freepik         | Official              | Yes          | configurable (plan-dependent)                     |\n| StockVault      | Official              | Yes          | configurable (undocumented, conservative default) |\n| Burst (Shopify) | **Unofficial scrape** | No           | self-imposed, polite default                      |\n\nBurst has no public API. It's included as a best-effort HTML scraper, clearly\nmarked unsupported in code — any failure there is caught and reported as an\nempty result rather than breaking `search_all_images`.\n\n## Install\n\nEach user runs the server locally and supplies their own provider API keys —\nthere's no shared hosting or centrally-held keys.\n\nWith [Claude Code](https://docs.claude.com/en/docs/claude-code):\n\n```bash\nclaude mcp add stock-image-mcp \\\n  -e UNSPLASH_ACCESS_KEY=... \\\n  -e UNSPLASH_TIER=demo \\\n  -e PEXELS_API_KEY=... \\\n  -e PIXABAY_API_KEY=... \\\n  -e FREEPIK_API_KEY=... \\\n  -e FREEPIK_REQUESTS_PER_MINUTE=60 \\\n  -e STOCKVAULT_API_KEY=... \\\n  -e STOCKVAULT_REQUESTS_PER_HOUR=60 \\\n  -e BURST_REQUESTS_PER_MINUTE=10 \\\n  -e DEFAULT_PROVIDER=pexels \\\n  -e DOWNLOAD_DIR=./downloads \\\n  -- uvx stock-image-mcp\n```\n\nWith [OpenAI Codex CLI](https://github.com/openai/codex):\n\n```bash\ncodex mcp add stock-image-mcp \\\n  --env UNSPLASH_ACCESS_KEY=... \\\n  --env UNSPLASH_TIER=demo \\\n  --env PEXELS_API_KEY=... \\\n  --env PIXABAY_API_KEY=... \\\n  --env FREEPIK_API_KEY=... \\\n  --env FREEPIK_REQUESTS_PER_MINUTE=60 \\\n  --env STOCKVAULT_API_KEY=... \\\n  --env STOCKVAULT_REQUESTS_PER_HOUR=60 \\\n  --env BURST_REQUESTS_PER_MINUTE=10 \\\n  --env DEFAULT_PROVIDER=pexels \\\n  --env DOWNLOAD_DIR=./downloads \\\n  -- uvx stock-image-mcp\n```\n\nWith [Gemini CLI](https://github.com/google-gemini/gemini-cli):\n\n```bash\ngemini mcp add stock-image-mcp \\\n  -e UNSPLASH_ACCESS_KEY=... \\\n  -e UNSPLASH_TIER=demo \\\n  -e PEXELS_API_KEY=... \\\n  -e PIXABAY_API_KEY=... \\\n  -e FREEPIK_API_KEY=... \\\n  -e FREEPIK_REQUESTS_PER_MINUTE=60 \\\n  -e STOCKVAULT_API_KEY=... \\\n  -e STOCKVAULT_REQUESTS_PER_HOUR=60 \\\n  -e BURST_REQUESTS_PER_MINUTE=10 \\\n  -e DEFAULT_PROVIDER=pexels \\\n  -e DOWNLOAD_DIR=./downloads \\\n  -- uvx stock-image-mcp\n```\n\nOr add it to your MCP config manually with [`uvx`](https://docs.astral.sh/uv/guides/tools/)\n(no clone or install step required — `uvx` fetches the package from PyPI on\nfirst run):\n\n```json\n{\n  \"mcpServers\": {\n    \"stock-image-mcp\": {\n      \"command\": \"uvx\",\n      \"args\": [\"stock-image-mcp\"],\n      \"env\": {\n        \"UNSPLASH_ACCESS_KEY\": \"...\",\n        \"UNSPLASH_TIER\": \"demo\",\n        \"PEXELS_API_KEY\": \"...\",\n        \"PIXABAY_API_KEY\": \"...\",\n        \"FREEPIK_API_KEY\": \"...\",\n        \"FREEPIK_REQUESTS_PER_MINUTE\": \"60\",\n        \"STOCKVAULT_API_KEY\": \"...\",\n        \"STOCKVAULT_REQUESTS_PER_HOUR\": \"60\",\n        \"BURST_REQUESTS_PER_MINUTE\": \"10\",\n        \"DEFAULT_PROVIDER\": \"pexels\",\n        \"DOWNLOAD_DIR\": \"./downloads\"\n      }\n    }\n  }\n}\n```\n\nOnly `UNSPLASH_ACCESS_KEY`, `PEXELS_API_KEY`, `PIXABAY_API_KEY`,\n`FREEPIK_API_KEY`, and `STOCKVAULT_API_KEY` are actual secrets — set only the\nones for providers you want enabled and drop the rest; any provider key you\nomit is simply skipped by `search_all_images` and rejected if queried\ndirectly via `search_stock_images`. The remaining variables are optional\ntuning knobs shown above with their defaults — see `.env.example` for the\nfull list.\n\n## Tools\n\n- `search_stock_images(query, provider=\"default\", orientation=None, per_page=10, page=1)`\n- `search_all_images(query, orientation=None, per_page=5)` — fans out to every configured provider concurrently\n- `get_best_image(query, provider=\"default\")`\n- `download_image(url, dest_path, provider=None)` — saves locally, returns attribution text if the image came from a prior search\n- `get_attribution(provider, image_id)`\n- `get_rate_limit_status(provider=None)`\n\n## Usage\n\nYou don't call these tools directly — you just talk to your agent, and it\ndecides when to reach for one based on what you asked and the tool\ndescriptions above. A few things worth knowing:\n\n- Just ask in plain English. \"Find me 3 landscape photos of mountains for a\n  blog post\" is enough to trigger `search_all_images` (or\n  `search_stock_images` if you name a provider). \"Download that first\n  Unsplash result to `./images/hero.jpg`\" triggers `download_image`. \"How\n  many Pexels requests do I have left this hour?\" triggers\n  `get_rate_limit_status`.\n- `search_stock_images` needs a specific provider (or `\"default\"`);\n  `search_all_images` just queries everything you've configured keys for and\n  merges the results. Say \"search Pexels only\" or similar if you care which\n  one gets used.\n- Several providers (Unsplash and Pexels in particular) require attribution\n  if you actually use the image somewhere public. `download_image` returns\n  the attribution text alongside the file when it applies — it's on you to\n  paste it wherever the image ends up, the server won't do that part for you.\n- Want to call tools by hand instead of through a conversation? See the MCP\n  Inspector section under Development below.\n\n## Developing locally\n\nWorking from a clone instead of the published package:\n\n```bash\nuv sync\ncp .env.example .env   # fill in the API keys for providers you want enabled\nuv run stock-image-mcp\n```\n\nPoint your Claude config at the local checkout instead of `uvx`:\n\n```json\n{\n  \"mcpServers\": {\n    \"stock-image-mcp\": {\n      \"command\": \"uv\",\n      \"args\": [\n        \"--directory\",\n        \"/absolute/path/to/stock-image-mcp\",\n        \"run\",\n        \"stock-image-mcp\"\n      ],\n      \"env\": {\n        \"UNSPLASH_ACCESS_KEY\": \"...\",\n        \"UNSPLASH_TIER\": \"demo\",\n        \"PEXELS_API_KEY\": \"...\",\n        \"PIXABAY_API_KEY\": \"...\",\n        \"FREEPIK_API_KEY\": \"...\",\n        \"FREEPIK_REQUESTS_PER_MINUTE\": \"60\",\n        \"STOCKVAULT_API_KEY\": \"...\",\n        \"STOCKVAULT_REQUESTS_PER_HOUR\": \"60\",\n        \"BURST_REQUESTS_PER_MINUTE\": \"10\",\n        \"DEFAULT_PROVIDER\": \"pexels\",\n        \"DOWNLOAD_DIR\": \"./downloads\"\n      }\n    }\n  }\n}\n```\n\n## Development\n\n```bash\nuv run pytest              # test suite (mocked HTTP, no live keys needed)\nuv run ruff check .         # lint\nuv run ruff format .        # format\nuv run mypy src             # type check\n```\n\nTo try it against real providers, use the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector):\n\n```bash\nnpx @modelcontextprotocol/inspector uv run stock-image-mcp\n```\n",
  "bytes": 7208,
  "sha": "91215e154357374961b5e8d179fbaab776e82f2de480e58842733c9d17621eb0",
  "repo_slug": "hasilt/images-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_hasilt_images_mcp_9223f1e5/readme"
}