persona_create
Add a persona to a brand: an audience that the brand talks to.
Ask for a new audience on a brand. The agent creates a persona from what you say.
“Add a persona to Acme: runners aged 28 to 45 who buy the same shoe again. They fear that a new model is worse.”
The agent calls persona_create with the age range and a body that states the frictions that you gave. You then see the new persona on Acme, for example Loyalists. The body has no other heading until you write it.
The job guide Describe a brand shows each step of the job.
Reference
Create a persona on a brand — an audience archetype describing who the brand talks to (not the voice it speaks in, which belongs in the body of the brand). The context of the persona is one optional Markdown body (up to 50,000 characters), and both age bounds are optional. Suggested headings for the body: ## Profile (who they are), ## Motivations (what they want), ## Frictions (what stops them) and ## Language (the words the audience itself uses, not a locale). The headings are advice, not a schema. The slug is unique within the brand, so two brands may each have a ‘loyalists’.
Input
| Argument | Type | Required | Description |
|---|---|---|---|
age_max |
integer, 0 to 120 | no | Upper age bound. Omit for “and older”. |
age_min |
integer, 0 to 120 | no | Lower age bound. Omit for “and younger”. |
body |
string, 1 to 50000 characters | no | The context of the persona, as one Markdown text. Suggested headings: Profile, Motivations, Frictions, Language. |
brand_name |
string | yes | The slug of the brand this persona belongs to. |
description |
string, 1 to 500 characters | yes | One-line summary used to pick this persona from a list. |
name |
string, 1 to 120 characters | yes | Display name, e.g. “Time-poor Parent”. |
slug |
string, at most 120 characters | no | Optional explicit slug handle; normalized to kebab-case. Defaults to one derived from the name. |
Output
A successful call returns this object in structuredContent.
| Field | Type | Always present | Description |
|---|---|---|---|
persona |
object | yes | The persona in full. |
persona.ageMax |
integer, 0 to 120 or null | yes | The highest age of the audience. null when the range has no upper bound. |
persona.ageMin |
integer, 0 to 120 or null | yes | The lowest age of the audience. null when the range has no lower bound. |
persona.body |
string or null | yes | The context of the persona, as one Markdown text. null when no body is written. Headings such as Profile, Motivations, Frictions and Language are the advice of the tools, and the body does not need them. |
persona.brandId |
string | yes | The brand that owns the persona (brd_…). |
persona.createdAt |
number | yes | Milliseconds since the Unix epoch, in UTC. |
persona.createdBy |
string | yes | The user who created the record (usr_…). |
persona.description |
string | yes | One line about the persona. An agent picks a persona on it. |
persona.id |
string | yes | The id of the persona (psn_…). |
persona.name |
string | yes | The display name. |
persona.revision |
number | yes | The version of the record. Each change adds 1. Send it as base_revision to update or delete the record. |
persona.slug |
string | yes | The handle of the persona. It is unique in its brand, not in the organization. The tools take it as persona_name. |
persona.updatedAt |
number or null | yes | Milliseconds since the Unix epoch, in UTC. null until the first change. |
Failure codes
A failed call has isError set, and structuredContent.error holds one of these codes. Errors describes the shape of a failed call.
not_foundinvalid_sluginvalid_age_rangeslug_conflictorganization_unentitledforbiddeninvalid_requestinternal_error
Scope
The token must hold brand:write. Auth & scopes lists each scope.
Annotations
A client reads these hints. A hint that the tool does not declare has the default value of the MCP specification.
- Writes. The tool can change data.
- Not destructive. The tool makes only additive changes.
- Not idempotent. A second call with the same arguments can change more.
- Closed world. The tool reads and writes the data of AdCrunch only.
Example
The arguments:
{
"age_max": 45,
"age_min": 28,
"body": "## Profile\n\nRunners of 40 to 80 kilometres a week, ten years in, with one pair in rotation and one on the shelf.\n\n## Motivations\n\nThey want the same shoe again, and proof that it is the same. A resole keeps them running on a pair they trust.\n\n## Frictions\n\nThey fear the new model is worse than the one they know. A change of sole or of last reads to them as a risk, not as progress.\n\n## Language\n\nThey say \"my daily trainer\" and \"I got 900 out of the last pair\". They ask about the drop and the stack, never about the technology.",
"brand_name": "acme",
"description": "Runners who already own a pair, and who buy the next one without looking at another brand.",
"name": "Loyalists"
}
The result, in structuredContent:
{
"persona": {
"ageMax": 45,
"ageMin": 28,
"body": "## Profile\n\nRunners of 40 to 80 kilometres a week, ten years in, with one pair in rotation and one on the shelf.\n\n## Motivations\n\nThey want the same shoe again, and proof that it is the same. A resole keeps them running on a pair they trust.\n\n## Frictions\n\nThey fear the new model is worse than the one they know. A change of sole or of last reads to them as a risk, not as progress.\n\n## Language\n\nThey say \"my daily trainer\" and \"I got 900 out of the last pair\". They ask about the drop and the stack, never about the technology.",
"brandId": "brd_6a9c33",
"createdAt": 1790000000000,
"createdBy": "usr_4d8b12",
"description": "Runners who already own a pair, and who buy the next one without looking at another brand.",
"id": "psn_8c4a20",
"name": "Loyalists",
"revision": 1,
"slug": "loyalists",
"updatedAt": null
}
}