Skip to main content
Glama
VictorNain26

pexels-mcp-server

by VictorNain26

pexels-mcp-server

CI License: MIT Python 3.10+ MCP

A Model Context Protocol (MCP) server that gives AI agents access to free stock photos and videos from Pexels. Plug it into claude.ai web, Claude Desktop, Claude Code, Cursor or any MCP-aware client and the model gains the three MCP primitives (tools, resources, prompts) over the Pexels REST surface.

Built around the MCP spec 2025-11-25 and Anthropic's Writing tools for agents guidance: strict Pydantic input schemas, structured tool output via structuredContent + outputSchema, isError=true on tool failure per SEP-1303, OAuth 2.1 + RFC 9728 + RFC 7591 DCR + PKCE for the HTTP transport.

What the agent gets

8 tools (model-controlled)

Tool

Purpose

pexels_search_photos

Search photos. Filters: orientation, size, color, locale, plus post-hoc min_width / min_height / aspect_ratio.

pexels_get_photo

Fetch one photo by id.

pexels_search_videos

Search videos. Same filters minus color.

pexels_get_video

Fetch one video by id.

pexels_get_collection_media

Read photos + videos in a Pexels collection.

pexels_get_curated_photos

Pexels' editor-curated daily photo feed. Post-hoc dim/aspect filters.

pexels_get_popular_videos

Trending video feed. Native min_width / min_height / min_duration / max_duration (Pexels-side), post-hoc aspect_ratio.

pexels_get_featured_collections

Discover curated collection ids (metadata only — pipe an id into pexels_get_collection_media).

3 resources (app-controlled, URI templates)

URI template

MIME

Body

pexels://photo/{photo_id}

application/json

SinglePhotoResult

pexels://video/{video_id}

application/json

SingleVideoResult

pexels://collection/{collection_id}

application/json

CollectionMediaResult

A user pasting a pexels.com URL into a chat lets the host attach the content directly without the agent invoking a tool.

2 prompts (user-controlled, claude.ai connector menu)

Prompt

Arguments

Use case

find_hero_image

topic, orientation?, brand_color?, aspect_ratio?

Marketing hero with brand fit

find_broll

topic, orientation?, resolution?, aspect_ratio?

B-roll, reels, hero loops

Each prompt renders a short user-message brief that names the tool, the filters and the attribution requirement — the agent acts in one turn instead of asking the user for parameters.

Related MCP server: MCP Image Resolver

Token economy

Every byte that goes onto the wire was audited. Cumulative gains vs the SDK defaults:

  • Tool descriptions trimmed to the minimum LLM-actionable signal (USE WHEN / DO NOT USE / filters / return shape).

  • Type docstrings removed from MediaSize, PhotoProjection, VideoProjection, FilterDiagnostics etc.: they leaked as description fields into every tool's $defs, duplicated across all tools that referenced them. Now Python comments only.

  • serverInfo.instructions reduced to one sentence (the attribution requirement); the tool list is already shipped by tools/list.

  • SDK patch (see _sdk_patches.py):

    • Forces model_dump(exclude_unset=True) so unset optional TypedDict fields don't leak as "field": null.

    • Replaces the SDK's duplicate-content behaviour: instead of shipping the payload twice (once as structuredContent, once as indented JSON in content[]), tools now ship the structured payload plus a 45-char marker in content[] pointing at it. Saves ~1500 tokens per tool call on a 15-photo search.

Numbers for a typical 15-photo search call:

content text

structuredContent

total

SDK default

7 100c (indented dup)

5 400c

12 500c (~3 100 tok)

This server

45c (marker)

5 400c

5 450c (~1 360 tok)

How the agent picks the best image

Pexels already ranks results by relevance. The tools just let the agent narrow the field in one shot:

  1. Frame query + filtersorientation for hero banners, aspect_ratio for fixed-frame (Instagram 1:1, Story 9:16, hero 16:9), min_width / min_height for hard pixel floors (~4000 for A4 print, ~1920 for hero), color for brand fit.

  2. Read alt textpexels_search_photos returns up to 15 candidates by default with alt text, dimensions and photographer credit. The agent drops anything off-topic and returns the best image_url plus the mandatory photographer / photographer_url.

When a post-hoc filter (aspect_ratio etc.) wipes the page, the envelope carries a filter_diagnostics block telling the agent how to retry.

