# MCP tool reference

Canonical URL: https://support.optimonk.com/en/articles/mcp-tool-reference

# MCP tool reference

The full MCP tool catalog, with params and returns.

The MCP server exposes 29 tools. Everything below is generated from the live tool schemas in `server/mcp-tools.ts` — the source of truth — by `npm run gen:mcp-docs`. A CI check fails the build if a tool changes and this page isn't regenerated, so it can't drift.

| Tool | What it does |
| --- | --- |
| whoami | Which OptiMonk account this connection is acting as, and what it is allowed to do. Call this first when a tool returns a not-found or a scope error — those read the same whether the credential is pointed at the wrong account or the object really is missing. |
| build_popup | Start a popup build from a public reference image URL. Returns a runId, which is also a valid jobId: call watch_job to wait until the job is terminal, or get_job for a single read or when the client cannot hold a request open. |
| get_popup_html | Fetch completed build HTML. Wait with watch_job first (the runId is a valid jobId); use get_job for a single read or when the client cannot hold a request open. |
| get_popup_preview | SEE a completed build: server-rendered screenshots at real browser proportions — desktop (1440×900) and mobile (390×844) — returned as image content blocks. get_popup_html returns the markup; this returns the picture. |
| edit_popup | Apply a natural-language edit to a completed build. Returns queued with a jobId; call watch_job with that jobId, then get_popup_html. Use get_job for a single read or when the client cannot hold a request open. |
| upload_reference_image | Upload a base64-encoded image to public storage; use the returned publicUrl as build_popup referenceUrl. |
| get_design_thread | Read a design thread: the ordered event log, the derived state (designing / variant_picked / campaign_live) and the current concept cards with their preview images. campaign_live means a campaign exists (it is created inactive); state.published says whether it was published and switched on. A single read; to wait for progress use watch_design_thread, never a poll loop. To show the cards for the user to pick from, use get_concept_board. |
| get_concept_board | SEE the concept cards of a design thread: this result ATTACHES the images — one 2×2 board with each card's letter and name rendered into it, plus one thumbnail per card in board order. Show the user the attached board image (or the attached thumbnails) exactly as returned; never hotlink imageUrl/mockupUrl inside HTML, widgets or artifacts (sandboxes block cross-origin images and the user sees broken tiles) — those URLs are for opening in a browser only. Under the picture list each letter with its name, then ask ONE question: which letter? Call select_variant only after the user has chosen. get_design_thread returns the same cards as data. |
| start_design_thread | Open a new design thread from a brief (e.g. "a welcome popup for earfun.hu with 10% off"). Returns the session id; the agent then asks discovery questions and generates concepts — call watch_design_thread to wait for the next question or the concept cards (never sleep or poll), and send_design_message to answer. |
| get_coupon | Read the coupon a build hands out: whether the popup even has a coupon element, the stored spec, and every fixed code currently in it. Call this before proposing a coupon — an empty codes list means the popup would publish a blank coupon box. |
| list_campaigns | List campaigns for this account (newest first). |
| get_campaign | Get a campaign by runId and/or campaignId (at least one required). |
| create_campaign | Create a DRAFT campaign from a completed build (no publish). Requires a designer-session-backed build: start_design_thread creates one, while a standalone build_popup run does not. Returns `livePreview` (a shareable public preview link and a logged-in app link) — give both to the user in your closing message, with a targeting summary from `summary`. |
| set_campaign_name | Rename a campaign. |
| publish_campaign | Publish a campaign to OptiMonk and activate it. Returns `livePreview` (a shareable public preview link and a logged-in app link) — give both to the user in your closing message, with a targeting summary. |
| get_campaign_settings | Read a build's current delivery settings (triggers, targeting, frequency, overlay) and a human-readable summary of them. |
| set_campaign_settings | Save a build's delivery settings (triggers, targeting, frequency, overlay) as one unit; creates the campaign's settings draft if no campaign exists yet. |
| prepare_animated_background | Start generating the animated background for one design, before the merchant is asked whether they want it. Takes about 40 seconds. Safe to call again: a second call while one is running, or on a design that already has its answer, starts nothing and tells you which. Many designs are deliberately not eligible — a flat-colour background has nothing to animate — and that is a normal answer, not a failure. Pass wait to be told the settled outcome instead of returning at the claim. |
| set_animated_background | Record whether this design should use its animated background or stay static. Choosing animated requires that the design actually has a clip — prepare_animated_background makes one, and many designs are deliberately not eligible. The answer survives a reload. Note: builds are static for now — the design journey no longer offers animation and the built popup does not carry the clip; the recorded answer is kept for a later campaign-page feature. |
| set_coupon | Settle the coupon on a build AFTER the merchant agreed to it: writes the spec, rewrites the fixed code in the popup, and records the agreement on the design thread. Propose the coupon in the conversation first — this tool is the approval, not the proposal. |
| get_job | Read the status of a long-running job by its jobId — a build, or a queued design-thread change. terminal tells you whether anything further will happen on its own. A build job in status selected is a design that was picked but never built: nothing is running, and select_variant starts the build. Prefer watch_job while you are waiting; use this for a single read or when the client cannot hold a request open. |
| watch_job | Wait for a long-running job to finish instead of polling. Emits progress notifications while it runs (when your client sends a progressToken) and returns the final status. Returns immediately if the job is already finished. On timeout it returns timedOut with the status so far — call again to keep waiting. Without a progressToken the call is silent until it returns, so keep timeoutSeconds under your client's idle timeout for tool calls (often 300 s); the default already is. |
| set_plan_coupon | Settle the coupon on the PLAN, before any popup has been built — the coupon step of the campaign-creation flow. Use this while the merchant is still choosing a design; once a popup exists, set_coupon writes to the build itself. Propose the coupon in the conversation first: this tool records the agreement, it is not the proposal. |
| regenerate_animated_background | Change how a built popup's animated background MOVES ("slower", "make the steam drift left", "stop the water moving"). Needs a built popup that already HAS an animated background — it regenerates the clip, it cannot add one. Takes about a minute: answers at once with a jobId, watch it with watch_job and read result.body for the new clip's url and motion. The new clip is a draft until it is saved. |
| patch_popup | Edit a built popup by describing the change in words ("make the headline bigger", "swap the button colour"). Answers at once with a jobId; watch it with watch_job, then read the edited html from the finished job's result (result.body.html). Omit html to edit the popup's current document. Use edit_popup instead for a conversational redesign through the design thread. |
| send_design_message | Send a message to a design thread. While the thread is still scoping it ANSWERS the agent's discovery question; once cards exist it refines the concept board; after select_variant it edits the picked popup. Set newVariant to start another concept round instead; newVariantFrom can optionally anchor it to a picked run. Otherwise the server routes by thread state. Then wait with watch_design_thread when the message landed on the board (routedTo: board) or with watch_job on the returned jobId when it landed on a run — never sleep or poll get_design_thread between calls. (Picking a variant is not done by message — use select_variant.) |
| restore_revision | Restore an earlier version of the popup in a design thread. Name the version by revisionId, or ask for stepsBack (1 = the previous version). The restore runs as a queued design change and answers with a jobId to watch; the live campaign is not changed until you publish again. |
| select_variant | Pick one or more concept cards and BUILD them into popups — the agent's Build it. This is THE decision that narrows the thread: afterwards send_design_message edits the picked popup instead of the board. The build starts in the background and the draft campaign is created right away: watch the returned jobId with watch_job, then agree targeting with get_campaign_settings / set_campaign_settings and publish with publish_campaign. This call answers within about 40 seconds even when the build is still starting up — `pending: true` with a null campaignId means exactly that, so watch the jobId and read the campaign from get_design_thread shortly after; never re-pick because a call felt slow, and if one ever does time out, repeat it with the same ids rather than picking again, since a repeat returns the same runs and never builds twice. Pass several ids for an A/B pair — always the FULL selection in the same order, since a call that adds to an earlier pick re-adopts the cards it repeats rather than reusing their runs. |
| watch_design_thread | Wait for a design thread to need you instead of polling: returns when the agent asks a discovery question, when the concept cards and their mockups are all ready, when the thread ends, or on timeout (then call again). Returns immediately if one of those already holds. Never sleep or poll get_design_thread between calls. |

