Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 78 additions & 9 deletions specification/draft/apps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,27 @@ UI iframes can use the following subset of standard MCP protocol messages:
- `ui/initialize` → `ui/notifications/initialized` - MCP-like handshake (replaces custom iframe-ready pattern in MCP-UI)
- `ping` - Connection health check

### App Capabilities in `ui/initialize`

When the View sends an `ui/initialize` request to the Host, it MUST include its capabilities in the `appCapabilities` field:

```typescript
interface McpUiAppCapabilities {
/** Experimental features (structure TBD). */
experimental?: {};
/** App exposes MCP-style tools that the host can call. */
tools?: {
/** App supports tools/list_changed notifications. */
listChanged?: boolean;
};
/**
* Display modes the app supports. See Display Modes section for details.
* @example ["inline", "fullscreen"]
*/
availableDisplayModes?: Array<"inline" | "fullscreen" | "pip">;
}
```

### Host Context in `McpUiInitializeResult`

When the View sends an `ui/initialize` request to the Host, the Host SHOULD include UI-specific context in the `McpUiInitializeResult`'s `hostContext` field:
Expand Down Expand Up @@ -709,6 +730,62 @@ bridge.onsizechange = ({ width, height }) => {

Apps using the SDK automatically send size-changed notifications via ResizeObserver when `autoResize` is enabled (the default). The notifications are debounced and only sent when dimensions actually change.

### Display Modes

Views can be displayed in different modes depending on the host's capabilities and the view's declared support.

```typescript
type McpUiDisplayMode = "inline" | "fullscreen" | "pip";
```

- **inline**: Default mode, embedded within the host's content flow
- **fullscreen**: View takes over the full screen/window
- **pip**: Picture-in-picture, floating overlay

#### Declaring Support

**View (`appCapabilities.availableDisplayModes`):**

Views declare which display modes they support in the `ui/initialize` request via `appCapabilities.availableDisplayModes`. This allows hosts to only offer display mode options that the view can handle.

```typescript
// Example: View declares support for inline and fullscreen
{
method: "ui/initialize",
params: {
appCapabilities: {
availableDisplayModes: ["inline", "fullscreen"]
},
// ...
}
}
```

**Host (`HostContext.availableDisplayModes`):**

Hosts declare which display modes they support in `HostContext.availableDisplayModes`. Views should check this before requesting a mode change.

#### Requesting Changes

Views request display mode changes via `ui/request-display-mode`. See the Requests section for message format.

#### Notifying Changes

Hosts notify views of display mode changes via `ui/notifications/host-context-changed` with the `displayMode` field.

#### Requirements

**View behavior:**
- View MUST declare all display modes it supports in `appCapabilities.availableDisplayModes` during initialization.
- View MUST check if the requested mode is in `availableDisplayModes` from host context before requesting a mode change.
- View MUST handle the response mode differing from the requested mode.

**Host behavior:**
- Host MUST NOT switch the View to a display mode that does not appear in its `appCapabilities.availableDisplayModes`, if set.
- Host MUST return the resulting mode (whether updated or not) in the response to `ui/request-display-mode`.
- If the requested mode is not available, Host SHOULD return the current display mode in the response.
- Host MAY decline display mode requests from Views that did not declare said modes in their capabilities.

### Theming

Hosts can optionally pass CSS custom properties via `HostContext.styles.variables` for visual cohesion with the host environment.
Expand Down Expand Up @@ -977,15 +1054,7 @@ Host behavior:
}
```

Host behavior:
* App MUST check if the requested mode is in `availableDisplayModes` from host context.
* It is up to the host whether it switches to the requested mode, but the host MUST return the resulting mode (whether updated or not) in the response.
* If the requested mode is not available, Host SHOULD return the current display mode in the response.
* Host MAY coerce modes on certain platforms (e.g., "pip" to "fullscreen" on mobile).

View behavior:
* View SHOULD check `availableDisplayModes` in host context before requesting a mode change.
* View MUST handle the response mode differing from the requested mode.
See the Display Modes section for detailed behavior requirements.

`ui/update-model-context` - Update the model context

Expand Down
90 changes: 87 additions & 3 deletions src/generated/schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion src/generated/schema.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion src/spec.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ export interface McpUiHostContext {
/** @description How the UI is currently displayed. */
displayMode?: McpUiDisplayMode;
/** @description Display modes the host supports. */
availableDisplayModes?: string[];
availableDisplayModes?: McpUiDisplayMode[];
/**
* @description Container dimensions. Represents the dimensions of the iframe or other
* container holding the app. Specify either width or maxWidth, and either height or maxHeight.
Expand Down Expand Up @@ -487,6 +487,8 @@ export interface McpUiAppCapabilities {
/** @description App supports tools/list_changed notifications. */
listChanged?: boolean;
};
/** @description Display modes the app supports. */
availableDisplayModes?: McpUiDisplayMode[];
}

/**
Expand Down
Loading