Deployment

Designed for one hosted HTTPS endpoint with OAuth 2.1 + RFC 9728. Stdio is supported for local power-user clients (Cursor, scripts).

Auth model — bring-your-own-key (BYOK) during the OAuth flow

The Python process is both the Resource Server (holding /mcp) and the Authorization Server. The MCP Python SDK mounts every well-known endpoint automatically: /.well-known/oauth-protected-resource (RFC 9728), /.well-known/oauth-authorization-server (RFC 8414), /authorize, /token, /register (RFC 7591 DCR), all with PKCE.

register_client rejects redirect_uri schemes that aren't https:// or http:// loopback (OAuth 2.1 phishing mitigation).

After the standard handshake, the server redirects the user's browser to /setup, a short HTML form asking for a Pexels API key. The user pastes their free key (from https://www.pexels.com/api/), the server validates it against api.pexels.com, then mints the OAuth code with the key bound to the soon-to-be-issued access token (30-day TTL). Every tool / resource call resolves the caller's key by Bearer-token lookup.

For per-request clients (Cursor stdio bridges, scripts), the server also accepts an X-Pexels-Api-Key HTTP header as a fallback.

Environment variables

Variable

Required

Description

TRANSPORT

yes

streamable-http or stdio (default).

MCP_SERVER_URL

yes (HTTP)

Public HTTPS URL of this service. No trailing slash.

MCP_ALLOWED_HOSTS

no

Comma-separated Host allowlist (DNS rebinding protection). Auto-set to MCP_SERVER_URL's hostname if unset.

MCP_RATE_LIMIT_PER_MINUTE

no (60)

Per-IP rate limit. /healthz, /readyz, OAuth metadata are exempt.

MCP_TRUSTED_PROXY_HOPS

no (1)

Proxies in front of the app (Koyeb LB = 1, Cloudflare-then-Koyeb = 2, no proxy = 0).

REDIS_URL

no

When set, OAuth state lives in Redis and survives restarts. Supports rediss:// (TLS).

MCP_ENCRYPTION_KEY

yes if REDIS_URL

32-byte url-safe base64 Fernet key. Pexels keys are encrypted at rest. Generate: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())".

HOST / PORT

no

Default 127.0.0.1:8000. Docker flips host to 0.0.0.0.

LOG_LEVEL

no (INFO)

Standard Python levels.

LOG_FORMAT

no

json (default in HTTP) or text (default in stdio).

PEXELS_API_KEY

stdio only

Default key for local clients. Ignored in HTTP mode.

Without REDIS_URL, OAuth state is in-memory and every Koyeb deploy forces users to re-walk /setup. With Redis, sessions survive restarts. The bound Pexels key is encrypted client-side with Fernet (AES-128-CBC + HMAC-SHA256) before being written — a leaked Redis dump alone yields opaque ciphertext.

Compatible providers: Upstash Redis (free tier 10k cmd/day, 256 MB, TLS), Redis Cloud, self-hosted. See docker-compose.yml for the local dev setup.

Koyeb (one-command deploy)

koyeb service create pexels-mcp \
  --git github.com/VictorNain26/pexels-mcp-server \
  --git-branch main \
  --git-builder docker \
  --ports 8000:http \
  --routes /:8000 \
  --checks 8000:http:/healthz \
  --env TRANSPORT=streamable-http \
  --env "MCP_SERVER_URL=https://{{ KOYEB_PUBLIC_DOMAIN }}" \
  --env "MCP_ALLOWED_HOSTS={{ KOYEB_PUBLIC_DOMAIN }}" \
  --env LOG_FORMAT=json \
  --instance-type nano \
  --regions fra

Then add REDIS_URL + MCP_ENCRYPTION_KEY for persistent sessions.

Smoke test

URL=https://<your-service>.koyeb.app
curl -s "$URL/healthz"   # -> ok
curl -s "$URL/.well-known/oauth-protected-resource" | head -20
curl -i -X POST "$URL/mcp" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json,text/event-stream' \
  -H 'MCP-Protocol-Version: 2025-11-25' \
  -d '{}' | head -10
# -> 401 with WWW-Authenticate: Bearer ... resource_metadata="..."

Connect a client

Client

Steps

claude.ai web