## Tool details

Parameters, defaults, enums, and return fields for each tool:

### `whoami`

0 params

Which OptiMonk account this connection is acting as, and what it is allowed to do. Call this first when a tool returns a not-found or a scope error — those read the same whether the credential is pointed at the wrong account or the object really is missing.

**Returns** `accountId` `loginId` `via` `credential` `scopes` `canPublish`

### `build_popup`

5 params

Start a popup build from a public reference image URL. Returns a runId, which is also a valid jobId: call watch_job to wait until the job is terminal, or get_job for a single read or when the client cannot hold a request open.

`referenceUrl` string required

Publicly fetchable PNG/JPG/WEBP of the popup to recreate

`domain` string required

Target store hostname, e.g. shop.com

`userPrompt` string optional

`formatHint` enum optional

`card` `fullscreen`

`idempotencyKey` string optional

Pass a stable id to make retries safe: a second call with the same key returns the first call's runId instead of starting (and charging for) another build.

**Returns** `runId` `shortId` `status` `replayed` `note`

### `get_popup_html`

2 params

Fetch completed build HTML. Wait with watch_job first (the runId is a valid jobId); use get_job for a single read or when the client cannot hold a request open.

`runId` string required

`viewport` enum optional default: `desktop`

`desktop` `mobile`

