Skip to main content
Glama
Pexafy

Pexafy MCP Server

Official

pexafy-mcp

CI License: MIT

AI 어시스턴트를 위한 스톡 포토 검색.MCP 서버는 Claude Desktop, ChatGPT 또는 모든 MCP 클라이언트가 로열티 프리 이미지 라이브러리를 검색할 수 있게 해 줍니다. 자연어로 장면을 설명하거나, 예시 이미지를 주거나, "이런 느낌"으로 요청할 수 있으며, 결과를 대화 안에서 썸네일 그리드로 렌더링합니다.

원격 MCP, OAuth, 붙여넣을 API 키 없음, 3가지 도구, 이미지 인라인 렌더링.

The Pexafy result grid, rendered inline in a Claude conversation


사용법 (설치할 필요 없음)

호스팅된 서버가 다음 주소에서 실행됩니다:

https://mcp.pexafy.com/mcp

streamable-http 전송을 지원하며 OAuth 2.1로 인증합니다 — 브라우저 창에서 Pexafy에 로그인하면 커넥터가 자체 자격 증명을 받습니다. 생성해서 JSON 파일에 붙여넣거나 나중에 회전해야 할 API 키가 없습니다.

Claude (웹 및 데스크톱)

  1. Settings → Connectors를 엽니다. (Team/Enterprise에서는 소유자가 Organization settings → Connectors에서 한 번만 추가합니다.)

  2. Add custom connector를 클릭합니다.

  3. https://mcp.pexafy.com/mcp를 붙여넣고 확인합니다.

  4. 열린 창에서 Pexafy에 로그인합니다. 완료 — Claude에게 사진을 요청하면 됩니다.

Claude Code

claude mcp add --transport http pexafy https://mcp.pexafy.com/mcp

다른 MCP 클라이언트

같은 URL에 streamable-http 전송으로 연결하세요. OAuth를 구현하지 않는 클라이언트는 Pexafy API 키를 Authorization: Bearer <key> 또는 x-api-key: <key>로 보내 인증할 수 있습니다. 키는 대시보드에서 발급받으세요.

활성 상태 확인: GET /health (공개, 인증 불필요).

또한 공식 MCP 레지스트리com.pexafy/pexafy-mcp로 등록되어 있으며, Smithery에도 있습니다 — 호스트된 게이트웨이 URL을 선호하는 클라이언트를 위한 옵션입니다.

비용

무료 플랜은 커넥터 1개로 월 5,000회 검색을 지원하며 — 일반적인 사용에 충분하고 카드가 필요 없습니다. 더 높은 등급은 가격 페이지에 있습니다. 한도에 도달하면 불명확한 오류로 실패하는 대신, 어시스턴트가 채팅에서 알려줍니다.


Related MCP server: brave-image-mcp

도구

읽기 전용 도구 3가지입니다. 쓰기 권한이나 계정 변경 기능은 없습니다.

search_photos — 의미 기반 텍스트 검색

장면을 완전한 문장으로 설명하세요. Pexafy는 의미 기반이므로, 키워드보다 문장이 더 좋습니다. 모든 매개변수는 선택 사항이지만, q 또는 필터를 하나 이상 전달해야 합니다.

매개변수

타입

설명

q

string

장면을 자연어로 표현. 최대 500자.

color_name

string

다음 중 하나: red, orange, yellow, green, blue, purple, pink, brown, black, white, gray, teal, beige, gold, navy. color_hex와 함께 사용 불가.

color_hex

string

예: #1E90FF. color_name과 함께 사용 불가.

color_tolerance

integer

0(정확) ~ 255(느슨함). 기본값 20. color_hex와 함께만 사용.

orientation

string[]

landscape, portrait, square.

source

string[]

Unsplash, Pexels, Pixabay, Kaboompics, Burst, StockSnap, Picjumbo, Skitterphoto, NegativeSpace.

license_type

string[]

free, cc0.

photographer

string

정확한 사용자 이름.

after_date

string

YYYY-MM-DD. 해당 날짜 이후 게시된 사진.

cursor

string

이전 응답의 pagination.next_cursor.

