> ## Documentation Index
> Fetch the complete documentation index at: https://docs.interchange.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat response rendering artifacts

> Optional UI artifacts the Murph chat response carries so MCPUI hosts can render a canonical surface instead of rebuilding from prose

A `POST /api/v2/murph/chat` response always carries the assistant's text
`answer`. On turns where Murph runs a tool that has a canonical interactive
surface, the response **also** carries a structured rendering artifact. MCPUI
hosts (the in-product Murph UI, and external hosts such as Claude or ChatGPT)
render that artifact instead of reconstructing the surface from the text.

<Info>
  Each artifact field is optional and nullable. A client that does not render
  MCPUI can ignore every artifact and show the text `answer` alone — the answer
  is always self-contained.
</Info>

## How to render an artifact

Every artifact names the MCP App that renders it and the data to hand it:

1. Load the MCP App at the artifact's `resourceUri`.
2. Pass the artifact's `data` object to the app as the tool result's
   `structuredContent`. The app routes on `data.endpoint` to the named `view`.

The host decides where to place the surface — the in-product Murph UI renders
the discovery widget **above** the text answer, for example.

## `discoveryMcpui`

Emitted on a successful `discover_products` tool call. Renders the product
discovery surface — a browsable, selectable list of the discovered products
grouped by storefront, with per-product brief-relevance reasoning.

```json theme={null}
{
  "discoveryMcpui": {
    "kind": "discover-products",
    "resourceUri": "ui://agentic-api/api-call/mcp-app.html",
    "view": "discover-products",
    "canonicalSurface": true,
    "discoveryId": "disc_7f3a…",
    "data": {
      "success": true,
      "status": 200,
      "endpoint": "/api/v2/buyer/discovery/discover-products",
      "method": "POST",
      "data": { "discoveryId": "disc_7f3a…", "productGroups": [], "proposals": [] }
    }
  }
}
```

| Field              | Type                                       | Notes                                                                                                                                                                                          |
| ------------------ | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `kind`             | `"discover-products"`                      | Identifies the artifact.                                                                                                                                                                       |
| `resourceUri`      | `"ui://agentic-api/api-call/mcp-app.html"` | The MCP App that renders it.                                                                                                                                                                   |
| `view`             | `"discover-products"`                      | The view the app routes to.                                                                                                                                                                    |
| `canonicalSurface` | `true`                                     | The artifact is the canonical surface for this result; do not rebuild it from the text answer.                                                                                                 |
| `discoveryId`      | string                                     | The discovery session id, when present. Lets the widget re-fetch products (`GET /api/v2/buyer/discovery/{discoveryId}/products`) so it can self-hydrate even if `data` was truncated for size. |
| `data`             | object                                     | The `discover_products` response envelope (`success`, `status`, `endpoint`, `method`, `data`). Hand this to the app as `structuredContent`.                                                    |

When this artifact is present, Murph's text `answer` is a concise orientation
(totals, price range, any recommended plans) plus next steps — it deliberately
does **not** re-list every product, because the widget already shows the full,
selectable set.

## Other rendering artifacts

The chat response uses the same pattern for other canonical surfaces:

| Field            | Emitted on                                                            | `resourceUri`                                      | `view`               |
| ---------------- | --------------------------------------------------------------------- | -------------------------------------------------- | -------------------- |
| `creativeMcpui`  | a successful creative-session call                                    | `ui://agentic-api/api-call/mcp-app.html`           | `creative-iteration` |
| `inventoryMcpui` | a seller inventory-selector / capabilities call                       | `ui://agentic-api/inventory-selector/mcp-app.html` | `inventory-selector` |
| `mcpAppWidget`   | an `open_<widget>` directive (e.g. a seller setup or credential form) | the named widget's `ui://…` resource               | —                    |

Each carries `kind`, `resourceUri`, `canonicalSurface`, and a `data` payload to
hand the app as `structuredContent`; `creativeMcpui` additionally carries a
`refresh` directive describing the tool call that reloads the surface, and
`inventoryMcpui` carries the `esaId` and the initial selector filters.

## `ask_murph` MCP tool result (conformant MCP-UI)

The artifacts above ride the **REST** `/api/v2/murph/chat` response as named
fields — the in-product Murph UI reads them directly. An external MCP-UI host
(Claude, ChatGPT) that calls the **`ask_murph` MCP tool** never sees those named
fields; it sees a standard tool result. So `ask_murph` surfaces a turn's widget
the conformant way any MCP-UI host renders:

* It selects **one primary widget per turn** — an MCP-UI tool result carries a
  single render payload. Precedence, highest-intent first:
  `mcpAppWidget` → `creativeIntentMcpui` → `inventoryMcpui` → `creativeMcpui` →
  `discoveryMcpui` → `sellerAnalytics` → `murphEscalations`.
* The result embeds that widget's `ui://` resource in `content` and sets a
  per-call `_meta` (`ui.resourceUri` and the legacy `ui/resourceUri`) so the host
  loads the right MCP App for this result.
* For api-call-style widgets (discovery, inventory, creative, creative-intent),
  the app reads the flat api-call envelope (`success`, `endpoint`, `params`,
  `data`), so that envelope is spread onto the **top level** of
  `structuredContent` where `ontoolresult` reads it. The now-redundant named
  field is dropped so the payload isn't carried twice.
* Launch widgets (`mcpAppWidget`) and named-field panels (`sellerAnalytics`,
  `murphEscalations`) carry no api-call envelope; their data already sits under
  their named key in `structuredContent`, which the host hands the app.

A turn that produced several widgets still renders **one** in a generic host;
the in-product drawer can show all of them via the REST fields above.

## Token usage

Every `POST /api/v2/murph/chat` response carries a `usage` object reporting the
turn's token consumption, cumulative across the tool-loop iterations of the turn.

```json theme={null}
{
  "usage": {
    "inputTokens": 1840,
    "outputTokens": 320,
    "cacheReadInputTokens": 11200,
    "cacheCreationInputTokens": 640,
    "latencyMs": 4200,
    "model": "claude-sonnet-5"
  }
}
```

| Field                      | Type    | Notes                                                                                                       |
| -------------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `inputTokens`              | integer | Uncached input tokens for the turn. Does **not** include tokens served from or written to the prompt cache. |
| `outputTokens`             | integer | Tokens generated in the response.                                                                           |
| `cacheReadInputTokens`     | integer | Input tokens served from the prompt cache.                                                                  |
| `cacheCreationInputTokens` | integer | Input tokens written to the prompt cache on this turn.                                                      |
| `latencyMs`                | integer | Wall-clock duration of the turn, in milliseconds.                                                           |
| `model`                    | string  | The model that produced the answer.                                                                         |

<Info>
  The model reports cache reads and creations **separately** from `inputTokens` —
  they are not included in it. To get the true total input volume for a turn, sum
  `inputTokens + cacheReadInputTokens + cacheCreationInputTokens`. Murph caches its
  system prompt and tool surface, so on a warm conversation `cacheReadInputTokens`
  is typically the largest of the three.
</Info>

## Related

<CardGroup cols={2}>
  <Card title="Conversation scope" href="/v2/api/murph/conversation-scope" icon="sitemap">
    Bind a Murph conversation to your account or a single advertiser.
  </Card>

  <Card title="Ask Murph" href="/v2/setup/ask-murph" icon="sparkles">
    How Murph works as the in-product assistant.
  </Card>
</CardGroup>
