Pexafy Stock Photos
OfficialPexafy Stock Photos is a read-only MCP server for finding free, real stock photographs by text or by image and returning them with credits, licences and usable image links.
Search by description (
search_photos): one concise English sentence, optional hard filter for landscape/portrait/square; returns ranked results withphoto_id, source, licence, credit line, dimensions, alt text and a 1280 px image link.Search by image (
search_photos_by_image): find visually similar photos using a Pexafyphoto_id, a publicimage_url, an uploadedimage_file, or base64 bytes — optionally adjusted with words ("like this, but at night").Fetch a photo file (
get_photo_file_by_photo_id): one photograph as an image file up to 1280 px wide, with its credit line.Retrieve grid picks (
get_grid_selected_photos): the photos liked in the chat grid, in the order chosen.Connect an account (
connect_account): OAuth sign-in prompt to attach a Pexafy account and raise the search allowance;check_onlyreports connection state.Use it anywhere: works over Streamable HTTP at
https://mcp.pexafy.com/mcpin ChatGPT, Claude, VS Code, Cursor, Codex and other MCP clients — no API key, anonymous search allowed, with daily/monthly budget notices returned in results.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Pexafy Stock Photosfind an aerial photo of a tropical beach with turquoise water"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Ask. Choose together. Put them to work.
🗣️ Ask, in your own words
Tell your assistant what you are working on, the way you would tell a colleague: “I'm writing a short article about Kyoto in autumn. Find photos of a temple garden with red maple leaves.” It writes the search; Pexafy matches the scene, not tags.
🤝 Choose together
Sixteen photographs come back. Open one large, swipe, heart the keepers, press ≈ for more like it: your picks go back to the assistant, in your order. Or simply answer in words: “the third one, but wider”.
🚀 Put them to work
The assistant carries on with them: the article with its photos in place, the slide, the landing page, the post. Each photograph keeps its licence and the credit line to display, and comes as an image file when the work needs one.
Related MCP server: Wikimedia-Search-Images
With the grid, or without it
In a chat that draws it | In an agent, a terminal or a script |
ChatGPT, Claude, VS Code, Cursor. The photographs appear as a grid in the conversation. You see them, open them, like them; the assistant works from what you picked. | Claude Code, Codex, any MCP client. Each result arrives as a link with its licence and credit line. The assistant chooses, fetches the file and places it in your Markdown, HTML, slides or CMS. |
Add it in 30 seconds
Where | How |
VS Code | Install in VS Code, or |
VS Code Insiders | |
GitHub Copilot app | |
GitHub MCP Registry | Pexafy's page in the registry, with its install buttons |
ChatGPT | Add Pexafy from ChatGPT's plugin directory |
Claude | Customize → Connectors → Add custom connector, then |
Claude Code |
|
Codex |
|
GitHub Copilot CLI |
|
Cursor | |
Goose, Kiro, Gemini CLI, OpenCode, Cline, Zed… | One click or one command each, on pexafy.com/mcp |
Any MCP client | Streamable HTTP at |
Zero friction: nothing to install, no API key. Most clients search right away, without an account. When you want your own account, ask the assistant to connect my Pexafy account: it opens Pexafy's sign-in page in your browser (OAuth), and nothing is pasted anywhere. ChatGPT and Claude ask you to sign in once; a free account is enough.
Five tools, all read-only
Tool | What it does |
| Photographs described in one sentence, in any language, optionally only landscape, portrait or square. |
| Photographs that look like a picture (a link, an upload) or like a Pexafy photo: “like this, but at night”. |
| One photograph as an image file, up to 1280 px wide, with its credit line. |
| The photographs you liked in the grid, in the order you chose. |
| Links your Pexafy account, right from the conversation. |
Where the photos come from
Pexafy searches its own index of millions of free-to-use photographs, collected from stock libraries such as Unsplash, Pexels and Pixabay. Every photograph is indexed by meaning, so a whole scene in one sentence beats a list of keywords. Each result names its source and licence and carries the credit line to display.
Available Tools
3 toolsconnect_accountConnect a Pexafy accountARead-onlyIdempotentInspect
Asks the host to offer its own flow for connecting a Pexafy account, when none is attached. Use it when the person asks to connect, link or sign in to a Pexafy account, or wants more searches than the daily allowance available without an account.
When no account is attached, it returns an error result that carries an account-connection request for the host: the error is how that request is delivered, not a failure. A host that supports it shows its own account-connection prompt, which the person completes or dismisses; other hosts show only the result's text. Calling it again returns the same request. When an account is already attached, it says so and starts nothing.
It does not search, and searching does not require calling it. check_only reads the state without opening a prompt; leave it unset when the person wants to connect or sign in.
| Name | Required | Description | Default |
|---|---|---|---|
| check_only | No | `true` reports whether an account is connected — and the allowance in force — without opening the connection prompt. Leave it unset when the person wants to connect or sign in. |
Output Schema
| Name | Required | Description |
|---|---|---|
| budget | No | What is left of the current allowance, or null when it is not worth saying. |
| connected | No | Whether an account is attached to this conversation. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations: it discloses that the connection request is delivered as an error result ('the error is how that request is delivered, not a failure'), that behavior is host-dependent (prompt vs. text-only), that repeat calls return the same request, and that an already-attached account makes it a no-op. This is exactly the kind of non-obvious behavior an agent could otherwise misread as a failure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose and usage, then layers behavioral caveats in three compact paragraphs. Some restatement occurs (idempotency and the already-attached no-op are covered twice), but every sentence carries operational information and nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be documented, yet the description still explains the error-result contract that is the crux of using this tool correctly. With one optional parameter, complete annotations, and host-variation disclosed, an agent has everything needed to invoke it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single parameter is fully documented in the schema, so the baseline is 3. The description restates the `check_only` semantics ('reads the state without opening a prompt') but adds no format or edge-case detail beyond the schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Asks the host to offer its own flow for connecting a Pexafy account') and immediately distinguishes it from siblings by declaring 'It does not search, and searching does not require calling it.' An agent can tell what this does and does not do without inspecting any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit trigger conditions ('when the person asks to connect, link or sign in... or wants more searches than the daily allowance') and an explicit non-use case ('searching does not require calling it'). It also carves out the `check_only` alternative for state reads versus opening a prompt.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_photosSearch free stock photosARead-onlyInspect
Use this when the user asks for a real photograph, or states a need that a photograph fills, and the picture is not already in the conversation.
Call it when they ask outright: “find me photos of…”, “show me images of…”, “I need a picture of…”, “do you have a photo of…”, “where can I find free photos of…”, in any language. Call it when they describe the need without asking to search: “I'm writing an article and need a header image”, “my landing page needs a hero image”, “I need something to illustrate this”. Call it when they ask for something meant to carry photographs: “write an article with pictures”, “a deck with images”. Call it when they name only the picture, with no reason given: “a photo of a white mug”, “a train in Japan”. If the user is working on something that usually carries photographs — an article, a page, a deck, a post — without asking for any, you may offer to look for some; call it only once they accept.
This covers requests for photographs for articles, blog posts, websites, landing pages, products, slides, documents, reports, social posts, ads, newsletters, banners, thumbnails, covers, posters, backgrounds, wallpapers and mood boards; photographs that illustrate a concept, explain a subject or accompany a piece of writing; and any request for free, stock, royalty-free, commercially usable, real or documentary photographs.
A request for a visual is not always a request for a photograph: this tool finds photographs that already exist — not illustrations, drawings, logos, icons, diagrams or screenshots — and it does not generate, edit or upscale an image, nor look for a named person.
It searches Pexafy's own index of millions of free-to-use photographs from stock libraries such as Unsplash, Pexels and Pixabay, matched to the scene described. Each result carries a rank, a photo_id, its licence, the credit line to display and an image link.
| Name | Required | Description | Default |
|---|---|---|---|
| english_search_sentence | Yes | Required. Describe the desired photograph in one concise English sentence, focusing on its visible subject and scene. Be specific: “Two colleagues laughing in a bright open-plan office” is more effective than “People office”. Keywords work too — send the user's own words, in English, rather than inventing detail they did not ask for. Maximum 250 characters. Describe one coherent scene, focusing on what should appear in the photograph rather than its intended use. Specify the requested photo shape or orientation in explicit_orientation_filter, not here. Example: “An old man sitting at a café table he has visited every morning for thirty years”. | |
| explicit_orientation_filter | No | Omit this parameter unless the user explicitly asks for a photo shape or orientation in their own words, or names a format whose shape is part of its definition — a vertical Short, a banner, a square post, a phone wallpaper. This is a hard filter, not a preference: it removes photos with other shapes before ranking, so using a shape the user did not request can exclude the best matches. Never infer the shape from a word inside `english_search_sentence` — “landscape” in “a natural landscape” names the scene, not the format — nor from the subject, the composition, or a purpose that fixes no shape (“a photo for my blog post”, “something for my landing page”). If you are choosing a value rather than repeating one explicitly requested by the user, omit it. Allowed values: `landscape`, `portrait`, `square`. Multiple values are allowed: two shapes return more than one alone, though any filter still returns less than none. For example, “anything but portrait” means `['landscape', 'square']`. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | |
| error | No | |
| budget | No | Present only when the caller is near the end of an allowance — the daily one without an account, the monthly one with. What is left of it, and, for a caller with no account, the one sentence that says what lifts the limit. Also carried by a refusal, where it describes the wall itself. |
| notice | No | Why this answer is empty, when it is. A plan limit was reached: the allowance and when it returns. There is nothing to retry until then. |
| success | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/openWorldHint/idempotentHint(false)/destructiveHint(false), so the safety profile is covered. The description adds genuinely useful context beyond them: the index is Pexafy's own corpus of free-to-use photos sourced from Unsplash, Pexels and Pixabay, and results carry a licence and a credit line that must be displayed. It slightly overlaps the output schema by listing result fields, and mentions no rate limits or failure behavior, keeping it at 4 rather than 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the primary condition ('Use this when...') and organized into triggers, scope and exclusions. It is long and several quoted example requests are near-duplicates, costing some efficiency, but every section serves routing or scope-setting rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 2-parameter, read-only search tool whose safety annotations and output schema are both present, the description supplies everything an agent needs to decide to call it: triggers, exclusions, entity scope, and the fact that it is a hard-filtered, externally sourced search. Nothing required for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters carry rich guidance (max length, specificity advice, explicit orientation rules, multi-value semantics), so the baseline is 3. The description body itself adds only the loose framing that results are 'matched to the scene described' and carries no parameter-level detail of its own.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (finds/searches) and resource (existing free stock photographs matched to a described scene) and bounds it sharply: not illustrations, logos, icons, diagrams or screenshots, and no generation, editing, upscaling or named-person lookup. Combined with the parameter name `english_search_sentence`, an agent can distinguish this from the text-query sibling `search_photos_by_image` without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Enumerates concrete trigger phrasings, covers indirect needs ('my landing page needs a hero image'), and explicitly states when NOT to use it (illustrations, drawings, logos, icons, diagrams, screenshots, image generation/editing, named persons). It even specifies an offer-first-then-call-once protocol for working contexts that usually carry photos.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_photos_by_imageFind photos that look like an image or a Pexafy photoARead-onlyInspect
Use this when the user wants photographs that look like a picture, rather than ones described in words: a picture they link to, one the host passes to the tool as a file, or a Pexafy photo already found.
Call it for “find images like this”, “something similar to this photo”, “find a free alternative to this image”, “I need this but royalty-free”, “photos in this style”, “more like the second one”, whether or not they say “search by image”.
Give exactly one reference: photo_id for a Pexafy photo from an earlier result; image_url for a picture at a public URL, such as a link the user pasted; image_file when the host passes the user's uploaded image to the tool; image_base64 for image bytes a client already holds. Sending two is refused. A picture that is only visible in the conversation — not linked, not passed to the tool — is not a reference this tool can receive; its scene can be searched in words with search_photos. Words are optional, in english_search_sentence: with a photo_id, the words that photograph was found under; with an image, only what the user wants changed or kept (“like this but at night”).
It finds free stock photographs in Pexafy's index that visually match the reference. The reference image is sent to Pexafy only to run the search; it is not stored. Each result carries a rank, a photo_id, its licence, the credit line to display and an image link.
| Name | Required | Description | Default |
|---|---|---|---|
| photo_id | No | The photo_id of the Pexafy reference photo, copied from the result the user or assistant is referring to. It is a UUID such as `019e1ecb-0039-7da6-b1ca-987ee4d337c0`. Use it instead of an image when the reference is a Pexafy photo returned in an earlier search, and pass the words of that search in `english_search_sentence` if needed. | |
| image_url | No | Public http(s) URL pointing directly to the reference image file, including a URL the user pasted in the conversation. For a photograph Pexafy returned, send its `photo_id` instead. | |
| image_file | No | The user's uploaded image, as a host that passes uploads to tools provides it: the upload's `download_url` and `file_id`. A picture that is only visible in the conversation has neither. | |
| image_base64 | No | Reference image as base64-encoded bytes, optionally as a data: URL. Use for programmatic clients that already hold the image data. | |
| english_search_sentence | No | Optional, and usable with any reference. Send the words that say what the user wants from the reference: with a `photo_id`, the words that photograph was found under, so the results stay on the subject they asked for; with an image, what they want changed or kept from it (“like this but at night”). The reference stays the main signal and these words adjust it. With an image, send the change alone (“at night”) rather than the whole scene rewritten, which would outweigh the picture instead of adjusting it; with a `photo_id`, the full sentence that photograph was found under is what to send. In English, like the sentence of a text search. The words a reference photograph was found under are the best ones. When it is unclear whether they want the same subject or simply the same look, send the words: staying on the subject is the safer default. Omit them only when they plainly want photographs that look like the picture itself. | |
| explicit_orientation_filter | No | Omit this parameter unless the user explicitly asks for a photo shape or orientation in their own words, or names a format whose shape is part of its definition — a vertical Short, a banner, a square post, a phone wallpaper. This is a hard filter, not a preference: it removes photos with other shapes before ranking, so using a shape the user did not request can exclude the best matches. Never infer the shape from the reference image the user gave — its shape is a property of the picture they had, not a constraint on the ones they want — nor from the subject, the composition, or a purpose that fixes no shape (“a photo for my blog post”, “something for my landing page”). If you are choosing a value rather than repeating one explicitly requested by the user, omit it. Allowed values: `landscape`, `portrait`, `square`. Multiple values are allowed: two shapes return more than one alone, though any filter still returns less than none. For example, “anything but portrait” means `['landscape', 'square']`. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | |
| error | No | |
| budget | No | Present only when the caller is near the end of an allowance — the daily one without an account, the monthly one with. What is left of it, and, for a caller with no account, the one sentence that says what lifts the limit. Also carried by a refusal, where it describes the wall itself. |
| notice | No | Why this answer is empty, when it is. A plan limit was reached: the allowance and when it returns. There is nothing to retry until then. |
| success | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, non-idempotent and non-destructive, so the safety profile is covered. The description adds real value beyond that: exactly one reference is accepted and 'sending two is refused', and the reference image 'is sent to Pexafy only to run the search; it is not stored'. It stops short of describing ranking behaviour or failure modes for unreachable URLs, so not a full 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loading is excellent — the when-to-use triggers come first — but the body is roughly 400 words and the guidance for english_search_sentence and explicit_orientation_filter largely restates the schema descriptions almost verbatim, which is padding rather than added value. The orientation paragraph in particular repeats the schema's own caution about it being a hard filter.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need no explanation (the brief mention of rank/licence/credit is a bonus, not a requirement), and annotations carry the safety profile. The description still covers the privacy handling of the reference image and the single-reference constraint, so nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds cross-parameter semantics the schema cannot express per-field: the mutually exclusive 'exactly one reference' rule across photo_id/image_url/image_file/image_base64, and the relationship between the reference and english_search_sentence ('the reference stays the main signal and these words adjust it', 'the full sentence that photograph was found under is what to send').
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — finds free stock photographs in Pexafy's index that visually match a reference image — and explicitly distinguishes itself from the sibling search_photos by noting that an unlinked picture's scene 'can be searched in words with search_photos'. An agent can route between the two tools without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit trigger phrases ('find images like this', 'more like the second one'), the condition under which the tool is inapplicable (a picture only visible in the conversation, not linked or passed), and names the alternative tool for that case. When-to-use, when-not-to-use, and the alternative are all present.
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.
2 tool updates
v1.0.1- Changed
search_photos11 fields changed- added
Output schema / properties / data / items / properties / alt_description / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - removed
Output schema / properties / data / items / properties / alt_description / typeRemoved value: -[ - "string", - "null" -] - added
Output schema / properties / data / items / properties / height / anyOfAdded value: +[ + { + "type": "integer" + }, + { + "type": "null" + } +] - removed
Output schema / properties / data / items / properties / height / typeRemoved value: -[ - "integer", - "null" -] - added
Output schema / properties / data / items / properties / photographer_full_name / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - removed
Output schema / properties / data / items / properties / photographer_full_name / typeRemoved value: -[ - "string", - "null" -] - added
Output schema / properties / data / items / properties / source_image_url / anyOfAdded value: +[ + { + "format": "uri", + "type": "string" + }, + { + "type": "null" + } +] - removed
Output schema / properties / data / items / properties / source_image_url / formatRemoved value: -"uri" - removed
Output schema / properties / data / items / properties / source_image_url / typeRemoved value: -[ - "string", - "null" -] - added
Output schema / properties / data / items / properties / width / anyOfAdded value: +[ + { + "type": "integer" + }, + { + "type": "null" + } +] - removed
Output schema / properties / data / items / properties / width / typeRemoved value: -[ - "integer", - "null" -]
- Changed
search_photos_by_image11 fields changed- added
Output schema / properties / data / items / properties / alt_description / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - removed
Output schema / properties / data / items / properties / alt_description / typeRemoved value: -[ - "string", - "null" -] - added
Output schema / properties / data / items / properties / height / anyOfAdded value: +[ + { + "type": "integer" + }, + { + "type": "null" + } +] - removed
Output schema / properties / data / items / properties / height / typeRemoved value: -[ - "integer", - "null" -] - added
Output schema / properties / data / items / properties / photographer_full_name / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - removed
Output schema / properties / data / items / properties / photographer_full_name / typeRemoved value: -[ - "string", - "null" -] - added
Output schema / properties / data / items / properties / source_image_url / anyOfAdded value: +[ + { + "format": "uri", + "type": "string" + }, + { + "type": "null" + } +] - removed
Output schema / properties / data / items / properties / source_image_url / formatRemoved value: -"uri" - removed
Output schema / properties / data / items / properties / source_image_url / typeRemoved value: -[ - "string", - "null" -] - added
Output schema / properties / data / items / properties / width / anyOfAdded value: +[ + { + "type": "integer" + }, + { + "type": "null" + } +] - removed
Output schema / properties / data / items / properties / width / typeRemoved value: -[ - "integer", - "null" -]
4 tool updates
v1.0.0- Added
connect_account - Removed
get_similar_photos - Changed
search_photos39 fields changed- removed
Input schema / properties / after_dateRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Only return photos published on or after this date, formatted `YYYY-MM-DD`.", - "example": "2025-01-01", - "title": "After Date" -} - removed
Input schema / properties / color_hexRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Keep 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.", - "title": "Color Hex" -} - removed
Input schema / properties / color_nameRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "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.", - "example": "blue", - "title": "Color Name" -} - removed
Input schema / properties / color_toleranceRemoved value: -{ - "anyOf": [ - { - "maximum": 255, - "minimum": 0, - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "How 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.", - "title": "Color Tolerance" -} - removed
Input schema / properties / cursorRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Token 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.", - "title": "Cursor" -} - added
Input schema / properties / english_search_sentenceAdded value: +{ + "description": "Required. Describe the desired photograph in one concise English sentence, focusing on its visible subject and scene.\n\nBe specific: “Two colleagues laughing in a bright open-plan office” is more effective than “People office”. Keywords work too — send the user's own words, in English, rather than inventing detail they did not ask for.\n\nMaximum 250 characters. Describe one coherent scene, focusing on what should appear in the photograph rather than its intended use.\n\nSpecify the requested photo shape or orientation in explicit_orientation_filter, not here.\n\nExample: “An old man sitting at a café table he has visited every morning for thirty years”.", + "examples": [ + "two people sharing a bench in comfortable silence" + ], + "maxLength": 250, + "minLength": 1, + "type": "string" +} - added
Input schema / properties / explicit_orientation_filterAdded value: +{ + "anyOf": [ + { + "items": { + "enum": [ + "landscape", + "portrait", + "square" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Omit this parameter unless the user explicitly asks for a photo shape or orientation in their own words, or names a format whose shape is part of its definition — a vertical Short, a banner, a square post, a phone wallpaper.\n\nThis is a hard filter, not a preference: it removes photos with other shapes before ranking, so using a shape the user did not request can exclude the best matches.\n\nNever infer the shape from a word inside `english_search_sentence` — “landscape” in “a natural landscape” names the scene, not the format — nor from the subject, the composition, or a purpose that fixes no shape (“a photo for my blog post”, “something for my landing page”). If you are choosing a value rather than repeating one explicitly requested by the user, omit it.\n\nAllowed values: `landscape`, `portrait`, `square`. Multiple values are allowed: two shapes return more than one alone, though any filter still returns less than none. For example, “anything but portrait” means `['landscape', 'square']`." +} - removed
Input schema / properties / license_typeRemoved value: -{ - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "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.", - "example": "free", - "title": "License Type" -} - removed
Input schema / properties / orientationRemoved value: -{ - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Keep only photos with these shapes: landscape, portrait, square. Repeat the parameter to pass several.", - "example": "landscape", - "title": "Orientation" -} - removed
Input schema / properties / photographerRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Only return photos from this photographer's username. Use `GET /api/v1/facets/photographers/suggest` to find usernames.", - "example": "nasa", - "title": "Photographer" -} - removed
Input schema / properties / qRemoved value: -{ - "anyOf": [ - { - "maxLength": 500, - "type": "string" - }, - { - "type": "null" - } - ], - "description": "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'.", - "example": "two people sharing a bench in comfortable silence", - "title": "Q" -} - removed
Input schema / properties / sourceRemoved value: -{ - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Keep only photos from these providers: Unsplash, Pexels, Pixabay, Kaboompics, Burst, StockSnap, Picjumbo, Skitterphoto, NegativeSpace. Repeat the parameter to pass several.", - "example": "Unsplash", - "title": "Source" -} - changed
Input schema / requiredPrevious value: -[]New value: +[ + "english_search_sentence" +] - added
Output schema / properties / budgetAdded value: +{ + "description": "Present only when the caller is near the end of an allowance — the daily one without an account, the monthly one with. What is left of it, and, for a caller with no account, the one sentence that says what lifts the limit. Also carried by a refusal, where it describes the wall itself.", + "properties": { + "limit": { + "description": "Searches allowed in that period.", + "type": "integer" + }, + "message": { + "description": "The whole notice in words, for a host with no UI.", + "type": "string" + }, + "remaining": { + "description": "Searches left in that period.", + "type": "integer" + }, + "scope": { + "description": "Which allowance this counts: the daily one or the monthly one. Both exist with or without an account, so `signed_in` does not tell them apart.", + "enum": [ + "day", + "month" + ], + "type": "string" + }, + "signed_in": { + "description": "Whether the caller has an account. False is the anonymous allowance.", + "type": "boolean" + }, + "state": { + "description": "`warning` while there is room left, `exhausted` once there is none.", + "enum": [ + "warning", + "exhausted" + ], + "type": "string" + }, + "used": { + "description": "Searches spent in that period.", + "type": "integer" + } + }, + "type": "object" +} - changed
Output schema / properties / data / items / descriptionPrevious value: -"A photo result. Fields returned can be narrowed with the `fields` parameter and may depend on your plan."New value: +"One photograph of this answer." - changed
Output schema / properties / data / items / properties / attribution / descriptionPrevious value: -"Ready-to-display credit for the photographer/source."New value: +"The credit line to display, already written." - removed
Output schema / properties / data / items / properties / attribution / properties / htmlRemoved value: -{ - "description": "HTML attribution snippet.", - "type": "string" -} - removed
Output schema / properties / data / items / properties / blur_hashRemoved value: -{ - "description": "BlurHash placeholder string.", - "type": [ - "string", - "null" - ] -} - removed
Output schema / properties / data / items / properties / color_hexRemoved value: -{ - "description": "Dominant color hex code.", - "type": "string" -} - removed
Output schema / properties / data / items / properties / color_nameRemoved value: -{ - "description": "Dominant color name.", - "type": "string" -} - removed
Output schema / properties / data / items / properties / descriptionRemoved value: -{ - "description": "AI-generated caption.", - "type": [ - "string", - "null" - ] -} - removed
Output schema / properties / data / items / properties / image_urlRemoved value: -{ - "description": "Canonical source image URL.", - "format": "uri", - "type": "string" -} - added
Output schema / properties / data / items / properties / orientation / descriptionAdded value: +"The shape of this photograph — `landscape`, `portrait` or `square`, the values `explicit_orientation_filter` takes." - removed
Output schema / properties / data / items / properties / photographer_urlRemoved value: -{ - "format": "uri", - "type": [ - "string", - "null" - ] -} - removed
Output schema / properties / data / items / properties / photographer_usernameRemoved value: -{ - "type": "string" -} - added
Output schema / properties / data / items / properties / rankAdded value: +{ + "description": "This photograph's place in this answer, from 1. A person may name a result by position (“the second one”); the tools take that result's `photo_id`, not its rank.", + "type": "integer" +} - removed
Output schema / properties / data / items / properties / relevance_scoreRemoved value: -{ - "description": "Match score 0–1 (higher is better). Only on search results.", - "type": [ - "number", - "null" - ] -} - removed
Output schema / properties / data / items / properties / source_descriptionRemoved value: -{ - "type": [ - "string", - "null" - ] -} - changed
Output schema / properties / data / items / properties / source_image_url / descriptionPrevious value: -"URL of the photo's page on the provider."New value: +"The photograph's page on the library it came from — where to send someone who wants the source." - removed
Output schema / properties / data / items / properties / uploaded_onRemoved value: -{ - "description": "Publication date (YYYY-MM-DD).", - "type": [ - "string", - "null" - ] -} - changed
Output schema / properties / data / items / properties / urls / descriptionPrevious value: -"Ready-to-use image links in five sizes."New value: +"The photograph's image file, 1280 pixels wide, for a page, a document or a download. `urls` carries this one variant and no other." - removed
Output schema / properties / data / items / properties / urls / properties / fullRemoved value: -{ - "format": "uri", - "type": "string" -} - removed
Output schema / properties / data / items / properties / urls / properties / largeRemoved value: -{ - "format": "uri", - "type": "string" -} - removed
Output schema / properties / data / items / properties / urls / properties / smallRemoved value: -{ - "format": "uri", - "type": "string" -} - removed
Output schema / properties / data / items / properties / urls / properties / thumbRemoved value: -{ - "format": "uri", - "type": "string" -} - changed
Output schema / properties / error / anyOfPrevious value: -[ - { - "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" - } -]New value: +[ + { + "properties": { + "code": { + "description": "Machine-readable error code (e.g. `MISSING_PARAMS`, `PHOTO_NOT_FOUND`).", + "type": "string" + }, + "message": { + "description": "Human-readable error message.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + { + "type": "null" + } +] - removed
Output schema / properties / metaRemoved value: -{ - "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" -} - added
Output schema / properties / noticeAdded value: +{ + "description": "Why this answer is empty, when it is. A plan limit was reached: the allowance and when it returns. There is nothing to retry until then.", + "type": "string" +} - removed
Output schema / properties / paginationRemoved value: -{ - "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" - } - ] -}
- Changed
search_photos_by_image41 fields changed- removed
Input schema / properties / after_dateRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Only return photos published on or after this date, formatted YYYY-MM-DD." -} - removed
Input schema / properties / color_nameRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "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." -} - removed
Input schema / properties / cursorRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "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." -} - added
Input schema / properties / english_search_sentenceAdded value: +{ + "anyOf": [ + { + "maxLength": 250, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional, and usable with any reference. Send the words that say what the user wants from the reference: with a `photo_id`, the words that photograph was found under, so the results stay on the subject they asked for; with an image, what they want changed or kept from it (“like this but at night”). The reference stays the main signal and these words adjust it. With an image, send the change alone (“at night”) rather than the whole scene rewritten, which would outweigh the picture instead of adjusting it; with a `photo_id`, the full sentence that photograph was found under is what to send. In English, like the sentence of a text search. The words a reference photograph was found under are the best ones. When it is unclear whether they want the same subject or simply the same look, send the words: staying on the subject is the safer default. Omit them only when they plainly want photographs that look like the picture itself." +} - added
Input schema / properties / explicit_orientation_filterAdded value: +{ + "anyOf": [ + { + "items": { + "enum": [ + "landscape", + "portrait", + "square" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Omit this parameter unless the user explicitly asks for a photo shape or orientation in their own words, or names a format whose shape is part of its definition — a vertical Short, a banner, a square post, a phone wallpaper.\n\nThis is a hard filter, not a preference: it removes photos with other shapes before ranking, so using a shape the user did not request can exclude the best matches.\n\nNever infer the shape from the reference image the user gave — its shape is a property of the picture they had, not a constraint on the ones they want — nor from the subject, the composition, or a purpose that fixes no shape (“a photo for my blog post”, “something for my landing page”). If you are choosing a value rather than repeating one explicitly requested by the user, omit it.\n\nAllowed values: `landscape`, `portrait`, `square`. Multiple values are allowed: two shapes return more than one alone, though any filter still returns less than none. For example, “anything but portrait” means `['landscape', 'square']`." +} - changed
Input schema / properties / image_base64 / descriptionPrevious 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."New value: +"Reference image as base64-encoded bytes, optionally as a data: URL. Use for programmatic clients that already hold the image data." - changed
Input schema / properties / image_file / descriptionPrevious 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`."New value: +"The user's uploaded image, as a host that passes uploads to tools provides it: the upload's `download_url` and `file_id`. A picture that is only visible in the conversation has neither." - changed
Input schema / properties / image_url / descriptionPrevious 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."New value: +"Public http(s) URL pointing directly to the reference image file, including a URL the user pasted in the conversation. For a photograph Pexafy returned, send its `photo_id` instead." - removed
Input schema / properties / license_typeRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "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." -} - removed
Input schema / properties / orientationRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Keep only photos with these shapes: landscape, portrait, square. Repeat the parameter to pass several." -} - added
Input schema / properties / photo_idAdded value: +{ + "anyOf": [ + { + "examples": [ + "019e1ecb-0039-7da6-b1ca-987ee4d337c0" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The photo_id of the Pexafy reference photo, copied from the result the user or assistant is referring to. It is a UUID such as `019e1ecb-0039-7da6-b1ca-987ee4d337c0`. Use it instead of an image when the reference is a Pexafy photo returned in an earlier search, and pass the words of that search in `english_search_sentence` if needed." +} - removed
Input schema / properties / photographerRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Only return photos from this photographer's exact username." -} - removed
Input schema / properties / qRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "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'." -} - removed
Input schema / properties / sourceRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Keep only photos from these providers: Unsplash, Pexels, Pixabay, Kaboompics, Burst, StockSnap, Picjumbo, Skitterphoto, NegativeSpace. Repeat the parameter to pass several." -} - removed
Input schema / properties / text_alphaRemoved value: -{ - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": null, - "description": "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`." -} - added
Output schema / properties / budgetAdded value: +{ + "description": "Present only when the caller is near the end of an allowance — the daily one without an account, the monthly one with. What is left of it, and, for a caller with no account, the one sentence that says what lifts the limit. Also carried by a refusal, where it describes the wall itself.", + "properties": { + "limit": { + "description": "Searches allowed in that period.", + "type": "integer" + }, + "message": { + "description": "The whole notice in words, for a host with no UI.", + "type": "string" + }, + "remaining": { + "description": "Searches left in that period.", + "type": "integer" + }, + "scope": { + "description": "Which allowance this counts: the daily one or the monthly one. Both exist with or without an account, so `signed_in` does not tell them apart.", + "enum": [ + "day", + "month" + ], + "type": "string" + }, + "signed_in": { + "description": "Whether the caller has an account. False is the anonymous allowance.", + "type": "boolean" + }, + "state": { + "description": "`warning` while there is room left, `exhausted` once there is none.", + "enum": [ + "warning", + "exhausted" + ], + "type": "string" + }, + "used": { + "description": "Searches spent in that period.", + "type": "integer" + } + }, + "type": "object" +} - changed
Output schema / properties / data / items / descriptionPrevious value: -"A photo result. Fields returned can be narrowed with the `fields` parameter and may depend on your plan."New value: +"One photograph of this answer." - changed
Output schema / properties / data / items / properties / attribution / descriptionPrevious value: -"Ready-to-display credit for the photographer/source."New value: +"The credit line to display, already written." - removed
Output schema / properties / data / items / properties / attribution / properties / htmlRemoved value: -{ - "description": "HTML attribution snippet.", - "type": "string" -} - removed
Output schema / properties / data / items / properties / blur_hashRemoved value: -{ - "description": "BlurHash placeholder string.", - "type": [ - "string", - "null" - ] -} - removed
Output schema / properties / data / items / properties / color_hexRemoved value: -{ - "description": "Dominant color hex code.", - "type": "string" -} - removed
Output schema / properties / data / items / properties / color_nameRemoved value: -{ - "description": "Dominant color name.", - "type": "string" -} - removed
Output schema / properties / data / items / properties / descriptionRemoved value: -{ - "description": "AI-generated caption.", - "type": [ - "string", - "null" - ] -} - removed
Output schema / properties / data / items / properties / image_urlRemoved value: -{ - "description": "Canonical source image URL.", - "format": "uri", - "type": "string" -} - added
Output schema / properties / data / items / properties / orientation / descriptionAdded value: +"The shape of this photograph — `landscape`, `portrait` or `square`, the values `explicit_orientation_filter` takes." - removed
Output schema / properties / data / items / properties / photographer_urlRemoved value: -{ - "format": "uri", - "type": [ - "string", - "null" - ] -} - removed
Output schema / properties / data / items / properties / photographer_usernameRemoved value: -{ - "type": "string" -} - added
Output schema / properties / data / items / properties / rankAdded value: +{ + "description": "This photograph's place in this answer, from 1. A person may name a result by position (“the second one”); the tools take that result's `photo_id`, not its rank.", + "type": "integer" +} - removed
Output schema / properties / data / items / properties / relevance_scoreRemoved value: -{ - "description": "Match score 0–1 (higher is better). Only on search results.", - "type": [ - "number", - "null" - ] -} - removed
Output schema / properties / data / items / properties / source_descriptionRemoved value: -{ - "type": [ - "string", - "null" - ] -} - changed
Output schema / properties / data / items / properties / source_image_url / descriptionPrevious value: -"URL of the photo's page on the provider."New value: +"The photograph's page on the library it came from — where to send someone who wants the source." - removed
Output schema / properties / data / items / properties / uploaded_onRemoved value: -{ - "description": "Publication date (YYYY-MM-DD).", - "type": [ - "string", - "null" - ] -} - changed
Output schema / properties / data / items / properties / urls / descriptionPrevious value: -"Ready-to-use image links in five sizes."New value: +"The photograph's image file, 1280 pixels wide, for a page, a document or a download. `urls` carries this one variant and no other." - removed
Output schema / properties / data / items / properties / urls / properties / fullRemoved value: -{ - "format": "uri", - "type": "string" -} - removed
Output schema / properties / data / items / properties / urls / properties / largeRemoved value: -{ - "format": "uri", - "type": "string" -} - removed
Output schema / properties / data / items / properties / urls / properties / smallRemoved value: -{ - "format": "uri", - "type": "string" -} - removed
Output schema / properties / data / items / properties / urls / properties / thumbRemoved value: -{ - "format": "uri", - "type": "string" -} - changed
Output schema / properties / error / anyOfPrevious value: -[ - { - "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" - } -]New value: +[ + { + "properties": { + "code": { + "description": "Machine-readable error code (e.g. `MISSING_PARAMS`, `PHOTO_NOT_FOUND`).", + "type": "string" + }, + "message": { + "description": "Human-readable error message.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + { + "type": "null" + } +] - removed
Output schema / properties / metaRemoved value: -{ - "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" -} - added
Output schema / properties / noticeAdded value: +{ + "description": "Why this answer is empty, when it is. A plan limit was reached: the allowance and when it returns. There is nothing to retry until then.", + "type": "string" +} - removed
Output schema / properties / paginationRemoved value: -{ - "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" - } - ] -}
1 tool update
v0.4.9- Changed
search_photos_by_image19 fields changed- added
Input schema / properties / after_date / descriptionAdded value: +"Only return photos published on or after this date, formatted YYYY-MM-DD." - added
Input schema / properties / color_name / descriptionAdded 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." - added
Input schema / properties / cursor / descriptionAdded 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." - added
Input schema / properties / image_base64 / descriptionAdded 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." - added
Input schema / properties / image_file / additionalPropertiesAdded value: +false - removed
Input schema / properties / image_file / anyOfRemoved value: -[ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "null" - } -] - removed
Input schema / properties / image_file / defaultRemoved value: -null - added
Input schema / properties / image_file / descriptionAdded 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`." - added
Input schema / properties / image_file / propertiesAdded value: +{ + "download_url": { + "type": "string" + }, + "file_id": { + "type": "string" + }, + "file_name": { + "type": "string" + }, + "mime_type": { + "type": "string" + } +} - added
Input schema / properties / image_file / requiredAdded value: +[ + "download_url", + "file_id" +] - added
Input schema / properties / image_file / typeAdded value: +"object" - added
Input schema / properties / image_url / descriptionAdded 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." - added
Input schema / properties / license_type / descriptionAdded 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." - added
Input schema / properties / orientation / descriptionAdded value: +"Keep only photos with these shapes: landscape, portrait, square. Repeat the parameter to pass several." - added
Input schema / properties / photographer / descriptionAdded value: +"Only return photos from this photographer's exact username." - added
Input schema / properties / q / descriptionAdded 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'." - added
Input schema / properties / source / descriptionAdded value: +"Keep only photos from these providers: Unsplash, Pexels, Pixabay, Kaboompics, Burst, StockSnap, Picjumbo, Skitterphoto, NegativeSpace. Repeat the parameter to pass several." - added
Input schema / properties / text_alpha / descriptionAdded 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`." - changed
Output 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 tool updates
v0.4.0- Added
get_similar_photos - Removed
photo_similar
3 tool updates
v0.2.0- First observed
photo_similar - First observed
search_photos - First observed
search_photos_by_image
TDQS
Scored across 3 tools
The three tools have clearly distinct purposes: text-described photo search, image-reference search, and account connection. The two search tools could superficially be confused, but the descriptions sharply delineate when to use each (words vs. a concrete reference image).
All names follow a consistent snake_case verb_noun pattern (search_photos, search_photos_by_image, connect_account). The shared search_photos prefix is predictable and reinforces the relationship between the two search tools.
Three tools is slightly lean but well-scoped for a photo search service, with each tool earning its place. No filler tools are present, though a small set like this has little redundancy to mask gaps.
For a stock photo search domain, text search, image-reference search, and account connection cover the core lifecycle. Minor gaps exist (e.g., no dedicated photo-detail or collection retrieval), but results already carry photo_id, licence, and credit info, so core workflows are unblocked.
Maintenance
Related MCP Connectors
MCP server for Qwen Image 3 AI image generation
Hosted MCP server for AI photo editing: nothing to install, no desktop photo editor needed.
MCP server for Wan AI video generation
MCP server for Midjourney AI image generation and editing
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceProvides access to the Unsplash API, enabling AI assistants to search and retrieve high-quality photos, browse collections, view photographer profiles, and get photo statistics with advanced filtering options.87 npmMIT
- AlicenseBqualityDmaintenanceThis 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.12Apache 2.0
- FlicenseBqualityDmaintenanceA Model Context Protocol server that provides access to the Pexels API for searching and retrieving photos, videos, and collections.8138 PyPI25-
- FlicenseAqualityDmaintenanceAn 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.21-