# Create AI sign design source (`create_ai_sign_design_source`)

Declare a PNG, JPEG or WebP image of at most 5 MiB for the AI sign designer and receive its source id, presigned PUT target and required headers. PUT the bytes to the target; the image is verified when a design uses it. The source belongs to the current connection, including after token refresh. Replay returns no target. Spends no credit. Requires ai_sign_designs:write, supports dry_run, and requires an idempotency_key for an actual declaration.

- Source URL: https://www.signcustomiser.com/help/mcp/tools/create_ai_sign_design_source/
- Markdown URL: https://www.signcustomiser.com/help/mcp/tools/create_ai_sign_design_source.md
- MCP endpoint: https://mcp.signcustomiser.com
- Required scope: `ai_sign_designs:write`
- Behaviour: write

## Purpose

Reserve a private upload target for the image an AI sign design starts from.

## Annotations

| Hint | Value |
| --- | --- |
| readOnlyHint | false |
| destructiveHint | false |
| idempotentHint | true |
| openWorldHint | false |

## Prerequisites

- The image filename, its content type and its exact byte size.
- A merchant has connected this store and approved the ai_sign_designs:write scope.
- Call get_ai_sign_design_capabilities first to confirm the AI sign designer is available.

## Side effects

- Creates one AI sign design source and mints a presigned target that expires after about ten minutes.
- Spends no credit and starts no design.
- Claims the idempotency_key for at least 24 hours.

## Arguments

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `filename` | string | yes | The original filename. Its extension must match the content type: .png, .jpg, .jpeg, .jfif or .webp. The server chooses the stored object name. |
| `content_type` | string | yes | The image media type: image/png, image/jpeg or image/webp. Raster images only. |
| `byte_size` | integer | yes | The exact size of the bytes that will be sent, at most 5242880. A design refuses the source if the stored bytes are a different size. |
| `idempotency_key` | string | unless `dry_run` is true | A client-generated key unique to this logical write, such as a UUID. Required: repeating the call with the same key and the same arguments replays the original result instead of writing twice, and the same key with different arguments is an idempotency_key_conflict. |
| `dry_run` | boolean | no | When true, the declaration is checked against the source limits is checked and nothing is written: the result is the same verdict the apply would have reached, and a problem the apply would have raised comes back as the same tool error. Defaults to false. A dry run claims no key. |

## Result

The source record and the presigned target to PUT the bytes to, with the headers the PUT must carry. The target is returned once and cannot be re-read. A dry run returns the create verdict and mints nothing.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `request_id` | string | yes |  |
| `store` | object | yes |  |
| `store.id` | integer | yes |  |
| `store.name` | string | yes |  |
| `source` | object | no | The declared source. Absent on a dry run. |
| `source.id` | string | yes |  |
| `source.filename` | string | no |  |
| `source.content_type` | string | no |  |
| `source.byte_size` | integer | no |  |
| `source.status` | string | no | One of: `pending`, `uploaded`, `consumed`, `rejected`, `expired`. |
| `source.verification_failure_code` | string or null | no | One of: `size_mismatch`, `too_large`, `content_type_mismatch`, `dimensions_exceeded`, `pixel_limit_exceeded`, `undecodable`. |
| `source.width_px` | integer or null | no |  |
| `source.height_px` | integer or null | no |  |
| `source.expires_at` | string | no |  |
| `source.consumed_at` | string or null | no |  |
| `source.created_at` | string | no |  |
| `upload_target` | object | no | Where to PUT the bytes, and the headers the PUT must carry. Returned only by this tool, only once, and null on a replay. |
| `upload_target.method` | string | yes |  |
| `upload_target.url` | string | yes |  |
| `upload_target.headers` | object | no |  |
| `upload_target.expires_at` | string or null | no |  |
| `idempotent_replay` | boolean | no | True when this call replayed an earlier declaration with the same idempotency_key rather than creating a second source. |
| `dry_run` | boolean | no | Present and true only when dry_run was requested. |
| `valid` | boolean | no | Present only on a dry run, and always true: a failing dry run returns a tool error instead. |
| `verdict` | object | no | Present only on a dry run: the create verdict. |

## Error cases

| Code | Recovery |
| --- | --- |
| `ai_sign_designer_unavailable` | The AI sign designer is turned off for this store. |
| `idempotency_subject_changed` | The source recorded by this key no longer exists. Issue a new key and declare the source again. |
| `insufficient_scope` | The connection was approved without ai_sign_designs:write. |
| `source_size_exceeded` | byte_size is above max_byte_size (5 MiB). |
| `source_type_not_allowed` | The content type is not PNG, JPEG or WebP, or the filename extension does not match it; allowed_values lists the accepted values. |

## Example: Declare a PNG logo

Request:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "create_ai_sign_design_source",
    "arguments": {
      "filename": "shopfront-logo.png",
      "content_type": "image/png",
      "byte_size": 482133,
      "idempotency_key": "b8f1c2d3-4e5f-4a6b-9c7d-8e9f0a1b2c3d"
    }
  }
}
```

Response:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": {
      "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t",
      "store": {
        "id": 12,
        "name": "Demo Signs"
      },
      "source": {
        "id": "aisrc_9f2c4b7ad13e6058ba41cd4201",
        "filename": "shopfront-logo.png",
        "content_type": "image/png",
        "byte_size": 482133,
        "status": "pending",
        "verification_failure_code": null,
        "width_px": null,
        "height_px": null,
        "expires_at": "2026-10-21T09:30:00Z",
        "consumed_at": null,
        "created_at": "2026-10-20T09:30:00Z"
      },
      "upload_target": {
        "method": "PUT",
        "url": "https://uploads.example.invalid/ai-sign-design-source-target",
        "headers": [],
        "expires_at": "2026-10-20T09:40:00Z"
      },
      "idempotent_replay": false
    }
  }
}
```

## Example: An SVG file, which a source does not accept (error)

Request:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "create_ai_sign_design_source",
    "arguments": {
      "filename": "logo.svg",
      "content_type": "image/svg+xml",
      "byte_size": 18044,
      "idempotency_key": "b8f1c2d3-4e5f-4a6b-9c7d-8e9f0a1b2c3d"
    }
  }
}
```

Response:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": true,
    "structuredContent": {
      "error": {
        "code": "source_type_not_allowed",
        "title": "Source type not allowed",
        "detail": "AI sign design sources do not accept image/svg+xml files.",
        "recovery": "Use a value from allowed_values for the field named by pointer. A source is a PNG, JPEG or WebP image, and its filename extension must match its content type.",
        "pointer": "/content_type",
        "allowed_values": [
          "image/png",
          "image/jpeg",
          "image/webp"
        ]
      }
    }
  }
}
```