search_photos_by_image — 예시 이미지로 시각 검색

참조 이미지와 비슷한 사진을 찾습니다. "이 사진 느낌인데 밤에"처럼 텍스트로 추가 조정할 수 있습니다.

매개변수

타입

설명

image_url

string

참조 이미지의 공개 http(s) URL.

image_file

object

업로드를 지원하는 호스트가 자동으로 채움 (예: ChatGPT).

image_base64

string

프로그래밍 방식 클라이언트용 원본 base64 바이트.

q

string

이미지와 함께 쓸 텍스트 ("손을 들은 모습으로").

text_alpha

number

이미지 대비 q의 가중치.

orientation, source, color_name, license_type, photographer, after_date

string

위와 동일한 필터.

cursor

string

페이지 네이션 토큰.

image_url, image_file 또는 image_base64 중 하나는 필수입니다. 이미지는 서버 측에서 가져옵니다. 최대 20MB.

get_similar_photos — 더 비슷한 사진

매개변수

타입

설명

photo_id

string

필수. 이전 결과에서 가져온 사진의 UUID.

cursor

string

페이지 네이션 토큰.

반환되는 것

모든 사진에는 id, 여러 크기 URL, 크기, 주요 색상, 방향, 출처, 라이선스, 작가, 그리고 크레딧을 위한 attribution 문자열이 포함됩니다 — 어시스턴트가 결과를 단순히 나열하지 않고, 그 결과를 바탕으로 추론할 수 있을 만큼의 정보를 갖습니다.

결과는 #1, #2, …로 번호가 매겨져서, 대화에서 말하듯 사진을 가리킬 수 있습니다. 복사할 id가 없습니다:

Asking for more photos like #1, and the assistant reasoning over the new set

MCP Apps를 지원하는 클라이언트에서는 썸네일을 클릭하면 전체 메타데이터가 포함된 세부 패널이 열립니다. 추가로 호출할 필요 없이 — 모든 정보가 이미 도구 결과에 들어 있습니다:

The detail panel: photographer, source, resolution, licence, dominant colour, orientation and description


자체 호스팅

그럴 필요는 없습니다 — 호스팅된 서버가 의도된 진입 방법입니다. 다만 이 서버는 Pexafy API의 얇고 단순한 클라이언트이므로, 자체 키로 직접 실행할 수도 있습니다.

Python 3.12+ 필요.

git clone https://github.com/Pexafy/pexafy-mcp.git && cd pexafy-mcp
./run.sh setup        # venv + editable install + seed .env
# edit .env — set PEXAFY_API_KEY
./run.sh dev          # stdio, for Claude Desktop / Claude Code

설치된 콘솔 스크립트(pip install .)를 사용:

pexafy-mcp                             # stdio (default)
PEXAFY_MCP_TRANSPORT=http pexafy-mcp   # remote Streamable HTTP

Claude Desktop / Claude Code를 stdio로 사용:

{
  "mcpServers": {
    "pexafy": {
      "command": "pexafy-mcp",
      "env": { "PEXAFY_API_KEY": "pexafy_api_…" }
    }
  }
}

Docker를 HTTP로 — docker-compose.example.yml 참고:

docker compose -f docker-compose.example.yml up -d
curl localhost:8765/health

이미지 자체의 기본값은 stdio인데, 이는 MCP 클라이언트가 컨테이너를 구동하는 데 쓰는 전송 방식이라 바로 사용할 수도 있습니다:

docker run -i --rm pexafy-mcp

이 방식은 API 키나 네트워크 없이 initializetools/list에 응답합니다. 도구 정의는 내장된 OpenAPI 스냅샷에서 가져옵니다. 키는 검색을 실행할 때만 필요합니다. HTTP 서비스는 전송만 바꾸면 되는데, 두 compose 파일 모두 그렇게 합니다.

설정

모든 설정은 환경 변수이며, 모두 선택 사항입니다. 아무것도 설정하지 않으면 pexafy-mcp는 stdio로 시작하고 오프라인 상태에서 initializetools/list 에 응답합니다. 두 가지만 알면 됩니다.

변수

기본값

용도

PEXAFY_MCP_TRANSPORT