**Returns** `html` `viewport`

### `get_popup_preview`

2 params

SEE a completed build: server-rendered screenshots at real browser proportions — desktop (1440×900) and mobile (390×844) — returned as image content blocks. get_popup_html returns the markup; this returns the picture.

`runId` string required

`viewport` enum optional default: `both`

`both` `desktop` `mobile`

Which viewport(s) to picture. Each comes back as its own image block.

**Returns** `runId` `images` `missing`

### `edit_popup`

4 params

Apply a natural-language edit to a completed build. Returns queued with a jobId; call watch_job with that jobId, then get_popup_html. Use get_job for a single read or when the client cannot hold a request open.

`runId` string required

`message` string required

What to change, e.g. 'make the headline red' (maximum 2000 characters)

`viewport` enum optional default: `desktop`

`desktop` `mobile`

`imageUrls` array optional

Up to 8 public reference image URLs

**Returns** `runId` `jobId` `status` `note`

### `upload_reference_image`

2 params

Upload a base64-encoded image to public storage; use the returned publicUrl as build_popup referenceUrl.

`imageBase64` string required

Base64-encoded image bytes (no data: prefix)

`contentType` enum required

`image/png` `image/jpeg` `image/webp`

**Returns** `publicUrl` `storageKey`

### `get_design_thread`

1 param

Read a design thread: the ordered event log, the derived state (designing / variant_picked / campaign_live) and the current concept cards with their preview images. campaign_live means a campaign exists (it is created inactive); state.published says whether it was published and switched on. A single read; to wait for progress use watch_design_thread, never a poll loop. To show the cards for the user to pick from, use get_concept_board.

`sessionId` string required

Design session id

**Returns** `sessionId` `domain` `status` `state` `legacy` `events` `concepts`

### `get_concept_board`

1 param

SEE the concept cards of a design thread: this result ATTACHES the images — one 2×2 board with each card's letter and name rendered into it, plus one thumbnail per card in board order. Show the user the attached board image (or the attached thumbnails) exactly as returned; never hotlink imageUrl/mockupUrl inside HTML, widgets or artifacts (sandboxes block cross-origin images and the user sees broken tiles) — those URLs are for opening in a browser only. Under the picture list each letter with its name, then ask ONE question: which letter? Call select_variant only after the user has chosen. get_design_thread returns the same cards as data.

`sessionId` string required

Design session id

**Returns** `sessionId` `cells` `next`

### `start_design_thread`

1 param

Open a new design thread from a brief (e.g. "a welcome popup for earfun.hu with 10% off"). Returns the session id; the agent then asks discovery questions and generates concepts — call watch_design_thread to wait for the next question or the concept cards (never sleep or poll), and send_design_message to answer.

`text` string required

The brief: what popup is wanted, for which store

**Returns** `sessionId` `shortId` `next`

### `get_coupon`

1 param

Read the coupon a build hands out: whether the popup even has a coupon element, the stored spec, and every fixed code currently in it. Call this before proposing a coupon — an empty codes list means the popup would publish a blank coupon box.

`runId` string required

The build's runId

**Returns** `runId` `hasCouponElement` `spec` `summary` `codes` `emptyCodeSlots` `contractIssues`

### `list_campaigns`

1 param

List campaigns for this account (newest first).

`limit` number optional default: `20`

**Returns** `campaigns` `nextCursor`

### `get_campaign`

2 params

Get a campaign by runId and/or campaignId (at least one required).

`runId` string optional

`campaignId` string optional

