Features tools
MCP tools for Features: features_create, features_list, features_update.
features_create: Create a featurefeatures_list: List featuresfeatures_update: Update a feature
features_create
Create a feature. Operation features.create · Brand level · permission catalog:write · risk tier write · since M4
Defines a feature of the brand, in the request's mode: something a product grants, such as feature.export
(a boolean), seats.max (a limit) or support.level (one of a set of values). Products grant values of it
in their entitlements, and customers' entitlements are resolved from what they've bought.
combine says how values from several products merge: or or first for booleans, max, sum or first
for limits, first for enums. The key and type never change, and enum values can be added but not removed.
A perUnit limit is multiplied by the subscription item's or purchase's quantity.
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: false · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
key | string | yes | Unique in the brand and mode, e.g. seats.max. Never changes. (at most 100 characters) |
name | string | yes | Shown on the pricing table, e.g. Seats. (1–120 characters) |
type | one of boolean, limit, enum | yes | boolean (on or off), limit (a whole number) or enum (one of a set of values). |
enumValues | array of string | no | Enum features: the allowed values, in display order. (1–50 items) |
combine | one of max, sum, or, first | no | Default: or for booleans, max for limits, first for enums. |
defaultValue | boolean or number or string | no | What customers without the feature get. Default: false, 0, or the first enum value. |
perUnit | boolean | no | Limit features only: multiply the value a product grants by the quantity bought or subscribed (e.g. 5 projects per seat). Default false. |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
validation_failed: A field is malformed, the combine rule doesn't fit the type, the default isn't a valid value, orperUnitis set on a feature that isn't a limit.feature_key_taken: The brand already has a feature with this key in this mode.permission_denied: You can't change this brand's catalog.
Example
A seat limit, per unit
Arguments:
{
"key": "seats.max",
"name": "Seats",
"type": "limit",
"defaultValue": 1,
"perUnit": true,
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"id": "feat_01m4tx5nj8emwbyf7y9vcf47y6",
"object": "feature",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
"livemode": false,
"key": "seats.max",
"name": "Seats",
"type": "limit",
"enumValues": null,
"combine": "max",
"defaultValue": 1,
"perUnit": true,
"createdAt": "2026-10-13T12:00:00.000Z",
"updatedAt": "2026-10-13T12:00:00.000Z"
}
features_list
List features. Operation features.list · Brand level · permission catalog:read · risk tier read · since M4
Lists the brand's features in the request's mode, newest first. Filter with key to find one feature.
Paginate with limit (1–100, default 10) and starting_after (the next_cursor of the previous page).
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
key | string | no | Only the feature with this key. (at most 100 characters) |
limit | integer | no | (1–100) |
starting_after | ID (feat_…) | no | – |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
validation_failed: A filter or pagination value is malformed.permission_denied: You can't see this brand's catalog.
Example
The brand's features
Arguments:
{
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"object": "list",
"data": [
{
"id": "feat_01m4tx5nj8emwbyf7y9vcf47y6",
"object": "feature",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
"livemode": false,
"key": "seats.max",
"name": "Seats",
"type": "limit",
"enumValues": null,
"combine": "max",
"defaultValue": 1,
"perUnit": true,
"createdAt": "2026-10-13T12:00:00.000Z",
"updatedAt": "2026-10-13T12:00:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}
features_update
Update a feature. Operation features.update · Brand level · permission catalog:write · risk tier write · since M4
Changes a feature's name, combine rule, default value, perUnit (limits) or (for enum features) its values.
Send only the fields to change. The key and type never change, and enum values can be added but not removed,
so values products already grant stay valid. Customers' entitlements are recomputed after a change of the
combine rule, default value or perUnit (customer.entitlements.updated for each customer whose values move).
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (feat_…) | yes | – |
name | string | no | (1–120 characters) |
combine | one of max, sum, or, first | no | How values from several products combine: or or first for booleans, max, sum or first for limits, first for enums. |
defaultValue | boolean or number or string | no | true/false for a boolean feature, a whole number for a limit, one of the values for an enum. |
enumValues | array of string | no | Enum features: the full list of values; existing values must stay (new ones can be added). (1–50 items) |
perUnit | boolean | no | Limit features only: multiply granted values by the quantity. Customers' entitlements follow. |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
validation_failed: No field to change was sent, or the new definition breaks a rule (e.g.perUniton a boolean).feature_change_not_allowed: The change removes enum values.resource_not_found: No feature with this ID is visible to the request.version_conflict: The feature changed at the same time; retry.permission_denied: You can't change this brand's catalog.
Example
Rename a feature
Arguments:
{
"id": "feat_01m4tx5nj8emwbyf7y9vcf47y6",
"name": "Team seats",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"id": "feat_01m4tx5nj8emwbyf7y9vcf47y6",
"object": "feature",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
"livemode": false,
"key": "seats.max",
"name": "Team seats",
"type": "limit",
"enumValues": null,
"combine": "max",
"defaultValue": 1,
"perUnit": true,
"createdAt": "2026-10-13T12:00:00.000Z",
"updatedAt": "2026-10-14T09:30:00.000Z"
}