Picsha AI

Picsha AI MCP Server

Overview

Picsha AI ships an official Model Context Protocol (MCP) server. This allows your custom AI agents, assistants, and LLM workflows to directly interface with your Picsha instance.

By connecting to the Picsha MCP Server, your AI agents can instantly search, retrieve, and process your organization's digital assets without you having to build custom API wrappers or prompt definitions.

Connection Details

Connect through the published @picsha-ai/mcp-server package. It runs locally over stdio transport (the model every MCP client supports natively — Claude Desktop, Cursor, custom agents), authenticates with your standard Picsha API key, and talks to the Picsha REST API under the hood.

PICSHA_API_KEY="<YOUR_PICSHA_API_KEY>" npx -y @picsha-ai/mcp-server

Don't have an API key? Generate one from your Picsha Admin Dashboard.

Hosted Remote MCP (Streamable HTTP)

Web and cloud agents that cannot spawn a local subprocess — hosted assistants, cloud-deployed agent frameworks, workflow platforms — can connect directly to Picsha's hosted MCP endpoint instead:

  • Endpoint: https://api.picsha.ai/v1/mcp (MCP Streamable HTTP transport)
  • Authentication: OAuth 2.0 (sign in with your Picsha account — recommended for AI assistants like Claude) or Authorization: Bearer <YOUR_PICSHA_API_KEY> for programmatic clients
  • Rate limits: requests are limited per credential (default 120 requests/minute)

Connect from Claude (OAuth — no API key needed)

The hosted endpoint is a full OAuth 2.0 protected resource: it supports standards-based discovery, dynamic client registration, and PKCE. In Claude (claude.ai, Desktop, or mobile):

  1. Go to Settings → Connectors → Add custom connector.
  2. Enter https://api.picsha.ai/v1/mcp.
  3. You'll be redirected to sign in to your Picsha account and approve access. That's it — the Picsha tools appear in your chats, and the session is automatically scoped to your Picsha organization.

Any other MCP client that implements the MCP authorization specification can connect the same way; discovery metadata is served at https://api.picsha.ai/.well-known/oauth-protected-resource/v1/mcp.

Connect with an API key (programmatic clients)

For CLIs, agent frameworks, and server-to-server integrations, authenticate with a Picsha API key instead:

  • Header: Authorization: Bearer <YOUR_PICSHA_API_KEY> — the same API key as the REST API
  • Multi-tenancy: send an x-external-user-id: <end-user-id> header to scope the session to a single end user (see Multi-Tenancy & User Isolation below). This header applies to API-key sessions only — OAuth sessions are automatically scoped to the signed-in user and ignore it.

The endpoint is stateless — every JSON-RPC message is an individual POST — so it needs no sticky sessions and works with any Streamable HTTP MCP client. For example, connecting Claude Code:

claude mcp add --transport http picsha-ai https://api.picsha.ai/v1/mcp --header "Authorization: Bearer <YOUR_PICSHA_API_KEY>"

Or a remote server entry in Cursor's .cursor/mcp.json:

{
  "mcpServers": {
    "picsha-ai": {
      "url": "https://api.picsha.ai/v1/mcp",
      "headers": {
        "Authorization": "Bearer <YOUR_PICSHA_API_KEY>"
      }
    }
  }
}

[!NOTE] The hosted endpoint exposes the same core toolset as the local package, with transport-appropriate substitutions for uploading and rendering. It also adds paging and filters to search and listing, and tools for similar assets, collections and moderation — see Hosted Endpoint Tools at the end of this page. Use the local stdio package when your agent should upload files from the local filesystem in a single step or render image previews inline in a chat UI.

Multi-Tenancy & User Isolation (For B2B2C Apps)

If you are building an AI agent that serves multiple users (for example, a Slack bot or a customer-facing SaaS application), you must ensure the agent only accesses assets belonging to the specific user making the request.

Use the hosted endpoint for this. It supports strict multi-tenant isolation at the transport layer: connect to https://api.picsha.ai/v1/mcp with an Organization API key and send x-external-user-id: <end-user-id> on your MCP requests. You do not need to build mapping logic or modify your LLM prompts.

When the header is present:

  1. Isolated Sandboxing: The Picsha backend applies OpenSearch and Postgres filters so the AI agent only searches, views, or modifies files owned by that specific user, and files what it uploads under that user.
  2. Invisible Enforcement: The LLM tools functionally operate the same — the scoping happens at the transport layer, not in your prompts.