**Returns** `id` `name` `status` `domain` `v3RunId` `omCampaignId` `livePreview` `next`

### `create_campaign`

2 params

Create a DRAFT campaign from a completed build (no publish). Requires a designer-session-backed build: start_design_thread creates one, while a standalone build_popup run does not. Returns `livePreview` (a shareable public preview link and a logged-in app link) — give both to the user in your closing message, with a targeting summary from `summary`.

`runId` string required

A completed build's runId

`domain` string optional

Only after a domain_not_on_account refusal: the merchant's own domain to file the campaign under, from the list that refusal named

**Returns** `id` `name` `status` `campaign` `summary` `livePreview` `next`

### `set_campaign_name`

2 params

Rename a campaign.

`campaignId` string required

`name` string required

**Returns** `name`

### `publish_campaign`

1 param

Publish a campaign to OptiMonk and activate it. Returns `livePreview` (a shareable public preview link and a logged-in app link) — give both to the user in your closing message, with a targeting summary.

`campaignId` string required

The campaign to publish, by id

**Returns** `campaignId` `omCampaignId` `omVariantId` `databaseId` `propagating` `ssrPreviewUrl` `activation` `redirect` `livePreview` `next`

### `get_campaign_settings`

2 params

Read a build's current delivery settings (triggers, targeting, frequency, overlay) and a human-readable summary of them.

`runId` string optional

The build whose settings to read (give this OR campaignId)

`campaignId` string optional

The campaign whose settings to read (give this OR runId)

**Returns** `campaignId` `settings` `summary` `livePreview` `next`

### `set_campaign_settings`

12 params

Save a build's delivery settings (triggers, targeting, frequency, overlay) as one unit; creates the campaign's settings draft if no campaign exists yet.

`runId` string optional

The build whose settings to save (give this OR campaignId)

`campaignId` string optional

The campaign whose settings to save (give this OR runId)

`trigger` enum required

`timed` `exitIntent` `scrollDown` `inactivity` `click` `javascriptEvent` `omPassthrough`

What opens the popup — the choice the delay/scroll fields below hang off

`timedDelaySec` number optional

Seconds to wait, for a timed or inactivity trigger only (default 5)

`scrollPercent` number optional

How far down the page, for a scrollDown trigger only (default 50)

`where` enum required

`all` `homepage` `urlContains`

Which pages the popup may show on

`urlContains` string optional

The URL fragment to match, for where: "urlContains" only (default "")

`triggers` array optional

`targeting` array optional

`frequency` object optional

`overlay` object optional

`meta` object optional

**Returns** `campaignId` `settings` `summary` `livePreview` `next`

### `prepare_animated_background`

3 params

Start generating the animated background for one design, before the merchant is asked whether they want it. Takes about 40 seconds. Safe to call again: a second call while one is running, or on a design that already has its answer, starts nothing and tells you which. Many designs are deliberately not eligible — a flat-colour background has nothing to animate — and that is a normal answer, not a failure. Pass wait to be told the settled outcome instead of returning at the claim.

`sessionId` string required

The design thread the concept belongs to

`conceptId` string required

The design to animate the background of

`wait` boolean optional

Hold the call until the clip has settled (about 40 seconds) instead of returning as soon as the work is claimed

**Returns** `sessionId` `conceptId` `outcome` `pending`

### `set_animated_background`

4 params

Record whether this design should use its animated background or stay static. Choosing animated requires that the design actually has a clip — prepare_animated_background makes one, and many designs are deliberately not eligible. The answer survives a reload. Note: builds are static for now — the design journey no longer offers animation and the built popup does not carry the clip; the recorded answer is kept for a later campaign-page feature.

`sessionId` string required

The design thread the concept belongs to

`conceptId` string required

The design being answered for

`choice` enum required

`static` `animated`

animated = use the generated clip as the background · static = keep the still plate

`version` number optional

The mockup version this answer is about. Omit unless you are tracking versions; a mismatch is refused rather than stored against the wrong picture.

**Returns** `sessionId` `conceptId` `choice`

### `set_coupon`

9 params

Settle the coupon on a build AFTER the merchant agreed to it: writes the spec, rewrites the fixed code in the popup, and records the agreement on the design thread. Propose the coupon in the conversation first — this tool is the approval, not the proposal.

`runId` string required

The build's runId

`type` enum required

`fixed` `unique` `shopify_automatic`