stdio

로컬 클라이언트는 stdio, 원격 서비스는 http

PEXAFY_API_BASE_URL

http://localhost:8000

Pexafy API 루트 — https://api.pexafy.com 또는 자체 배포를 지정.

나머지는 컨테이너를 실행하는 사람보다 배포 환경에 더 관련된 것이며 [env.example]... (원문: .env.example)에 있습니다: 클라이언트가 키를 보내지 않을 때 stdio에서 쓸 기본 PEXAFY_API_KEY, 인라인 그리드 썸네일 서명에 PEXAFY_THUMB_BASE_URLPEXAFY_THUMB_HMAC_SECRET, 그리고 OAuth 리소스 서버로 HTTP 전송을 실행하기 위한 MCP_RESOLVE_SECRET와 함께 PEXAFY_OAUTH_*. 어느 것도 서버를 시작하는 데 필요하진 않습니다.


동작 원리

src/pexafy_mcp/
├── server.py     # entry point: builds the server, wires hooks, custom tools, /health
├── tooling.py    # tunes the OpenAPI-derived tools for an LLM (descriptions, value sets)
├── widget.py     # MCP Apps UI resource — the inline result grid (self-contained HTML)
├── previews.py   # signs the thumbnail URLs injected into each result
├── limits.py     # turns plan-limit (429) responses into in-chat upgrade nudges
├── auth.py       # per-user auth: OAuth Resource Server or forwarded API key
└── assets/       # vendored, shipped with the package:
    ├── openapi.json          # OpenAPI snapshot the tools are generated from
    ├── facets.json           # evolving source/license value sets
    └── ext_apps_bundle.js    # @modelcontextprotocol/ext-apps SDK (inlined in the widget)
  • 도구는 FastMCP.from_openapi()로 Pexafy OpenAPI 스펙에서 생성됩니다. 그래서 API가 유일한 소스가 되며, tooling.py가 이를 LLM용으로 다듬습니다 — 검색 핵심만 남기고 모델을 오도할 수 있는 매개변수를 제거하고, 닫힌 값 집합을 인라인해서 패싯 조회(facet lookup)가 전혀 필요가 없게 합니다.

  • build_server()가 모든 것을 조립합니다. 패키지를 가져오는 것은 부작용이 없고 네트워크 I/O를 하지 않습니다: 내장된 assets/openapi.jsonassets/facets.json을 읽기만 합니다. prepare.sh는 이 파일들을 다시 생성합니다.

  • search_photos_by_image는 손수 작성했습니다. 채팅 어시스턴트는 MCP 도구에 이진 파일을 업로드할 수 없기 때문에, 이 도구는 이미지 URL을 받아 서버 측에서 받아옵니다.

  • 인라인 그리드는 MCP Apps UI 리소스입니다. 호스트의 샌드박스 iframe은 런타임에 외부 스크립트를 가져올 수 없으므로, ext-apps 클라이언트는 번들로 묶여 인라인되어 있습니다.

개발

./run.sh test         # offline test suite (pytest)
./run.sh inspect      # MCP Inspector
./prepare.sh          # maintainers: regenerate the vendored assets/

기여는 언제나 환영합니다 — CONTRIBUTING.md 참고.

라이선스

MIT — LICENSE 참고.

이 패키지는 서드파티 자산도 재배포합니다 (Inter 글꼴, @modelcontextprotocol/ext-apps 브라우저 번들 및 그 안에 포함된 라이브러리). 각각은 자체 라이선스를 따릅니다 — THIRD_PARTY_NOTICES.md 참고.

Available Tools

3 tools
get_similar_photosFind similar photosA
Read-onlyIdempotent
Inspect

Use this tool when the user says 'find something similar', 'show me more like this', or 'I need a visually consistent set'. Requires a photo_id obtained from a previous search result. A person normally refers to a photo by the rank shown on the result grid rather than by its identifier; each search result carries both, in the same object. Each result carries: rank, its position on this page (1, 2, 3, …), which is also the number drawn on the inline grid and the handle a person naturally uses to refer to one photo among several; photo_id, the identifier the similar-photos tool takes, present in the same object as the rank; attribution, the credit line to display with the photo; and urls, the image at several sizes, urls.regular being the one to link to. Inline thumbnails are attached to this tool's result as an MCP App resource. Some clients, claude.ai on the web among them, render that resource only inside an expandable tool panel rather than in the reply itself; where it is not rendered, the photos remain reachable through their URLs.

