# Update customiser option (`update_customiser_option`)

Applies a JSON merge patch to one record in one customiser option family. Only the fields present in the patch change; omitted fields are left alone and a field set to null clears a nullable value. The patch is checked against the family schema and the customiser pricing model, so a field the model does not use is refused rather than stored. Read the record with get_customiser_option first. It requires the customisers:write scope, takes an optional idempotency_key for replay, and supports dry_run.

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

## Purpose

Change one option a shopper picks from, without touching the rest of its family.

## Annotations

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

## Prerequisites

- A record id from list_customiser_options.
- The record current values from get_customiser_option, so the patch is built against what is there now.
- letter_type_id for the letter_part and letter_part_colour families, and letter_part as well for letter_part_colour.
- A merchant has connected this store and approved the customisers:write scope.

## Side effects

- Changes one option record of one customiser, visible to shoppers if the customiser is live.
- Clears the customiser cached storefront configuration.
- Spends one unit of the store option-write budget.

## Arguments

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `customiser_id` | integer | yes | The customiser id, from list_customisers. |
| `option_type` | string | yes | Which option family the record belongs to. One of: `backboard`, `backlight`, `colour`, `extra`, `font`, `form`, `icon`, `jacket`, `letter_type`, `letter_part`, `letter_part_colour`, `material`, `mounting`, `mounting_colour`, `preset`, `size`, `support_finish`, `legacy_fixed_height_size`. |
| `option_id` | integer or string | yes | The record identifier from list_customiser_options: an integer for every family except letter_part, which is addressed by its catalogue name such as face or halo. |
| `patch` | object | yes | The RFC 7396 merge patch to apply. Only the members present change; a member set to null clears a nullable field. |
| `letter_type_id` | integer | no | The letter type that owns the record, required for the letter_part and letter_part_colour families. |
| `letter_part` | string | no | The letter part that owns the colour, required for the letter_part_colour family. One of: `face`, `back`, `side`, `top`, `bottom`, `left`, `right`, `halo`, `trim`, `tube`. |
| `idempotency_key` | string | no | An optional client-generated key unique to this logical write, such as a UUID. Repeating the call with the same key and the same arguments replays the original result; the route does not require one. |
| `dry_run` | boolean | no | When true, the patch is checked against the family schema and the customiser pricing model 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. |

## Result

The patched record with the family own field names. A dry run returns the update verdict instead and writes nothing.

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `request_id` | string | yes |  |
| `store` | object | yes |  |
| `store.id` | integer | yes |  |
| `store.name` | string | yes |  |
| `customiser_id` | integer | yes |  |
| `option_type` | string | yes | One of: `backboard`, `backlight`, `colour`, `extra`, `font`, `form`, `icon`, `jacket`, `letter_type`, `letter_part`, `letter_part_colour`, `material`, `mounting`, `mounting_colour`, `preset`, `size`, `support_finish`, `legacy_fixed_height_size`. |
| `option` | object | no | The record as it now stands, with the field names the public API publishes for its family. Absent on a dry run. |
| `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 update verdict. |

## Error cases

| Code | Recovery |
| --- | --- |
| `field_not_used_by_pricing_model` | Remove the field named by pointer; the customiser pricing model does not use it. |
| `insufficient_scope` | The connection was approved without customisers:write. |
| `resource_not_found` | No record with that id exists in that family of that customiser. |
| `unsupported_value` | That family has no update operation; allowed_values lists the families that do. |
| `validation_failed` | A patched value is out of range, the wrong type, or not a field this family accepts. |

## Example: Rename a colour

Request:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "update_customiser_option",
    "arguments": {
      "customiser_id": 42,
      "option_type": "colour",
      "option_id": 7,
      "patch": {
        "name": "Warm White (2700K)"
      }
    }
  }
}
```

Response:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": {
      "request_id": "req_01jz9x2k7c8f3m5n6p7q8r9s0t",
      "store": {
        "id": 12,
        "name": "Demo Signs"
      },
      "customiser_id": 42,
      "option_type": "colour",
      "option": {
        "id": 7,
        "customiser_id": 42,
        "name": "Warm White (2700K)",
        "colour_type": "single",
        "hexcode": "#FFEEDD",
        "sort_order": 1
      }
    }
  }
}
```

## Example: A family that cannot be updated (error)

Request:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "update_customiser_option",
    "arguments": {
      "customiser_id": 42,
      "option_type": "legacy_fixed_height_size",
      "option_id": 3,
      "patch": {
        "name": "Small"
      }
    }
  }
}
```

Response:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": true,
    "structuredContent": {
      "error": {
        "code": "unsupported_value",
        "title": "Unsupported value",
        "detail": "The legacy_fixed_height_size option family has no update operation. It supports: delete.",
        "recovery": "Send one of the values in allowed_values for the field named by pointer or parameter.",
        "parameter": "option_type",
        "allowed_values": [
          "backboard",
          "backlight",
          "colour"
        ],
        "supported_verbs": [
          "delete"
        ]
      }
    }
  }
}
```