Settings → Connectors → Add custom connector → URL https://<host>/mcp. Click Connect. Paste your Pexels key on the /setup page.

Claude Desktop

Settings → Connectors → Add (remote) → same URL. Same /setup flow.

Claude Code

claude mcp add pexels --transport http https://<host>/mcp.

MCP Inspector

npx @modelcontextprotocol/inspector → paste the URL.

Local development

git clone https://github.com/VictorNain26/pexels-mcp-server
cd pexels-mcp-server
uv sync --all-extras

HTTP server (prod parity)

TRANSPORT=streamable-http HOST=127.0.0.1 PORT=8000 \
  MCP_SERVER_URL=http://127.0.0.1:8000 \
  uv run pexels-mcp-server

Full stack with Redis (Fernet path exercised)

echo "MCP_ENCRYPTION_KEY=$(python -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())')" > .env
docker compose up --build

Stdio (Cursor, local scripts)

PEXELS_API_KEY=your-key uv run pexels-mcp-server

Stdio bypasses OAuth — the key comes from the env var directly.

Check suite

uv run ruff check && uv run ruff format --check
uv run mypy src
uv run python -m pytest

Response shape

pexels_search_photos(query="paris", per_page=1) ships:

  • structuredContent (canonical payload, machine-readable, ~600c):

{
  "page": 1,
  "per_page": 1,
  "count": 1,
  "has_more": true,
  "next_page": 2,
  "total_results": 8000,
  "photos": [
    {
      "id": 28448939,
      "alt": "Vibrant street view of central Paris ...",
      "page_url": "https://www.pexels.com/photo/.../28448939/",
      "photographer": "Sergey Guk",
      "photographer_url": "https://www.pexels.com/@sergeyguk",
      "width": 4000,
      "height": 6000,
      "image_url": "https://images.pexels.com/photos/28448939/.../original.jpeg"
    }
  ]
}
  • content[0] (45-char marker): "See structuredContent for the result payload."

The marker exists so backwards-compat clients reading content see a non-empty block. Modern clients (claude.ai web, Claude Desktop, MCP Inspector 0.10+) consume structuredContent directly.

Three usage examples

1. Hero image with brand color and aspect ratio

pexels_search_photos(
  query="modern open-plan office workspace",
  orientation="landscape",
  size="large",
  color="blue",
  aspect_ratio="16:9",
  min_width=1920,
  per_page=6,
)

2. 4K B-roll, fixed aspect

pexels_search_videos(
  query="aerial drone shot of mountain lake at dawn",
  orientation="landscape",
  size="large",
  aspect_ratio="16:9",
  per_page=10,
)

video_url is the direct MP4 of the top-resolution variant.

3. Drill into a Pexels collection

pexels_get_collection_media(collection_id="9j5dhpu", per_page=20)

The response splits photos[] and videos[]. Filter to one type with type="photos" or type="videos".

Rate limits and attribution

Pexels free tier: 200 requests/hour, 20 000 requests/month on the caller's key (per Pexels' API docs). The server warns to stderr below 100 remaining; the response envelope does not carry rate-limit metadata (saves tokens — flip LOG_LEVEL=DEBUG if you need it).

If you publish anything returned by this server you must credit the photographer / videographer and link back to Pexels per the Pexels licence. Every tool, resource and prompt is shaped so the LLM sees photographer / uploader_name and matching URLs and can surface them in the user-facing answer.

