# Tools Reference

> All 19 PicX MCP tools, their parameters, return shape, and whether they cost credits.

Every tool below is live on the production server and callable by any connected client with a valid `Authorization: Bearer pxsk_...` header. There is no per-workspace enable/disable policy — access is controlled entirely by the calling API key's scopes, exactly as it is for the REST API.

## Generation

### `picx_generate_image`

Generate a new image from a text prompt.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `prompt` | `string` | Yes | Text description of the image, max 4000 characters. |
| `model` | `string` | No | Model ID. Omit for the account default. |
| `size` | `"1K" \| "2K" \| "4K"` | No | Output resolution. Omit for model default. |
| `aspect_ratio` | `string` | No | e.g. `"16:9"`, `"1:1"`, `"9:16"`. Omit for square. |
| `n` | `number` | No | Number of images, 1-10. Each counts as a separate credit spend. |

**Costs credits.** Returns `{ images: [{ url, id, model, size, aspect_ratio }], credits_used, total_images }`, plus an MCP `resource_link` content block per image so a supporting client renders it inline instead of showing a bare URL.

### `picx_edit_image`

Edit one or more existing images with a natural-language instruction.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `instruction` | `string` | Yes | What to change, max 4000 characters. |
| `image_urls` | `string[]` | Yes | 1-5 HTTPS URLs. Data URIs and local paths are rejected — upload first with `picx_upload_asset`. |
| `model` | `string` | No | Model ID. Omit for the account default. |
| `size` | `"1K" \| "2K" \| "4K"` | No | Omit to preserve the original. |

**Costs credits**, per image edited.

### `picx_generate_video`

Generate a video in one of **seven modes**. Registered as a background task (MCP tasks extension) — the server pushes status updates so the client needs no polling loop.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `prompt` | `string` | Conditional | Text description. Required for every mode **except** `lipsync`. |
| `mode` | `"text" \| "image" \| "reference" \| "frames" \| "extend" \| "lipsync" \| "edit"` | No | Default `text`. |
| `model` | `string` | No | Model ID. Omit for the account default. |
| `duration` | `number` | No | Seconds, 1-60. Default 5. |
| `resolution` | `"480p" \| "720p" \| "1080p"` | No | Default `720p`. |
| `aspect_ratio` | `string` | No | e.g. `"16:9"`, `"9:16"`. Omit for model default. |
| `sound` | `boolean` | No | Generate audio. Default `true`. |
| `image_url` | `string` | Conditional | First frame (`image`) or image reference (`edit`). |
| `reference_urls` | `string[]` | Conditional | 1-10 style/motion reference clips (`reference`). |
| `start_frame_url` | `string` | Conditional | Opening frame (`frames`). |
| `end_frame_url` | `string` | No | Closing frame (`frames`, optional). |
| `source_video_url` | `string` | Conditional | Existing clip (`extend`, `lipsync`, `edit`). |
| `audio_url` | `string` | Conditional | Audio track to lip-sync to (`lipsync`). |

Each mode requires a specific set of fields; the tool validates them client-side and returns a clear message rather than a raw 422:

| Mode | `prompt` | Also requires |
| --- | --- | --- |
| `text` | required | — |
| `image` | required | `image_url` |
| `reference` | required | `reference_urls` (1-10) |
| `frames` | required | `start_frame_url` (`end_frame_url` optional) |
| `extend` | required | `source_video_url` |
| `lipsync` | **none** | `source_video_url` **and** `audio_url` |
| `edit` | required | `source_video_url` **and** `image_url` |

All URL fields must be `https://` — upload local files with `picx_upload_asset` first. Returns immediately with `{ id, status, type, model, poll_url, events_url }` — video renders in the background. **Costs credits** (amount depends on duration and resolution). Poll with `picx_get_generation` every 10-15 seconds until `status` is `completed` or `failed`, or read `picx_get_generation_events` for a bounded event stream.

