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

# MCP Apps

> How widget-bearing tools return interactive pages, and the REST endpoint that serves the same built widget HTML to hosts without a live MCP client.

Many Semicola tools open an interactive page (a widget) next to the chat: the campaign receipt, the
creative composer, the storefront's Listing. They follow the MCP Apps convention, so any host that
supports MCP Apps renders them.

## Tool-result contract

A widget-bearing tool declares its widget as a `ui://semicola/<view>/mcp-app.html` resource (the
[tool catalog](/v3/tool-catalog) lists it as **Opens widget**). Its result carries:

* short, model-facing text in `content`;
* the widget's data in `structuredContent`;
* host-only data in `_meta`, which the model doesn't see.

The host reads the `ui://` resource with `resources/read`, renders it in a sandboxed iframe, and
hands the tool result to it over the MCP Apps bridge. `resources/list` returns the live set of
widgets; don't hard-code a list, because it changes with the product.

Widgets call back through the host with the same tools, so every write still goes through the
tool's confirmation rules (see [Semi confirmations](/setup/semi-confirmations)).

## Widget HTML over REST

For a host that renders widgets without a live MCP client:

| Endpoint                                   | Returns                                     |
| ------------------------------------------ | ------------------------------------------- |
| `GET /api/v2/mcp-apps`                     | The registered widget views.                |
| `GET /api/v2/mcp-apps/{view}/mcp-app.html` | The built single-file widget, as HTML text. |

Both need authentication. Pass the HTML to a sandboxed iframe as `srcdoc`. The response carries the
widget's content security policy in the `x-mcp-app-csp` header, which the host should apply, and
`cache-control: no-store`. An unknown view returns `404` ("Unknown widget view."). Treat the view
name as opaque: use the one from the tool's resource URI.

Semicola's own app renders widgets in an iframe sandboxed to `allow-scripts allow-forms
allow-downloads`, with `form-action 'none'` so a form never submits anywhere.

## Not available yet

* Session-bound page capabilities and host-only page aliases (the Teach and Library pages' private
  material tools).