ParametersJSON Schema
NameRequiredDescriptionDefault
cursorNoToken to fetch the next page. Take `pagination.next_cursor` from a previous response and pass it back here. See the Pagination guide.
photo_idYesThe reference photo's unique Pexafy identifier (a UUID).

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
metaNo
errorNo
successNo
paginationNo

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already indicate readOnlyHint, openWorldHint, idempotentHint, and non-destructive behavior, so the safety profile is covered. The description adds useful behavioral context: the result includes inline thumbnails as an MCP App resource, and warns that some clients (like claude.ai on web) render them only in an expandable panel, with URLs still available. This goes beyond annotations and is valuable for the agent.

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

Conciseness4/5

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

The description is relatively lengthy but every paragraph serves a purpose: it explains when to use, prerequisites, how users refer to photos (critical for agent understanding), and display behavior. It is front-loaded with the primary usage trigger and then provides necessary details. Slightly verbose but justified by the need to explain the rank vs. photo_id distinction.

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?

The tool has an output schema, so return values are covered there. The description compensates for the complexity of the tool by explaining the relationship between rank and photo_id, which is not obvious from the schema. It also addresses pagination and resource rendering behavior. Given the moderate complexity and presence of output schema, this is adequately complete, though more details on what 'similar' entails could be added.

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 coverage is 100%, with both parameters (photo_id and cursor) described in the schema. The description reinforces the use of photo_id (requires it from a prior search) and explains the cursor's role (pass pagination.next_cursor), but adds minimal additional semantics beyond the schema. Baseline 3 is appropriate given full schema coverage.

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 it finds similar photos based on a photo_id, distinct from sibling search tools by focusing on similarity rather than keywords or image upload. It explicitly ties to user phrases like 'find something similar', making its purpose actionable.

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?

It explicitly explains when to use the tool ('when the user says...'), specifies the prerequisite (photo_id from a previous search), and details how a person refers to photos (by rank) versus the identifier, which prevents misuse. It also clarifies how to use the cursor for pagination.

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

search_photosSearch photos by descriptionA
Read-onlyIdempotent
Inspect

Use this tool whenever the user needs an image, photo, or visual — for a presentation, blog, website, social-media post, mood board, or any creative project. Pexafy is a SEMANTIC search engine: describe the scene in full natural-language sentences, not keywords. Rich descriptions return far better results than tag-like queries. Good queries: 'a melancholy portrait of an old person sitting under a soft light'; 'two people sharing a bench in comfortable silence'; 'the last sunlight of the day hitting a dusty windowsill'; 'a child discovering snow for the first time'. Prefer this tool over search_photos_by_image when the user describes what they want in words. BUT if they want photos LIKE a specific image that has a URL — a photo from a previous result, or a public URL they gave — use search_photos_by_image instead (pass that URL, plus a q for any change like 'but with hands raised'). Only use THIS text tool for a reference image with NO URL (a file pasted/uploaded in the chat): describe what you see in rich detail — Pexafy is semantic, so a good description finds visually similar photos. Each result carries: rank, its position on this page (1, 2, 3, …), which is also the number drawn on the inline grid and the handle a person naturally uses to refer to one photo among several; photo_id, the identifier the similar-photos tool takes, present in the same object as the rank; attribution, the credit line to display with the photo; and urls, the image at several sizes, urls.regular being the one to link to. Inline thumbnails are attached to this tool's result as an MCP App resource. Some clients, claude.ai on the web among them, render that resource only inside an expandable tool panel rather than in the reply itself; where it is not rendered, the photos remain reachable through their URLs.

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoYour search query as a full natural-language sentence describing the scene you want — Pexafy is semantic, so sentences beat keywords. Up to 500 characters. Optional if you provide at least one filter instead. Example: 'an old man sitting at a café table he has visited every morning for thirty years'.
cursorNoToken used to fetch the next page. Take the `pagination.next_cursor` value from a previous response and pass it back here. See the [Pagination](/pagination) guide.
sourceNoKeep only photos from these providers: Unsplash, Pexels, Pixabay, Kaboompics, Burst, StockSnap, Picjumbo, Skitterphoto, NegativeSpace. Repeat the parameter to pass several.
color_hexNoKeep only photos close to this hex color (e.g. `#1E90FF`). Cannot be combined with `color_name`. Use `color_tolerance` to widen or tighten the match.
after_dateNoOnly return photos published on or after this date, formatted `YYYY-MM-DD`.
color_nameNoKeep only photos whose dominant color matches one of: red, orange, yellow, green, blue, purple, pink, brown, black, white, gray, teal, beige, gold, navy. Cannot be combined with color_hex.
orientationNoKeep only photos with these shapes: landscape, portrait, square. Repeat the parameter to pass several.
license_typeNoKeep only photos with these license types: free, cc0. 'free' means the photo can be used freely and attribution is appreciated. Repeat the parameter to pass several.
photographerNoOnly return photos from this photographer's username. Use `GET /api/v1/facets/photographers/suggest` to find usernames.
color_toleranceNoHow far a photo's color may be from `color_hex` and still match, from `0` (exact match) to `255` (very loose). Defaults to `20`. Only applies when `color_hex` is set.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
metaNo
errorNo
successNo
paginationNo