Architecture notes

  • 3-of-3 MCP primitives. Tools (model-controlled), Resources (app-controlled, URI templates per RFC 6570), Prompts (user-controlled, surfaced in claude.ai's connector menu).

  • Spec-compliant auth. OAuth 2.1 Resource Server + Authorization Server in one process via the MCP Python SDK's OAuthAuthorizationServerProvider. RFC 9728 PRM, RFC 8414 ASM, RFC 7591 DCR, PKCE — all served by the SDK. The only custom routes are GET / (landing) and GET/POST /setup (BYOK form).

  • Stateless HTTP by default. stateless_http=True, json_response=True so deployment scales horizontally without sticky sessions. Trade-off: no sampling / no ctx.report_progress / no resource subscriptions — documented in CLAUDE.md.

  • Read-only by construction. Every tool advertises readOnlyHint=true, destructiveHint=false, idempotentHint=true, openWorldHint=true plus a title.

  • Structured tool output + isError=true. Tools return a TypedDict; the SDK auto-generates outputSchema. Errors raise → FastMCP wraps in CallToolResult(isError=true) per SEP-1303.

  • Strict inputs. Pydantic v2 with extra="forbid"; invalid values come back as Invalid parameters: <field>: <reason>.

  • Token-lean payloads. See the Token economy section above.

  • SDK patches in _sdk_patches.py. The only place in the repo that mutates third-party state.

Health and probes

GET /healthz (liveness) and GET /readyz (readiness) return 200 ok and bypass auth. The Dockerfile declares HEALTHCHECK against /healthz.

Compatibility

  • Python 3.10, 3.11, 3.12.

  • mcp SDK pinned >=1.25,<2.

  • Transport: stdio + Streamable HTTP. Legacy SSE is not enabled.

  • MCP spec 2025-11-25 (SDK negotiates downgrade to 2025-06-18 / 2025-03-26).

See SECURITY.md to report a vulnerability, PRIVACY.md for what the server does and doesn't store.

License

MIT. See LICENSE.

Available Tools

8 tools
pexels_get_collection_mediaGet Pexels Collection ContentsA
Read-onlyIdempotent

Read the photos + videos inside a Pexels collection.

USE WHEN you have a collection id (pexels.com/collections/<id>).
Filter to one type with `type` ('photos' or 'videos').
Post-hoc filters (aspect_ratio, min_width, min_height) apply to both.
DO NOT USE for discovery — no public list-all-collections endpoint.

Per-item shape matches the search tools.
ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo
sortNo
typeNo
per_pageNo
min_widthNo
min_heightNo
aspect_ratioNo
collection_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
pageYes
countYes
photosYes
videosYes
has_moreYes
per_pageYes
next_pageNo
total_resultsNo
filter_diagnosticsNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, etc. Description adds that per-item shape matches search tools and that filters apply to both types, providing useful behavioral context beyond annotations without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Seven lines of concise, front-loaded text. Every sentence adds value: purpose, usage condition, filter guidance, exclusion, and matching note. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists, so return values are handled. Covers key parameters and usage constraints. Mentions per-item shape matches search tools for familiarity. Lacks detail on pagination but sufficient given standard expectations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so description must compensate. Mentions collection_id, type, aspect_ratio, min_width, min_height (4 of 8 parameters). Misses page, per_page, sort. Partial compensation, adequate but not complete.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states 'Read the photos + videos inside a Pexels collection' with specific verb and resource. Implicitly distinguishes from discovery tools by requiring collection_id and explicitly advising against discovery use.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'USE WHEN you have a collection id' and 'DO NOT USE for discovery — no public list-all-collections endpoint.' Provides clear context for when to use and when to avoid, including mention of filters and matching search tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pexels_get_curated_photosGet Pexels Curated PhotosA
Read-onlyIdempotent

Fetch Pexels' editor-curated daily photo feed.

USE WHEN: feed-style discovery without a specific query — "what's
trending on Pexels today", brand-safe brainstorming, mood-board fuel.
DO NOT USE for targeted topic search — call pexels_search_photos.

Post-hoc filters (4x oversample, cap 80): aspect_ratio, min_width,
min_height. image_url is a public CDN link: render as Markdown or
pass to any URL-accepting downstream tool. Do not curl/download
the bytes. Always credit photographer per Pexels licence.
ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo
per_pageNo
min_widthNo
min_heightNo
aspect_ratioNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
pageYes
countYes
photosYes
has_moreYes
per_pageYes
next_pageNo
total_resultsNo
filter_diagnosticsNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds useful context beyond annotations: post-hoc filter behavior (oversample, cap 80), CDN link property, no-download instruction, and licensing credit requirement. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Very concise: 5 sentences covering purpose, usage, filter behavior, link handling, and attribution. Front-loaded with main action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given sibling set and output schema (implied), the description covers all essential aspects: when to use, filter details, output link handling, and legal note. No gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates by explaining the filter parameters (aspect_ratio, min_width, min_height) include behavioral details (post-hoc, oversample, cap 80). Missing page/per_page, but these are standard pagination fields with defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states it fetches editor-curated daily photo feed (specific verb+resource+scope). Distinguishes from sibling pexels_search_photos for targeted search.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit 'USE WHEN' for feed-style discovery and 'DO NOT USE' for targeted topic search with direct sibling reference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pexels_get_photoGet a Pexels Photo by IDA
Read-onlyIdempotent

Fetch one Pexels photo by id.

USE WHEN you have a photo id (previous search result, or extracted
from a pexels.com URL ending in -<id>).
DO NOT USE for discovery — call pexels_search_photos. No guessed ids.

Render image_url as Markdown link; credit photographer.
ParametersJSON Schema
NameRequiredDescriptionDefault
photo_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
photoYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint, openWorldHint, idempotentHint, and destructiveHint. Description adds behavioral context: how to handle the output (render image_url as Markdown link, credit photographer) and that IDs should not be guessed. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely concise: one sentence for purpose, followed by three clear usage lines. No redundant information. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (one param, output schema present), the description covers purpose, usage prerequisites, limitations, and output rendering. Completely sufficient for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 0% description coverage for the single parameter. Description compensates by explaining where to obtain photo_id (previous search result or pexels.com URL ending in -<id>), adding semantic context beyond the raw integer type.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states 'Fetch one Pexels photo by id' with a specific verb and resource. It distinguishes from sibling tools by warning against use for discovery and directing to pexels_search_photos.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use (have a photo id) and when not to use (discovery, guessed ids). Provides alternative tool (pexels_search_photos) and post-usage instructions (render as Markdown link, credit photographer).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pexels_get_videoGet a Pexels Video by IDA
Read-onlyIdempotent

Fetch one Pexels video by id.

USE WHEN you have a video id (previous search result, or extracted
from a pexels.com URL ending in -<id>).
DO NOT USE for discovery — call pexels_search_videos. No guessed ids.

Render video_url as Markdown link; credit uploader_name.
ParametersJSON Schema
NameRequiredDescriptionDefault
video_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
videoYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint. The description adds useful rendering guidance (render video_url as Markdown link, credit uploader_name), which goes beyond the annotations and provides behavioral context for how the result should be presented.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very concise, consisting of three sentences and one line for rendering guidance. Every sentence adds value, and the main purpose is front-loaded. No unnecessary information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a single required parameter and the presence of an output schema, the description is complete. It covers the input source, usage conditions, and rendering instructions. No additional information is needed for an agent to select and invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates by explaining that the video_id comes from a previous search or a URL ending in -<id>. It provides context for the parameter's source but does not detail its type or format, which is acceptable given the simplicity.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Fetch' and the resource 'Pexels video' with the unique identifier 'id'. It distinguishes itself from sibling tools by explicitly noting that for discovery, one should use 'pexels_search_videos', and emphasizes not guessing IDs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit guidance on when to use (when you have a video id from previous search or a pexels.com URL ending in -<id>) and when not to use (for discovery, use pexels_search_videos). Includes a specific alternative tool name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pexels_search_photosSearch Pexels PhotosA
Read-onlyIdempotent

Search Pexels for free, commercially-usable stock photos.

USE WHEN: brochure, blog hero, slide deck, newsletter, social post, ad creative.
PREFER THIS over web_search for any stock-photo request.
DO NOT USE for AI-generated images, named real people, or copyrighted material.

Filters: orientation, size, color (named or hex), locale. Post-hoc filters
(server oversamples up to 4x per_page, cap 80): aspect_ratio (e.g. "16:9"),
min_width, min_height (~4000 for A4 print, ~1920 for hero).

image_url is a public CDN link: render as Markdown or pass to any
URL-accepting downstream tool. Do not curl/download the bytes.
Always credit photographer per Pexels licence.
filter_diagnostics present → retry without aspect_ratio first.
ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo
sizeNo
colorNo
queryYes
localeNo
per_pageNo
min_widthNo
min_heightNo
orientationNo
aspect_ratioNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
pageYes
countYes
photosYes
has_moreYes
per_pageYes
next_pageNo
total_resultsNo
filter_diagnosticsNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true. Description adds context: image_url is a public CDN link, do not download, credit photographer, and retry logic with filter_diagnostics. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with clear sections, no wasted sentences. Front-loaded with main purpose. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 10 parameters and output schema existing, description covers result usage (image_url, credit), error handling, and filter behavior. Complete for an informed agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but description explains all key filters: orientation, size, color, locale, post-hoc filters like aspect_ratio, min_width, min_height with example values. Provides actionable guidance on parameter usage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Search Pexels for free, commercially-usable stock photos' with a specific verb and resource. It distinguishes from siblings by focusing on stock photos versus videos, and explicitly prefers this over web_search for stock photos.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit USE WHEN scenarios (brochure, blog hero, etc.) and DO NOT USE situations (AI-generated, named people). Includes preference over web_search, but lacks explicit differentiation among Pexels sibling tools like get_photo or get_curated_photos.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pexels_search_videosSearch Pexels VideosA
Read-onlyIdempotent

Search Pexels for free, commercially-usable stock videos.

USE WHEN: B-roll, reels, hero loops, ad motion, animated backgrounds.
PREFER THIS over web_search for stock-video requests.
DO NOT USE for AI-generated video or named real people.

Filters: orientation, size (large=4K, medium=FullHD, small=HD), locale.
Post-hoc (4x oversample, cap 80): aspect_ratio, min_width, min_height.

video_url is a public CDN MP4 link: render as Markdown or pass to any
URL-accepting downstream tool. Do not curl/download the bytes.
Credit uploader_name per Pexels licence. filter_diagnostics same
semantics as pexels_search_photos.
ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo
sizeNo
queryYes
localeNo
per_pageNo
min_widthNo
min_heightNo
orientationNo
aspect_ratioNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
pageYes
countYes
videosYes
has_moreYes
per_pageYes
next_pageNo
total_resultsNo
filter_diagnosticsNo

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnly, openWorld, idempotent, and non-destructive hints. The description adds beyond that: explains video_url is a public CDN MP4 link, instructs not to download, and mandates credit. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, well-structured with sections, and front-loaded with the most important information. Every sentence adds value, no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (9 params, no schema descriptions, has output schema), the description covers purpose, usage, key parameters, output handling, and credits. Minor gap: pagination not discussed, but adequate for most use cases.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so description must compensate. It explains filters (orientation, size mapping to resolutions, locale), post-hoc filters (aspect_ratio, min_width, min_height with 4x oversample cap 80), and output semantics. However, not all parameters (page, per_page) are explained, but schema titles and defaults provide some info.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Search Pexels for free, commercially-usable stock videos.' It lists specific use cases (B-roll, reels, hero loops, etc.) which distinguish it from sibling tools like pexels_search_photos.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells when to use ('USE WHEN: ...') and when not to use ('DO NOT USE for AI-generated video or named real people'), and prefers this over web_search. However, it does not explicitly differentiate from sibling Pexels tools like pexels_get_popular_videos.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 8 tool updatesv0.6.0
    • First observedpexels_get_collection_media
    • First observedpexels_get_curated_photos
    • First observedpexels_get_featured_collections
    • First observedpexels_get_photo
    • First observedpexels_get_popular_videos
    • First observedpexels_get_video
    • First observedpexels_search_photos
    • First observedpexels_search_videos

TDQS

A4.7/5.0

Scored across 8 tools

Disambiguation5/5

Each tool targets a distinct resource and action (e.g., search vs. get individual, photos vs. videos, collections vs. curated vs. popular). No overlapping purposes.

Naming Consistency5/5

All tools follow a consistent 'pexels_verb_noun' pattern with clear verbs (get, search) and nouns (photos, videos, collections, media). No mixing of conventions.

Tool Count5/5

8 tools is well-scoped for a stock media API covering both photos and videos with search, individual retrieval, curated feeds, and collections. Each tool earns its place.

Completeness5/5

The tool surface covers all key Pexels features: search, single-item fetch, curated lists, popular feeds, and collection browsing. No gaps for a read-only API; uploads are outside scope.

Maintenance

ActivityInactive
ResponsivenessUnresponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that enables AI assistants to search for royalty-free images from Pexels and Unsplash using natural language, returning structured results with metadata.
    5
    59
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    A Model Context Protocol server that exposes Pexels API tools for searching and retrieving free stock photos, videos, and curated collections, enabling AI agents to incorporate royalty-free media directly from chat.
    2
    9
    145
    2
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    MCP server for the Pexels API that provides tools for searching photos and videos, retrieving curated content, and accessing featured collections. Enables natural language interaction with Pexels media search functionality.
    -

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/VictorNain26/pexels-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server