Metadata-Version: 2.5
Name: pexels-mcp
Version: 1.0.1
Summary: MCP + CLI toolkit to search and download free Pexels stock images/videos. No API key, no quota. Built-in relevance gate kills Pexels's junk hits; picks the right resolution tier for vertical shorts.
Project-URL: Homepage, https://modelscope.cn/mcp/servers
Author: aqiu
License: MIT
License-File: LICENSE
Keywords: images,mcp,model-context-protocol,pexels,shorts,stock,video-assembly,videos
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# pexels-mcp

MCP + CLI toolkit to **search and download free Pexels stock images/videos**.

- **Zero third-party dependencies** — pure Python standard library (urllib). Install, run, done.
- **No API key, no quota** — talks to Pexels' own web front-end API v3 (the public `secret-key` constant Pexels hardcodes in its JS).
- **Built-in relevance gate** — Pexels returns *something* for any query (even `zzzqqqxxx_not_exist_9999`). This tool validates every candidate against title/tags and drops 0-hit junk, so you never get unrelated footage.
- **Right resolution tier, automatically** — picks the video_files tier closest to your target (default 1080×1920 portrait) and refuses to upscale postage-stamp clips.
- **Chinese query rejected** — the English site can't search Chinese meaningfully. Translate to concrete English words (`office meeting` > `work`).

Works as an [MCP](https://modelcontextprotocol.io) server (5 tools) or a plain CLI.

---

## Quick start

```bash
pip install pexels-mcp          # or: uvx pexels-mcp@latest
```

### As an MCP server

```json
{
  "mcpServers": {
    "pexels": {
      "command": "uvx",
      "args": ["pexels-mcp@latest"],
      "env": { "PEXELS_OUT_DIR": "/tmp/pexels_download" }
    }
  }
}
```

Any MCP client (Claude Desktop, CowAgent, …) sees 5 tools:

| tool            | what it does |
|-----------------|--------------|
| `pexels_search` | search only, returns direct links + size/duration metadata; no junk hits |
| `pexels_get`    | search **and download** N items to a local dir, returns paths + byte counts |
| `pexels_download` | download a single direct link you already have |
| `pexels_health` | channel self-check; includes a reverse probe (a nonsense query must return 0 hits) |
| `pexels_info`   | capability boundary, no network |

`PEXELS_OUT_DIR` sets the download folder (default: OS temp dir).

### As a CLI

```bash
pexels-cli search "elderly woman face" --kind video -n 5
pexels-cli search "office meeting" --json
pexels-cli get "hands holding cash" -o ./out -n 2
pexels-cli health
pexels-cli info
```

All subcommands support `--json` for machine-readable output.

---

## Why it's reliable

- **No fake hits**: Pexels fabricates total_results even for nonsense queries. We split your query into content tokens (with a stop-word list — `not` must not match `do not lean`), and require ≥1 token to actually appear in the item's title/tags/slug. A test with `zzzqqqxxx_not_exist_9999` returns 0 hits.
- **No decompression trap**: we request `Accept-Encoding: identity` (avoid brotli unless you have it) and fall back to gunzip.
- **Throttle-safe**: measured 100 sequential + 8-way parallel direct downloads at 100% success with no Cloudflare intervention.
- **Bomb fuse**: downloads stream with size cap, and a `text/html` response is rejected as a Cloudflare block page masquerading as HTTP 200.

## Notes

- This package is just "give me a keyword → get good direct-link stock media". It does **not** assemble videos — pair it with an assembler MCP (e.g. `video-assembler-mcp`) for the full pipeline.
- The endpoint is Pexels' own public web API and could change at any time. It's a third-party behavior, out of our control; `pexels_health` exists precisely to catch that the day it happens.

## License

MIT