If the header is omitted, the session operates with the full organization scope of the API key. That is appropriate for internal tools and org-wide automations — but for customer-facing multi-user deployments, always send it so one user's agent can never touch another user's assets. Hosted OAuth sessions don't use this header: they are automatically and non-overridably scoped to the signed-in Picsha user.

The local @picsha-ai/mcp-server package does not confine a session. You can start it with an end user's id:

PICSHA_API_KEY="..." PICSHA_EXTERNAL_USER_ID="user_123" npx @picsha-ai/mcp-server

It then sends x-external-user-id on the REST calls it makes, which records that user as the owner of what it uploads. Its search, list and asset tools still reach the whole Organization, because the REST API does not narrow reads by the header. Use the local package for single-user and internal agents, and the hosted endpoint when one user's agent must not see another user's assets.

Personal API keys

A personal API key — one that does not belong to an organization — is always scoped to its owner's own assets, the same as GET /v1/assets and POST /v1/search. This holds on the hosted endpoint and for the local @picsha-ai/mcp-server alike.

The x-external-user-id header is ignored for personal keys, so setting PICSHA_EXTERNAL_USER_ID has no effect with one: uploads are filed under the key's owner, and every tool reaches only the owner's assets. To isolate your own end users from each other, use an API key that belongs to an organization with the hosted endpoint, as described above.

Collections in an isolated session

A session scoped to a single end user sees only the collections that session's user created through the hosted tools. It does not see collections shared across the organization. Sessions with full organization scope see every collection in the organization.

Integrating with AI Agents

Using the MCP TypeScript / Python SDKs

If you are building your own AI agent (for example, using LangChain, defining custom LLM tool chains, or a custom Node/Python application), you can connect to the Picsha MCP server using the official MCP client SDKs. The client spawns the server as a subprocess over stdio:

TypeScript Example:

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

const transport = new StdioClientTransport({
  command: "npx",
  args: ["-y", "@picsha-ai/mcp-server"],
  env: {
    PICSHA_API_KEY: process.env.PICSHA_API_KEY
  }
});