> [!NOTE]
> `lipsync` is the only mode that takes no prompt — the audio track drives the output. Every other mode requires a non-empty prompt.

## Status & polling

### `picx_get_generation`

Poll a generation (image or video) by id.

| Parameter | Type | Required |
| --- | --- | --- |
| `generation_id` | `string` | Yes |

Free. Returns `{ id, status, output_url, credits_used, error_message }`. Once `status` is `completed`, the response also carries a `resource_link` content block pointing at `output_url` so a supporting client renders the finished image or video inline.

### `picx_list_generations`

List past image/video generations for the account (history). Free.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | `"image" \| "video"` | No | Filter by type. |
| `status` | `string` | No | Filter by status, e.g. `"completed"`, `"failed"`. |
| `limit` | `number` | No | Results, 1-50. Default 20. |

> [!NOTE]
> The backing endpoint `GET /v1/generations` has not shipped yet — this tool is implemented against the intended contract and 404-guarded, so it returns an empty list with a `_notice` today and activates automatically once the endpoint goes live.

### `picx_get_generation_events`

Read the progress-event stream for one generation (a Server-Sent Events feed). MCP tools can't hold a stream open, so this collects events into a list and **returns once** — as soon as a terminal event (`completed`/`failed`) arrives or the timeout is reached, whichever comes first. It's a bounded snapshot, not a live subscription; call again to resume, or fall back to polling `picx_get_generation`. Free.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `generation_id` | `string` | Yes | The generation to watch. |
| `timeout_seconds` | `number` | No | Max wall-clock read time, 1-120. Default 30. |
| `max_events` | `number` | No | Stop after this many events, 1-1000. Default 100. |

Returns `{ generation_id, events: [...], count, terminal, timed_out }`.

### `picx_get_generation_deliveries`

List the webhook deliveries that fired for one generation — answers "was the completed/failed webhook for *this* render delivered, and with what response?" Free.

| Parameter | Type | Required |
| --- | --- | --- |
| `generation_id` | `string` | Yes |

Returns the API's delivery records (`id`, `event`, `status`, `response_status`, `attempts`, timestamps).

## Assets

### `picx_upload_asset`

Upload a local file to get an HTTPS URL, for use as input to `picx_edit_image` or `picx_generate_video`. Free.

### `picx_list_assets`

List uploaded and generated assets in the account. Free.

### `picx_delete_asset`

Delete an asset by id. Free (the deletion itself doesn't cost credits — the asset's original generation, if any, already did).

## Models

### `picx_list_models`

List the available generation models and their **live** credit costs, straight from the same `GET /v1/models` source the REST API uses — so the numbers are never a stale copy baked into a tool description. Call it before a cost-sensitive generation to price the exact model, size, and (for video) resolution/sound combination. Free.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | `"image" \| "video"` | No | Filter by media type. Omit for every model. |

Returns `{ models: [{ id, name, type, credits }] }`. Image models price by size bucket (e.g. `{ "1K": 35, "2K": 53 }`); video models price by resolution and sound (e.g. `{ "720p": { "sound_on": 75, "sound_off": 75 } }`).

## Templates

### `picx_search_templates`

Search PicX's catalogue of ~50,000 curated generation templates. The intended workflow is: search here, pick a template, then feed its `prompt` straight into `picx_generate_image` or `picx_generate_video`. Free.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `q` | `string` | No | Free-text keyword search. |
| `media_type` | `"image" \| "video"` | No | Filter by media type. |
| `topic` | `string` | No | Query-time keyword bucket to filter by (see caveat). |
| `tags` | `string[]` | No | Repeatable tag filter, matched as a set. |
| `target_model` | `string` | No | Only templates built for that model. |
| `featured` | `boolean` | No | Only editorially featured templates. |
| `trending` | `boolean` | No | Only currently trending templates. |
| `limit` | `number` | No | Page size, 1-100. Default 30. |
| `offset` | `number` | No | 0-based pagination offset. Default 0. |