fixed = one code everyone sees (needs fixedCode) · unique = codes from the campaign's uploaded pool · shopify_automatic = Shopify generates a code per visitor (needs automatic)

`fallbackAction` enum optional

`hide` `text`

unique/shopify_automatic: what to do when no code is available. Default hide.

`fallbackCoupon` string optional

Text shown when fallbackAction is text

`autoRedeem` boolean optional

Shopify shops: apply the code at checkout automatically

`automatic` object optional

Required for shopify_automatic

`fixedCode` string optional

The code to show, for type=fixed. Required unless the popup already carries one.

`couponIndex` number optional

Write into ONE coupon slot (index into get_coupon's codes). Omit to set every slot.

`fixedCodeChanges` array optional

Write several coupon slots at once: one {couponIndex, code} per slot. Use instead of fixedCode/couponIndex, never alongside them.

**Returns** `runId` `ok` `draft` `summary` `codes` `omPublished` `omPublishError` `contractIssues` `savedCodes`

### `get_job`

1 param

Read the status of a long-running job by its jobId — a build, or a queued design-thread change. terminal tells you whether anything further will happen on its own. A build job in status selected is a design that was picked but never built: nothing is running, and select_variant starts the build. Prefer watch_job while you are waiting; use this for a single read or when the client cannot hold a request open.

`jobId` string required

The jobId from a command that started long work (or a bare runId from build_popup)

**Returns** `jobId` `kind` `status` `terminal` `sourceStatus` `error` `runId` `threadId` `hasHtml` `result`

### `watch_job`

2 params

Wait for a long-running job to finish instead of polling. Emits progress notifications while it runs (when your client sends a progressToken) and returns the final status. Returns immediately if the job is already finished. On timeout it returns timedOut with the status so far — call again to keep waiting. Without a progressToken the call is silent until it returns, so keep timeoutSeconds under your client's idle timeout for tool calls (often 300 s); the default already is.

`jobId` string required

The jobId from a command that started long work (or a bare runId from build_popup)

`timeoutSeconds` number optional

How long to wait before giving up and reporting the status so far (default 240, max 900).

**Returns** `jobId` `kind` `status` `terminal` `sourceStatus` `error` `runId` `threadId` `hasHtml` `result` `timedOut`

### `set_plan_coupon`

7 params

Settle the coupon on the PLAN, before any popup has been built — the coupon step of the campaign-creation flow. Use this while the merchant is still choosing a design; once a popup exists, set_coupon writes to the build itself. Propose the coupon in the conversation first: this tool records the agreement, it is not the proposal.

`sessionId` string required

The design thread whose plan the coupon belongs to

`type` enum required

`fixed` `unique` `shopify_automatic`

fixed = one code everyone sees (needs fixedCode) · unique = codes from the campaign's uploaded pool · shopify_automatic = Shopify generates a code per visitor (needs automatic)

`fallbackAction` enum optional

`hide` `text`

unique/shopify_automatic: what to do when no code is available. Default hide.

`fallbackCoupon` string optional

Text shown when fallbackAction is text

`autoRedeem` boolean optional

Shopify shops: apply the code at checkout automatically

`automatic` object optional

Required for shopify_automatic

`fixedCode` string optional

The code to show, for type=fixed

**Returns** `sessionId` `coupon` `fixedCode` `agreedBy` `at`

### `regenerate_animated_background`

2 params

Change how a built popup's animated background MOVES ("slower", "make the steam drift left", "stop the water moving"). Needs a built popup that already HAS an animated background — it regenerates the clip, it cannot add one. Takes about a minute: answers at once with a jobId, watch it with watch_job and read result.body for the new clip's url and motion. The new clip is a draft until it is saved.

`runId` string required

The build (run) id whose animated background to regenerate

`instruction` string required

What should move differently, in plain words

**Returns** `runId` `jobId`

### `patch_popup`

12 params

Edit a built popup by describing the change in words ("make the headline bigger", "swap the button colour"). Answers at once with a jobId; watch it with watch_job, then read the edited html from the finished job's result (result.body.html). Omit html to edit the popup's current document. Use edit_popup instead for a conversational redesign through the design thread.

`viewport` enum required

`desktop` `mobile`

Which document to edit: desktop or mobile

`html` string optional

The document to edit. Omit to edit the run's current html for the viewport

`instruction` string required

What to change, in plain words

`selectedIds` array optional

Optional data-v3id handles that scope the edit to particular elements

`overlaySelected` boolean optional

True when the caller selected the campaign's overlay/backdrop rather than an element

`mode` enum optional

`fast` `full`

fast (default) for a surgical patch, full for a rebuild of the document

`omStep` number optional

For multi-page popups: the 1-based page the instruction refers to

`history` array optional

Recent user/agent exchanges about this popup, oldest first, so a follow-up resolves

`skipSettingsGate` boolean optional

Skip the campaign-settings intent check (for re-sends of an instruction already vetted)

`measuredFeedback` string optional

What a previous attempt measured against the ask, for a second try at a size

`runId` string required

The build (run) id whose popup to edit

`requestId` string optional

Optional idempotency key: the same key on the same run returns the same job

**Returns** `runId` `jobId` `replayed`

### `send_design_message`

7 params

Send a message to a design thread. While the thread is still scoping it ANSWERS the agent's discovery question; once cards exist it refines the concept board; after select_variant it edits the picked popup. Set newVariant to start another concept round instead; newVariantFrom can optionally anchor it to a picked run. Otherwise the server routes by thread state. Then wait with watch_design_thread when the message landed on the board (routedTo: board) or with watch_job on the returned jobId when it landed on a run — never sleep or poll get_design_thread between calls. (Picking a variant is not done by message — use select_variant.)

`sessionId` string required

Design session id

`message` string required

What to change, in plain language

`imageUrls` array optional

Optional reference images for this message (public urls or app-relative refs), up to 8

`viewport` enum optional

`desktop` `mobile`

Which viewport the change is about, once a variant is picked

`answers` object optional

Optional structured answers to a clarify card: question id (from the agent_message questions payload in get_design_thread) → the chosen answer. Prose in `message` alone is read too, but only when it names one of the offered options exactly; anything else leaves the card unanswered.

`newVariant` boolean optional

Start a new concept round instead of editing the picked popup

`newVariantFrom` string optional

Optional picked run to use as the new variant's anchor

**Returns** `sessionId` `jobId` `routedTo` `runId` `state`

### `restore_revision`

3 params

Restore an earlier version of the popup in a design thread. Name the version by revisionId, or ask for stepsBack (1 = the previous version). The restore runs as a queued design change and answers with a jobId to watch; the live campaign is not changed until you publish again.

`sessionId` string required

The design thread id

`revisionId` string optional

A revision id from an earlier edit_applied event or a version listing

`stepsBack` number optional

How many versions to go back from the current one; 1 = the previous version

**Returns** `sessionId` `runId` `jobId` `targetRevisionId` `targetRevisionNumber`

### `select_variant`

3 params

Pick one or more concept cards and BUILD them into popups — the agent's Build it. This is THE decision that narrows the thread: afterwards send_design_message edits the picked popup instead of the board. The build starts in the background and the draft campaign is created right away: watch the returned jobId with watch_job, then agree targeting with get_campaign_settings / set_campaign_settings and publish with publish_campaign. This call answers within about 40 seconds even when the build is still starting up — `pending: true` with a null campaignId means exactly that, so watch the jobId and read the campaign from get_design_thread shortly after; never re-pick because a call felt slow, and if one ever does time out, repeat it with the same ids rather than picking again, since a repeat returns the same runs and never builds twice. Pass several ids for an A/B pair — always the FULL selection in the same order, since a call that adds to an earlier pick re-adopts the cards it repeats rather than reusing their runs.

`sessionId` string required

Design session id

`conceptIds` array required

The full selection of concept card ids from get_design_thread; more than one starts an A/B

`domain` string optional

Only after a domain_not_on_account refusal: the merchant's own domain to file the campaign under, from the list that refusal named

**Returns** `sessionId` `runId` `runIds` `campaignId` `jobId` `pending` `state` `next`

### `watch_design_thread`

2 params

Wait for a design thread to need you instead of polling: returns when the agent asks a discovery question, when the concept cards and their mockups are all ready, when the thread ends, or on timeout (then call again). Returns immediately if one of those already holds. Never sleep or poll get_design_thread between calls.

`sessionId` string required

Design session id, from start_design_thread

`timeoutSeconds` number optional

How long to wait before returning with reason "timeout" (default 240, max 900).

**Returns** `sessionId` `status` `state` `reason` `question` `concepts` `timedOut` `next`