TDQS

A4.8/5.0
Behavior5/5

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

The annotations already declare a safe, read-only, idempotent operation, so the description's job is to add context beyond that. It does: semantic search behavior, result-field semantics (rank, photo_id, attribution, urls), the inline-thumbnail MCP resource, and the rendering caveat on claude.ai. 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.

Conciseness4/5

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

The description is long, but it is front-loaded with the primary use case and every section earns its place: query style, examples, sibling distinction, result fields, and rendering behavior. A few example queries could be trimmed without losing meaning, which keeps it from a 5.

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?

For a tool with 10 optional parameters, an output schema, and two siblings, the description is complete: it explains semantic querying, when to use each sibling, what each result field means, and how the inline resource may render. The output schema covers return values, so the description correctly focuses on selection and invocation behavior.

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 coverage is 100%, so the baseline is 3 and the schema already documents every parameter. The description adds real value by teaching the core q semantics, showing strong example queries, and explaining how photo_id connects to the similar-photos sibling, but it does not need to repeat the schema.

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 opens with a specific use case ('user needs an image, photo, or visual') and names the resource being searched. It clearly differentiates this text-query tool from search_photos_by_image, which is the main sibling it could be confused with.

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?

It gives explicit when-to-use guidance ('Prefer this tool over search_photos_by_image when the user describes what they want in words') and names the alternative with the exact input it needs. It also handles the edge case of a reference image with no URL, telling the agent to describe it in rich detail instead.

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

search_photos_by_imageSearch photos by example imageA
Read-onlyIdempotent
Inspect

