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: 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 (same semantics as PICSHA_EXTERNAL_USER_ID below)
  • Rate limits: requests are limited per API key (default 120 requests/minute)

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 two transport-appropriate substitutions — see Available Tools. Use the local stdio package when your agent should upload files from the local filesystem 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.

Picsha AI natively supports strict multi-tenant isolation at the transport layer. You do not need to build complex mapping logic or modify your LLM prompts. Instead, you simply start the MCP Server session with the PICSHA_EXTERNAL_USER_ID environment variable.

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

(Under the hood, the MCP server forwards this value as the x-external-user-id header on every Picsha API request it makes. If you connect to the hosted Streamable HTTP endpoint instead of the local package, send the x-external-user-id header directly on your MCP requests — the isolation semantics are identical.)

When this value is present:

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

If PICSHA_EXTERNAL_USER_ID 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 set the external user ID so one user's agent can never touch another user's assets.

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

Claude Desktop runs local MCP servers over stdio transport — exactly how @picsha-ai/mcp-server works, so no bridge or extra configuration is needed.

  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 uses summarize_asset to produce an on-demand text summary.

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.2.1+) 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 two substitutions for transport reasons: instead of upload_asset it offers get_presigned_upload_url(filename, contentType) (returning a short-lived S3 PUT URL, since a remote server cannot read your local files), instead of get_rendered_asset_url it offers generate_render_url(id, transformations), and it omits the chat-UI preview tools (render_asset_preview, poll_render).

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): The search mode to use. Set to "ai" to enable hybrid semantic vector search using natural language (e.g., "people wearing red hats"). Defaults to "standard" for simple tag/text matching.
  • threshold (number, optional): Minimum relevance score threshold (default: 0.6).

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 in chronological order.

  • limit (number, default: 10): Number of assets to retrieve.

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 flagged assets. Approval sets the asset's status to active; 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.

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

Generates an on-demand AI text summary of a document 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.