const mcpClient = new Client(
  { name: "my-ai-agent", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

await mcpClient.connect(transport);

// View available Picsha tools for your LLM
const tools = await mcpClient.request({ method: "tools/list" });
console.log(tools);

Agent Framework Recipes

Every major agent framework can now consume MCP servers natively, so there is no Picsha-specific package to install — you point the framework's MCP adapter at @picsha-ai/mcp-server and the full toolset appears as regular framework tools. The recipes below cover the most common Python frameworks; multi-tenancy works identically in all of them (add PICSHA_EXTERNAL_USER_ID to the env block).

LangChain / LangGraph

# pip install langchain-mcp-adapters langgraph "langchain[anthropic]"
import asyncio, os
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent

async def main():
    client = MultiServerMCPClient({
        "picsha": {
            "transport": "stdio",
            "command": "npx",
            "args": ["-y", "@picsha-ai/mcp-server"],
            "env": {"PICSHA_API_KEY": os.environ["PICSHA_API_KEY"]},
        }
    })
    tools = await client.get_tools()
    agent = create_react_agent("anthropic:claude-sonnet-5", tools)
    result = await agent.ainvoke({
        "messages": "Find photos of people wearing red hats and tag the top result 'campaign-hats'"
    })
    print(result["messages"][-1].content)

asyncio.run(main())

Building in TypeScript? The equivalent adapter is @langchain/mcp-adapters with the same server config.

LlamaIndex

# pip install llama-index llama-index-tools-mcp llama-index-llms-anthropic
import os
from llama_index.tools.mcp import BasicMCPClient, McpToolSpec
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.llms.anthropic import Anthropic

mcp_client = BasicMCPClient(
    "npx",
    args=["-y", "@picsha-ai/mcp-server"],
    env={"PICSHA_API_KEY": os.environ["PICSHA_API_KEY"]},
)
tools = await McpToolSpec(client=mcp_client).to_tool_list_async()

agent = FunctionAgent(tools=tools, llm=Anthropic(model="claude-sonnet-5"))
response = await agent.run("Summarize the most recently uploaded document")

CrewAI

# pip install crewai "crewai-tools[mcp]"
import os
from crewai import Agent
from crewai_tools import MCPServerAdapter
from mcp import StdioServerParameters

server_params = StdioServerParameters(
    command="npx",
    args=["-y", "@picsha-ai/mcp-server"],
    env={"PICSHA_API_KEY": os.environ["PICSHA_API_KEY"]},
)

with MCPServerAdapter(server_params) as picsha_tools:
    media_specialist = Agent(
        role="Media Specialist",
        goal="Search, organize, and transform the team's digital assets",
        backstory="Expert curator of the organization's Picsha AI asset library",
        tools=picsha_tools,
    )
    # Add media_specialist to any Crew alongside your other agents

Claude Desktop Integration

The easiest way to use Picsha in Claude Desktop (and claude.ai) is the hosted connector — Settings → Connectors → Add custom connector → https://api.picsha.ai/v1/mcp, then sign in with your Picsha account. No API key, no config file. See Connect from Claude above.

Alternatively, run the local stdio server when you specifically need its local-machine tools — uploading files straight from your filesystem (upload_asset) or rendering image previews inline in the chat (render_asset_preview):

  1. Open Claude Desktop.
  2. Go to Settings > Developer and click Edit Config.
  3. Add the following entry to your claude_desktop_config.json file:
{
  "mcpServers": {
    "picsha-ai": {
      "command": "npx",
      "args": ["-y", "@picsha-ai/mcp-server"],
      "env": {
        "PICSHA_API_KEY": "<YOUR_PICSHA_API_KEY>"
      }
    }
  }
}

Don't have an API key? Generate one from your Picsha Admin Dashboard.

  1. Save the file and restart Claude Desktop. You should now see the Picsha hammer icon 🔨 in your prompt bar, indicating the tools are successfully connected!

The Agentic Workflow (How to talk to Claude)

Now that Claude is connected, you can use natural language to search, generate, and organize your files.

Recommended Context Prompt To get the best results from Claude, start a new chat with the following context prompt. This ensures Claude knows exactly how to utilize the Picsha tools you've provided.

"You are my Picsha Media Assistant. You have direct access to my organization's Digital Asset Management library via MCP tools. When I ask for images, use search_assets with mode: \"ai\" to find them semantically. When I ask for alterations (like background removal or MIMI edits), use render_asset_preview to perform the transformation and show me the resulting image preview inline while also providing the final cdnUrl. Keep my workspace organized by using create_dam_group and link_assets for variations."

Example Prompts to Try

1. Semantic Search & Discovery

  • You: "Find me photos of people wearing red hats enjoying the outdoors, then summarize what's happening in the top 3 results."
  • What Claude Does: Calls search_assets(query: "people wearing red hats outdoors", mode: "ai"), reads the rich AI descriptions attached to the results, and intelligently summarizes them.

2. On-the-fly Image Manipulation

  • You: "Grab that sunset photo we just uploaded, remove the background, and crop it to a 16:9 aspect ratio."
  • What Claude Does: First searches to find the sunset photo ID. Then calls render_asset_preview(id: "550e8400-e29b-41d4-a716-446655440000", params: "bg_rem=true&ar=16:9") to dynamically generate the asset. Claude visually returns the finished image directly into the chat interface for your review, and provides the finalized 4K delivery CDN link.

3. Intelligent Organization

  • You: "Gather all photos related to the Q3 Marketing Campaign and put them into a new folder."
  • What Claude Does: Executes a semantic search for related campaign assets. Calls create_dam_group(name: "Q3 Campaign"), adds the retrieved IDs to the group, and confirms the organization structure.

4. Re-analysis & Summarization

  • You: "Re-run the AI analysis on that blurry document, then give me a summary of it."
  • What Claude Does: Calls reanalyze_asset on the document to re-trigger the ingestion pipeline, checks back with get_asset for the refreshed analysis, and reads the resulting text summary with summarize_asset.

5. Safe Cleanup with the Trash

  • You: "Clean up the duplicate screenshots from last week's testing."
  • What Claude Does: Searches for the assets and calls delete_asset on each — which moves them to the Trash rather than destroying them. They stay recoverable for 30 days (via restore_asset or the dashboard), so a misunderstood instruction never causes permanent data loss.

Cursor Integration

Add the server to .cursor/mcp.json in your project root (or ~/.cursor/mcp.json to make it available in every project):

{
  "mcpServers": {
    "picsha-ai": {
      "command": "npx",
      "args": ["-y", "@picsha-ai/mcp-server"],
      "env": {
        "PICSHA_API_KEY": "<YOUR_PICSHA_API_KEY>"
      }
    }
  }
}

Cursor lists the Picsha tools under Settings → MCP once the file is saved. In Agent mode, just ask in natural language — "find our hero images with transparent backgrounds and crop them to 1:1" — and Cursor will call the tools directly.

VS Code Integration

VS Code (1.99+) supports MCP servers in agent mode via .vscode/mcp.json. The inputs block below prompts for your API key the first time the server starts and stores it securely, so the key never lives in a file you might commit:

{
  "inputs": [
    {
      "type": "promptString",
      "id": "picsha-api-key",
      "description": "Picsha AI API Key",
      "password": true
    }
  ],
  "servers": {
    "picsha-ai": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@picsha-ai/mcp-server"],
      "env": {
        "PICSHA_API_KEY": "${input:picsha-api-key}"
      }
    }
  }
}

Open Copilot Chat in Agent mode and the Picsha tools appear in the tools picker.

Available Tools

The published @picsha-ai/mcp-server package (v2.3.x) exposes the following tools:

[!NOTE] The hosted Streamable HTTP endpoint (https://api.picsha.ai/v1/mcp — see Connection Details) exposes the same core toolset with substitutions for transport reasons: instead of upload_asset it offers get_presigned_upload_url and complete_upload (a remote server cannot read your local files, so the client uploads the file itself), instead of get_rendered_asset_url it offers generate_render_url, and it omits the chat-UI preview tools (render_asset_preview, poll_render). On the hosted endpoint search_assets and list_recent_assets also accept filters, sorting and paging, and there are additional tools for similar assets, collections and the moderation queue. All of these are documented under Hosted Endpoint Tools at the end of this page.

Every hosted tool also declares MCP tool annotations (readOnlyHint / destructiveHint), so clients like Claude can distinguish safe read-only operations from writes and apply the right permission prompts automatically.

1. search_assets

Search for assets in the Picsha AI platform. Natively supports semantic/vector search for natural language queries.

  • query (string, required): The search query to find assets.
  • mode (string, optional): "ai" (default) is hybrid semantic vector search using natural language (e.g., "people wearing red hats"). "standard" is simple tag/text matching.
  • threshold (number, optional): Minimum relevance score threshold (default: 0.6).
  • sort (string, optional): "relevance" (default), "newest" or "oldest".

The local package returns the top 5 matches. On the hosted endpoint this tool pages through every match and accepts filters; its mode defaults to "standard" there. See Hosted Endpoint Tools.

2. get_asset

Retrieve detailed metadata and AI analysis results for a specific asset.

  • id (string, required): The unique ID of the asset to fetch metadata for.

3. list_recent_assets

Returns the most recently uploaded assets, newest first. Assets in the Trash are not listed.

  • limit (number, default: 10): Number of assets to retrieve. The hosted endpoint accepts 1–100.

On the hosted endpoint this tool also filters, sorts and pages. See Hosted Endpoint Tools.

4. reanalyze_asset

Re-runs the Picsha AI processing pipeline on an existing asset (face/object detection, tagging, summaries, embeddings).

  • id (string, required): The unique ID of the asset.

5. upload_asset

Uploads a local file directly to the Picsha platform. The tool fetches a pre-signed S3 URL and executes the PUT automatically, then triggers the asynchronous ingestion pipeline — so the asset is initially pending; use get_asset a few seconds later for the processed result.

  • filePath (string, required): Absolute path to the local file.
  • filename (string, optional): Original filename to associate; defaults to the file's basename.

6. trigger_url_ingest

Ingests a file from a public web URL. The Picsha ingest worker downloads the file to S3 and processes it automatically.

  • url (string, required): Public URL for the worker to download the asset from.
  • filename (string, optional): Explicit filename to save.
  • config (object, optional): Processing configuration (e.g. { auto_summarize: true }).

7. get_rendered_asset_url

Generates a delivery URL for an asset with applied transformations or AI overrides — immediate access to Picsha's visual manipulation engine without duplicating the underlying asset.

  • id (string, required): The unique ID of the asset.
  • params (string, optional): A query string of transformation parameters. Supports standard parameters (e.g. w, h, ar, fmt, forced downloads via download=true) and generative AI parameters (e.g. bg_rem=true, mimi=remove person and add a sunset scene, mimi_mode=lite, upscale=4k, mimi_bg=misty alpine lake).
  • When params includes generative parameters, the returned URL is automatically minted with a delivery signature (?sig=) so it is fetchable without authentication — anonymous unsigned generative URLs are rejected with 401. Always obtain generative URLs from this tool (or sign-delivery) rather than hand-constructing them.

8. update_asset

Allows agents to act as automated curators by updating asset metadata and tags.

  • id (string, required): The unique ID of the asset.
  • tags (array, optional): Array of strings to append as tags. To remove tags, prefix the string with a hyphen (e.g. ["-old_tag", "new_tag"]).
  • metadata (object, optional): Custom key-value dictionary to attach to the asset.

9. delete_asset

Moves an asset into a 30-day Trash state (soft delete). The asset immediately disappears from search results and delivery endpoints (cached CDN copies are evicted), but remains restorable via restore_asset or the dashboard until its purge date. This fail-safe protects against prompt injection or misunderstood instructions causing permanent data loss.

  • id (string, required): The unique ID of the asset.
  • force (boolean, optional): If true, skips the Trash and permanently deletes immediately (database, search indexes, and storage). Agents should pass this only when the user explicitly asks for permanent deletion.

10. restore_asset

Restores a trashed asset to its previous state, making it deliverable and searchable again. No re-processing is needed — the asset returns exactly as it was.

  • id (string, required): The unique ID of the trashed asset.

11. moderate_asset

Allows specialized AI agents to handle moderation workflows by approving or rejecting assets that are held for review. Only an asset whose status is pending_moderation can be moderated; any other status returns an error. Approval sets the asset's status to completed; rejection sets it to rejected (blocking delivery).

  • id (string, required): The unique ID of the asset.
  • action (string, required): The moderation action. Must be "approve" or "reject".

12. create_dam_group

Creates a collection or folder to structurally organize assets.

  • name (string, required): The name of the collection/folder.
  • description (string, optional): A description for the group.
  • assetIds (string[], optional, hosted endpoint only): Existing assets to place in the group. An asset has one collection, so adding it moves it out of any other. The response lists addedAssetIds and notFoundAssetIds.

13. link_assets

Explicitly defines a relationship between two assets, useful for linking AI-generated variants to their originals.

  • sourceId (string, required): The asset ID of the parent or source asset.
  • targetId (string, required): The asset ID of the variation, derived, or correlated asset.
  • relationshipType (string, required): Description of the link (e.g., "REPLACES", "VARIATION", "CONVERTED").

14. summarize_asset

Returns the AI text summary produced for a document asset at ingest. If the asset has no summary yet, analysis is queued and the tool says so — check back with get_asset.

  • id (string, required): The unique ID of the asset.

15. escalate_to_support

Use this tool ONLY when you need to log a feature request, report a documentation gap, or escalate an issue to the engineering team. This will actually send an email to support@picsha.ai.

  • subject (string, required): The subject of the escalation email.
  • headline (string, required): A short, punchy headline for the email.
  • message (string, required): The full summary of the request, formatted nicely.

16. render_asset_preview

Generates a dynamic preview of an asset with applied transformations or AI overrides, returning the visual image bytes natively to the agent. Non-blocking: if a cold generation takes too long, it returns pending with a jobId for poll_render.

  • id (string, required): The unique ID of the asset.
  • params (string, optional): A query string of transformation parameters (e.g. bg_rem=true&mimi=sunset, or mimi=sunset&mimi_mode=lite for a faster 1K preview render).
  • maxDim (number, optional): The maximum dimension in pixels to cap the preview at (default: 768).
  • timeoutMs (number, optional): Max time to block waiting for cold generation.

17. poll_render

Retrieves the result of an asynchronous generation started by render_asset_preview when the initial request timed out and returned pending.

  • jobId (string, required): The async job ID returned by a pending render response.
  • timeoutMs (number, optional): Bounded wait to check for completion.

Hosted Endpoint Tools

This section covers what is different on the hosted endpoint (https://api.picsha.ai/v1/mcp):

  • Uploading: get_presigned_upload_url and complete_upload replace upload_asset.
  • Rendering: generate_render_url replaces get_rendered_asset_url.
  • Searching and listing: search_assets and list_recent_assets accept filters, sorting and paging, and find_similar_assets is added.
  • Collections: list_dam_groups, get_dam_group, add_assets_to_dam_group and remove_assets_from_dam_group are added.
  • Moderation: list_pending_moderation is added.

Result format

search_assets, list_recent_assets, find_similar_assets, get_dam_group and list_pending_moderation return assets in the same format.

Lists come back as an object with the results and the paging position:

{
  "results": [ ... ],
  "pagination": { "page": 1, "limit": 20, "total": 57 }
}

Request the next page with page while page * limit is less than total.

Each asset is a summary by default: id, originalName, mimeType, size, status, width, height, captureDate, createdAt, tags, description, labels, metadata (your custom metadata, without raw EXIF), matchScore and thumbnail_url. A summary is typically under 1 KB.

  • detail (string, optional): "summary" (default) or "full". "full" returns every stored field, including raw EXIF and face geometry. That is about 25 KB per asset, so keep limit small with it. For one asset, get_asset always returns every field.

Uploading a file

A hosted server cannot read files from your machine, so an upload takes three steps:

  1. Call get_presigned_upload_url to create a pending asset and receive an upload URL.
  2. Send the file to that URL with an HTTP PUT, using the exact Content-Type you declared.
  3. Call complete_upload with the assetId to start processing.

Until complete_upload is called the asset stays in pending_upload status and is not processed, searchable or deliverable.

# Step 2: upload the file to the URL returned by get_presigned_upload_url
curl -X PUT -H "Content-Type: image/jpeg" --data-binary "@photo.jpg" "<uploadUrl>"

[!NOTE] Step 2 is an ordinary HTTP request made by the client, not an MCP tool call. Agents that can run commands or make HTTP requests (Claude Code, agent frameworks, your own backend) can do it. Chat assistants that cannot should use trigger_url_ingest with a public URL instead.

get_presigned_upload_url

Creates a pending asset and returns a short-lived URL for uploading its file directly to storage.

  • filename (string, required): Original filename (e.g. photo.jpg).
  • contentType (string, required): MIME type of the file (e.g. image/jpeg).

Returns assetId, uploadUrl, method (PUT), the headers to send with the upload, and expiresInSeconds (3600).

complete_upload

Finishes an upload started with get_presigned_upload_url. It verifies that the file reached storage, records its size, and queues the asset for AI processing. Follow the asset's status with get_asset.

  • id (string, required): The assetId returned by get_presigned_upload_url.
  • config (object, optional): Processing configuration (e.g. { auto_summarize: true, auto_tag: true }).

Calling it before the file has been uploaded returns an error and leaves the asset in pending_upload. Calling it again after it has succeeded changes nothing.

Rendering

generate_render_url

Builds a CDN delivery URL for an asset with transformation parameters. It does not modify the asset.

  • id (string, required): The unique ID of the asset.
  • transformations (object, required): Transformation parameters as key-value pairs (e.g. { "w": "800", "h": "600", "bg_rem": "true" }).

URLs that include generative parameters are signed automatically, the same as get_rendered_asset_url.

Searching and listing

search_assets

Searches the asset library with the same filters, sorting and paging as POST /v1/search.

  • query (string, required): What to find. May be empty when filters alone select the assets.
  • mode (string, optional): "standard" (default) matches text and tags. "ai" is hybrid semantic search and understands natural language, including dates and places.
  • threshold (number, optional): Minimum relevance score for "ai" matches, 0–1. Defaults to the server's setting (0.45).
  • limit (number, default: 20): Results per page, 1–50.
  • page (number, default: 1): Page number.
  • sort (string, optional): "relevance" (default), "added-desc", "added-asc", "created-desc", "created-asc", "name-asc" or "name-desc".
  • filters (object, optional): Structured filters, all of which must match: addedAfter, addedBefore, capturedAfter, capturedBefore, face, object, place, ocr, type, style, minRating, metadata, metadataField / metadataValue, and anyOf for alternative filter blocks. These are the Advanced Filters described in the Search docs.
  • timezone (string, optional): IANA zone (e.g. "America/New_York") that anchors "today" and "this week" to the user's day.
  • assetIds (string[], optional): Only search within these assets.
  • excludeAssetIds (string[], optional): Assets to leave out of the results.
  • facets (object[], optional): Distinct values with counts over the matching assets, e.g. [{ "field": "tags" }]. Fields: faces, labels, places, tags, mimeType, cameraMake, cameraModel. The response then carries a facets object.
  • detail (string, optional): See Result format.
{
  "query": "",
  "filters": { "type": "image", "capturedAfter": "2026-01-01", "minRating": 4 },
  "sort": "created-desc",
  "limit": 20,
  "page": 2
}

list_recent_assets

Lists assets, newest first unless sort says otherwise, with the same filters and paging as GET /v1/assets.

  • limit (number, default: 10): Assets per page, 1–100.
  • page (number, default: 1): Page number.
  • sort (string, optional): "added-desc" (default), "added-asc", "created-desc", "created-asc", "name-asc" or "name-desc".
  • type (string, optional): MIME type prefix, e.g. "image", "video" or "application/pdf".
  • tag (string, optional): Only assets carrying this tag.
  • search (string, optional): Only assets whose original filename contains this text.
  • status (string, optional): Only assets in this status, e.g. "completed" or "pending_upload". "trashed" lists the Trash, which is hidden otherwise.
  • albumId (string, optional): Only assets in this collection, by its id or name.
  • metadata (object, optional): Exact matches on custom metadata keys, e.g. { "asset_status": "Retired" }. Every key must match. A list of values for a key matches any of them.
  • anyOf (object[], optional): Alternative { "metadata": { ... } } blocks. An asset matches when it satisfies at least one.
  • detail (string, optional): See Result format.

find_similar_assets

Finds assets that look like a given asset, most similar first. The asset itself and trashed assets are never returned.

  • id (string, required): The asset to compare against.
  • limit (number, default: 12): How many matches to return, 1–50.
  • minScore (number, optional): Drop matches scoring below this, 0–1. When omitted, the nearest limit matches are returned whatever they score.
  • filters (object, optional): Structured filters the matches must satisfy, the same as search_assets.
  • excludeAssetIds (string[], optional): Assets never returned as matches.
  • detail (string, optional): See Result format.

Returns { assetId, results, total }. When the response carries "reason": "no-embedding", the asset has not been vectorized yet; run reanalyze_asset on it and try again.

Collections

A collection is a folder, group or album. An asset belongs to one collection at a time. Each collection has a kind:

  • collection: made by a person or an agent, for example with create_dam_group.
  • session: made automatically for one upload session.
  • unregistered: an album id that assets carry but that was never created as a collection, typically an album that came from another system. It can be listed, opened and added to like any other.

list_dam_groups

Lists collections with the number of assets in each.

  • kind (string, optional): "all" (default), "collection", "session" or "unregistered".
  • search (string, optional): Only collections whose name contains this text.
  • limit (number, default: 50): Collections per page, 1–200.
  • page (number, default: 1): Page number.

Each result has id, name, kind, assetCount, and where available description and createdAt.

get_dam_group

Returns one collection and a page of the assets in it.

  • id (string, required): The collection's id or exact name.
  • limit (number, default: 20): Assets per page, 1–100.
  • page (number, default: 1): Page number.
  • sort (string, optional): Asset order. Defaults to newest upload first.
  • detail (string, optional): See Result format.

Returns { collection, assets: { results, pagination } }.

add_assets_to_dam_group

Puts existing assets in a collection. An asset has one collection, so adding it moves it out of any other.

  • groupId (string, required): The collection's id or exact name. The collection must already exist; create one with create_dam_group.
  • assetIds (string[], required): The assets to add, 1–100.

Returns addedAssetIds and notFoundAssetIds.

remove_assets_from_dam_group

Takes assets out of a collection. The assets themselves are not deleted.

  • groupId (string, required): The collection's id or exact name.
  • assetIds (string[], required): The assets to remove, 1–100.

Returns removedAssetIds, notInGroupAssetIds (assets that were not in this collection and were left alone) and notFoundAssetIds.

Moderation

list_pending_moderation

Lists the assets held for manual review (status pending_moderation), newest first. Resolve each one with moderate_asset.

  • limit (number, default: 20): Assets per page, 1–100.
  • page (number, default: 1): Page number.

Each result is an asset summary plus moderationLabels: the labels that flagged it, each with name, confidence and, where there is one, parent.

An asset is held for review only when it was ingested with content_moderation enabled and a label scored 80 or higher.