Find visually similar stock photos from an EXAMPLE IMAGE, optionally TWEAKED with words. This is the right tool for 'find photos LIKE THIS but ' (e.g. 'like this but with their hands raised', 'the same scene but at night'). Give the reference image one of three ways: (1) image_url — a public http(s) link: a photo from a PREVIOUS search result (reuse its image_url/urls.regular), or any public URL the user provides; (2) image_file — auto-filled by the host when the user UPLOADS an image (e.g. ChatGPT) — it is populated by the host, not by the caller; (3) image_base64 — raw base64 image bytes, for a programmatic client that already holds the file. A chat assistant has no access to the exact bytes of an image it was shown, so image_base64 is not available to it. Put any change in q; raise text_alpha to weight the text more. If the reference image has no URL and the host did not auto-provide image_file (e.g. a file pasted into a chat that can't be forwarded), you cannot send it — describe what you see and use search_photos instead. Every result carries an attribution you show.

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoYour search query as a full natural-language sentence describing the scene you want — Pexafy is semantic, so sentences beat keywords. Up to 500 characters. Optional if you provide at least one filter instead. Example: 'an old man sitting at a café table he has visited every morning for thirty years'.
cursorNoToken to fetch the next page. Take `pagination.next_cursor` from a previous response and pass it back here — no need to re-upload the image. See the Pagination guide.
sourceNoKeep only photos from these providers: Unsplash, Pexels, Pixabay, Kaboompics, Burst, StockSnap, Picjumbo, Skitterphoto, NegativeSpace. Repeat the parameter to pass several.
image_urlNoPublic http(s) URL of the reference image. Reuse the `image_url` of a photo from a previous search result, or any public URL the user provides.
after_dateNoOnly return photos published on or after this date, formatted YYYY-MM-DD.
color_nameNoKeep only photos whose dominant color matches one of: red, orange, yellow, green, blue, purple, pink, brown, black, white, gray, teal, beige, gold, navy. Cannot be combined with color_hex.
image_fileNoFilled in by the host when the user uploads an image, not by the caller. Carries the upload's `download_url` and `file_id`.
text_alphaNoBalance between your text and the image when both are provided, from `0` to `10`. `0` ignores the text (pure visual search), `1.7` (the default) is balanced, and higher values give your words more weight. Has no effect without `q`.
orientationNoKeep only photos with these shapes: landscape, portrait, square. Repeat the parameter to pass several.
image_base64NoThe reference image as base64 bytes, optionally as a `data:` URL. For a client that already holds the bytes; prefer `image_url` when a link exists.
license_typeNoKeep only photos with these license types: free, cc0. 'free' means the photo can be used freely and attribution is appreciated. Repeat the parameter to pass several.
photographerNoOnly return photos from this photographer's exact username.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
metaNo
errorNo
successNo
paginationNo

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already declare readOnly and idempotent, so the description doesn't need to repeat that. It adds meaningful context beyond annotations: the image_file is host-populated rather than caller-set, image_base64 is unavailable to chat assistants, and every result carries an attribution to display. 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.

Conciseness4/5

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

The description is long but every section earns its place—it covers usage, input methods, edge cases, and attribution. The numbered list of image-providing options is clear and well-structured. It could be slightly trimmed, but the density is justified by the tool's complexity.

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 12 parameters, 100% schema coverage, and an output schema, the description provides all necessary behavioral context: how to provide the reference image, the host-filling behavior of image_file, the text weighting mechanism, and the fallback to search_photos. It also mentions the attribution requirement from results, which is not in the schema.

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 100%, so the schema already documents each parameter. The description adds practical nuance beyond the schema, such as how text_alpha weights text against image, and the guidance to put any modification in q. This exceeds the baseline for fully covered schemas.

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 finds visually similar stock photos from an example image, optionally tweaked with words. It explicitly distinguishes from siblings by providing a usage scenario ('find photos LIKE THIS but <change>') and names the alternative (search_photos) when the image can't be sent.

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 when-to-use guidance with examples and a concrete fallback: when the image has no URL and no auto-provided file, use search_photos instead. It also explains the three ways to supply the reference image and which is appropriate for different clients.

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. 1 tool updatev0.4.9
    • Changedsearch_photos_by_image19 fields changed
      • addedInput schema / properties / after_date / description
        Added value: +"Only return photos published on or after this date, formatted YYYY-MM-DD."
      • addedInput schema / properties / color_name / description
        Added value: +"Keep only photos whose dominant color matches one of: red, orange, yellow, green, blue, purple, pink, brown, black, white, gray, teal, beige, gold, navy. Cannot be combined with color_hex."
      • addedInput schema / properties / cursor / description
        Added value: +"Token to fetch the next page. Take `pagination.next_cursor` from a previous response and pass it back here — no need to re-upload the image. See the Pagination guide."
      • addedInput schema / properties / image_base64 / description
        Added value: +"The reference image as base64 bytes, optionally as a `data:` URL. For a client that already holds the bytes; prefer `image_url` when a link exists."
      • addedInput schema / properties / image_file / additionalProperties
        Added value: +false
      • removedInput schema / properties / image_file / anyOf
        Removed value: -[
        -  {
        -    "additionalProperties": true,
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • removedInput schema / properties / image_file / default
        Removed value: -null
      • addedInput schema / properties / image_file / description
        Added value: +"Filled in by the host when the user uploads an image, not by the caller. Carries the upload's `download_url` and `file_id`."
      • addedInput schema / properties / image_file / properties
        Added value: +{
        +  "download_url": {
        +    "type": "string"
        +  },
        +  "file_id": {
        +    "type": "string"
        +  },
        +  "file_name": {
        +    "type": "string"
        +  },
        +  "mime_type": {
        +    "type": "string"
        +  }
        +}
      • addedInput schema / properties / image_file / required
        Added value: +[
        +  "download_url",
        +  "file_id"
        +]
      • addedInput schema / properties / image_file / type
        Added value: +"object"
      • addedInput schema / properties / image_url / description
        Added value: +"Public http(s) URL of the reference image. Reuse the `image_url` of a photo from a previous search result, or any public URL the user provides."
      • addedInput schema / properties / license_type / description
        Added value: +"Keep only photos with these license types: free, cc0. 'free' means the photo can be used freely and attribution is appreciated. Repeat the parameter to pass several."
      • addedInput schema / properties / orientation / description
        Added value: +"Keep only photos with these shapes: landscape, portrait, square. Repeat the parameter to pass several."
      • addedInput schema / properties / photographer / description
        Added value: +"Only return photos from this photographer's exact username."
      • addedInput schema / properties / q / description
        Added value: +"Your search query as a full natural-language sentence describing the scene you want — Pexafy is semantic, so sentences beat keywords. Up to 500 characters. Optional if you provide at least one filter instead. Example: 'an old man sitting at a café table he has visited every morning for thirty years'."
      • addedInput schema / properties / source / description
        Added value: +"Keep only photos from these providers: Unsplash, Pexels, Pixabay, Kaboompics, Burst, StockSnap, Picjumbo, Skitterphoto, NegativeSpace. Repeat the parameter to pass several."
      • addedInput schema / properties / text_alpha / description
        Added value: +"Balance between your text and the image when both are provided, from `0` to `10`. `0` ignores the text (pure visual search), `1.7` (the default) is balanced, and higher values give your words more weight. Has no effect without `q`."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "properties": {
        +    "data": {
        +      "items": {
        +        "description": "A photo result. Fields returned can be narrowed with the `fields` parameter and may depend on your plan.",
        +        "properties": {
        +          "alt_description": {
        +            "description": "Accessibility-friendly text.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "attribution": {
        +            "description": "Ready-to-display credit for the photographer/source.",
        +            "properties": {
        +              "html": {
        +                "description": "HTML attribution snippet.",
        +                "type": "string"
        +              },
        +              "plain": {
        +                "description": "Plain-text attribution.",
        +                "type": "string"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "blur_hash": {
        +            "description": "BlurHash placeholder string.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "color_hex": {
        +            "description": "Dominant color hex code.",
        +            "type": "string"
        +          },
        +          "color_name": {
        +            "description": "Dominant color name.",
        +            "type": "string"
        +          },
        +          "description": {
        +            "description": "AI-generated caption.",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "height": {
        +            "type": [
        +              "integer",
        +              "null"
        +            ]
        +          },
        +          "image_url": {
        +            "description": "Canonical source image URL.",
        +            "format": "uri",
        +            "type": "string"
        +          },
        +          "license_type": {
        +            "description": "License type (e.g. `free`).",
        +            "type": "string"
        +          },
        +          "orientation": {
        +            "enum": [
        +              "landscape",
        +              "portrait",
        +              "square"
        +            ],
        +            "type": "string"
        +          },
        +          "photo_id": {
        +            "description": "Unique Pexafy identifier (UUID).",
        +            "type": "string"
        +          },
        +          "photographer_full_name": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "photographer_url": {
        +            "format": "uri",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "photographer_username": {
        +            "type": "string"
        +          },
        +          "relevance_score": {
        +            "description": "Match score 0–1 (higher is better). Only on search results.",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "source": {
        +            "description": "Provider (e.g. `Pexels`, `Unsplash`, `Pixabay`).",
        +            "type": "string"
        +          },
        +          "source_description": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "source_image_url": {
        +            "description": "URL of the photo's page on the provider.",
        +            "format": "uri",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "uploaded_on": {
        +            "description": "Publication date (YYYY-MM-DD).",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "urls": {
        +            "description": "Ready-to-use image links in five sizes.",
        +            "properties": {
        +              "full": {
        +                "format": "uri",
        +                "type": "string"
        +              },
        +              "large": {
        +                "format": "uri",
        +                "type": "string"
        +              },
        +              "regular": {
        +                "format": "uri",
        +                "type": "string"
        +              },
        +              "small": {
        +                "format": "uri",
        +                "type": "string"
        +              },
        +              "thumb": {
        +                "format": "uri",
        +                "type": "string"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "width": {
        +            "type": [
        +              "integer",
        +              "null"
        +            ]
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "error": {
        +      "anyOf": [
        +        {
        +          "properties": {
        +            "code": {
        +              "description": "Machine-readable error code (e.g. `MISSING_PARAMS`, `PHOTO_NOT_FOUND`).",
        +              "type": "string"
        +            },
        +            "message": {
        +              "description": "Human-readable error message.",
        +              "type": "string"
        +            },
        +            "request_id": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "code",
        +            "message"
        +          ],
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "meta": {
        +      "properties": {
        +        "request_id": {
        +          "description": "Unique id for this request (quote it in support tickets).",
        +          "type": "string"
        +        },
        +        "took_ms": {
        +          "description": "Server processing time in milliseconds.",
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "pagination": {
        +      "anyOf": [
        +        {
        +          "properties": {
        +            "has_more": {
        +              "description": "Whether another page exists.",
        +              "type": "boolean"
        +            },
        +            "next_cursor": {
        +              "description": "Pass back as `cursor` for the next page; `null` when `has_more` is false.",
        +              "type": [
        +                "string",
        +                "null"
        +              ]
        +            },
        +            "per_page": {
        +              "description": "Number of items per page.",
        +              "type": "integer"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "type": "object",
        +  "x-fastmcp-top-level-schema": "PhotoListResponse"
        +}
  2. 2 tool updatesv0.4.0
    • Addedget_similar_photos
    • Removedphoto_similar
  3. 3 tool updatesv0.2.0
    • First observedphoto_similar
    • First observedsearch_photos
    • First observedsearch_photos_by_image

TDQS

A4.4/5.0
Disambiguation4/5

Each tool has a clearly documented input type (text query vs. image/file vs. previous photo_id), and the descriptions are explicit about which phrase or condition triggers each tool. However, search_photos_by_image and get_similar_photos both produce visually similar photos, and their boundary (one tweaks by text, the other just fetches similar) could occasionally mislead an agent even with the detailed guidance.

Naming Consistency4/5

All names follow a snake_case verb_noun pattern (search_photos, search_photos_by_image, get_similar_photos), and the shared 'search_photos' prefix on two tools is helpful. The slight deviation is 'get' in get_similar_photos versus 'search' elsewhere for the same core concept, but the pattern is otherwise uniform and predictable.

Tool Count4/5

Three tools is a lean but sensible footprint for a dedicated photo-search server, covering the natural query modalities (text, image, similar-by-id). While each tool does earn its place, the set feels slightly minimal—no dedicated tool for fetching individual photo details, but results already carry URLs and attribution, so it works.

Completeness4/5

The core workflow is complete: text query → results → similar-by-photo_id, and image query → results with tweakable text, covering the main stock-photo search use cases with no dead ends. Minor gaps exist (no downloadable/collections/curated feed support, no orientation/filter parameters), but agents can work around these with richer natural-language calls to search_photos.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    This MCP server enables AI assistants to search for images on Wikimedia Commons, providing detailed metadata and optional thumbnail combinations to assist AI models in visual comparisons.
    1
    2
    Apache 2.0
  • F
    license
    A
    quality
    D
    maintenance
    An MCP server that provides image search capabilities via the Brave Image Search API, allowing AI assistants to search images with various filters and perform batch queries.
    2
    1
    -
  • 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

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/Pexafy/pexafy-mcp'

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