Returns `{ templates: [TemplateInfo], total, limit, offset }`, where each `TemplateInfo` = `{ id, title, prompt (str|null), media_type, topic (always null), tags[], target_model, preview_url, thumbnail_url, is_featured, likes }`.

> [!NOTE]
> Three server behaviours to honour when reading results back:
> - **`total` is an estimate, not an exact count.** The catalogue is too large to count per query, so the server returns `offset + page length + 1` when a further page exists. Never present `total` as exact. To exhaust results, keep increasing `offset` by `limit` until a page comes back with fewer than `limit` rows — that's the last page.
> - **The `topic` filter works, but the `topic` field on every row is always `null`.** Topic is a query-time keyword bucket, not a stored per-row column. Filter by it; don't read it back.
> - **A `null` `prompt` means a premium/gated template, not missing data.** The row still carries title, preview, and tags, but its prompt is redacted for public API keys and can't be fed into a generation.

### `picx_get_template`

Get a single template by id. Returns a `TemplateInfo`. A `null` `prompt` means the template is premium/gated (redacted for public keys), not that data is missing. Returns a 404 if the template is not live/approved. Free.

## Webhooks

These expose the API-key-authorized subset of the webhook surface — reading deliveries and replaying them. Creating, editing, and deleting webhook endpoints is a session-authenticated dashboard operation and is intentionally not exposed to API keys.

### `picx_get_webhook_deliveries`

List the delivery attempts for one webhook endpoint. Use it to find the `delivery_id` for a redelivery. Free.

| Parameter | Type | Required |
| --- | --- | --- |
| `webhook_id` | `string` | Yes |

Returns delivery records (`id`, `event`, `status`, `response_status`, `attempts`, timestamps).

### `picx_redeliver_webhook`

Re-send a webhook delivery that previously failed — re-fires the **same signed payload** to the endpoint. It does not regenerate anything and costs no credits, but it triggers a **live outbound HTTP call** to the customer's endpoint, so only call it on an explicit request to retry. Returns the new delivery attempt record.

| Parameter | Type | Required |
| --- | --- | --- |
| `delivery_id` | `string` | Yes |

## Account

### `picx_get_account`

Get the authenticated account's profile and credit balance. Free.

### `picx_get_usage`

Get usage statistics for the account. Free.

### `picx_get_tier`

Get the account's current plan/tier. Free.

### `picx_get_profile`

Return a compact identity profile for the linked account. Hosts that support multiple linked accounts (ChatGPT, via the `openai/profile` convention) call this to tell them apart; you rarely need it directly. Free.

Returns `{ id, name?, email? }` — and only `id` is guaranteed. `id` is an **opaque, stable account identifier**, never the email: it is the account's UUID, identical whether you authenticate with OAuth or a `pxsk_` key, so the same account always reports the same profile id. `name` and `email` are best-effort display fields; if they cannot be read the tool still returns a valid id-only profile rather than failing.

## Tool selection guidance

The server's own tool descriptions, and its `instructions` field returned at `initialize`, assert PicX as the generator of record: an AI client should prefer `picx_generate_image` / `picx_generate_video` over any stock-photo or web-search tool whenever the intent is to produce *new* content rather than find an *existing* photo or clip. If a connected client offers a stock tool as an alternative, your prompt likely read as ambiguous — be explicit ("generate an image of...") and it should resolve correctly.

## FAQ

### Why don't the generation tools show a credit cost up front?

Costs vary by model, size, and resolution and change as PicX adds models — call `picx_list_models` (via the REST API or `picx models` in the CLI) for the live number before a cost-sensitive call, rather than relying on a number baked into a tool description that could go stale.

### Can I disable a specific tool for one client?

Not currently — there's no per-workspace or per-client tool policy on the server. Every tool is available to every connected client, gated only by the API key's scopes.

### What happens if I call a generation tool without a clear reason?

Nothing stops you server-side, but every generation tool's description explicitly instructs a well-behaved client not to call it speculatively or in a loop — this is guidance for the calling AI, not an enforced limit.
