# Protocol Extensions MCP protocol extensions advertise additional, optional capabilities during the initialize handshake. A server opts in via `Builder::enableExtension()`: ```php use Mcp\Schema\Extension\Apps\McpApps; use Mcp\Server; $server = Server::builder() ->setServerInfo('My Server', '1.0.0') ->enableExtension(new McpApps()) ->build(); ``` Pass one or more `ServerExtensionInterface` instances; multiple extensions can be enabled in a single call. Enabling the same extension twice throws a `LogicException`. > Note: extensions enabled via `enableExtension()` are merged into the > `extensions` capability even when you supply your own `ServerCapabilities` via > `setCapabilities()`. An enabled extension overrides any entry under the same > id already present in those capabilities. ## MCP Apps (`io.modelcontextprotocol/ui`) The [MCP Apps extension][ext-apps] lets servers expose interactive HTML UIs as resources. Clients that support it render them in sandboxed iframes and bridge tool calls between the iframe (the *View*) and the server via the host. A UI consists of two pieces wired together by `_meta.ui`: 1. **A resource** with URI scheme `ui://` and MIME type `text/html;profile=mcp-app`, returning the HTML body. 2. **A tool** linked to that resource via `UiToolMeta`, so the client knows to open the UI when the tool is invoked. ```php use Mcp\Schema\Content\TextResourceContents; use Mcp\Schema\Extension\Apps\McpApps; use Mcp\Schema\Extension\Apps\ToolVisibility; use Mcp\Schema\Extension\Apps\UiResourceContentMeta; use Mcp\Schema\Extension\Apps\UiResourceCsp; use Mcp\Schema\Extension\Apps\UiResourcePermissions; use Mcp\Schema\Extension\Apps\UiToolMeta; $server = Server::builder() ->enableExtension(new McpApps()) ->addResource( fn () => new TextResourceContents( uri: 'ui://my-app', mimeType: McpApps::MIME_TYPE, text: file_get_contents(__DIR__.'/app.html'), meta: ['ui' => new UiResourceContentMeta( csp: new UiResourceCsp(connectDomains: ['https://api.example.com']), permissions: new UiResourcePermissions(geolocation: true), prefersBorder: true, )], ), 'ui://my-app', mimeType: McpApps::MIME_TYPE, meta: ['ui' => McpApps::resourceMarker()], ) ->addTool( $myToolHandler, 'my_tool', meta: ['ui' => new UiToolMeta( resourceUri: 'ui://my-app', visibility: [ToolVisibility::Model, ToolVisibility::App], )], ) ->build(); ``` Note the two distinct `_meta.ui` shapes: the resource *descriptor* (its `resources/list` entry) carries only an empty marker — `McpApps::resourceMarker()` — flagging it as an MCP App, while the resource *content* returned by `resources/read` carries the structured `UiResourceContentMeta` with the actual CSP and permission configuration. ### Server-side DTOs | Class | Purpose | | --- | --- | | `McpApps` | Extension marker; provides `EXTENSION_ID`, `MIME_TYPE`, `URI_SCHEME` constants. | | `UiToolMeta` | Tool `_meta.ui` payload: `resourceUri` + `visibility`. | | `ToolVisibility` | Enum: `Model`, `App`. | | `UiResourceContentMeta` | Resource content `_meta.ui`: `csp`, `permissions`, `domain`, `prefersBorder`. | | `UiResourceCsp` | CSP allow-lists: `connectDomains`, `resourceDomains`, `frameDomains`, `baseUriDomains`. | | `UiResourcePermissions` | Sandbox permissions: `camera`, `microphone`, `geolocation`, `clipboardWrite`. | ### Writing the HTML view The View and host exchange `JSONRPCMessage` **objects** (not JSON strings) via `window.parent.postMessage`. Before the host forwards `tools/call`, `tool-input`, or `tool-result`, the View must complete the spec-mandated handshake: 1. View → Host: `ui/initialize` request 2. Host → View: response with `hostCapabilities`, `hostInfo`, `hostContext` 3. View → Host: `ui/notifications/initialized` 4. View → Host: `ui/notifications/size-changed` whenever the iframe wants to resize See the [`ext-apps` repository][ext-apps] for the full protocol, official TypeScript SDK (`@modelcontextprotocol/ext-apps`), and view-side examples. A working minimal view is included in [`examples/server/mcp-apps/weather-app.html`](../examples/server/mcp-apps/weather-app.html). [ext-apps]: https://github.com/modelcontextprotocol/ext-apps