Skip to content

Conversation

@martinalong
Copy link
Collaborator

Document the availableDisplayModes field in McpUiAppCapabilities that allows apps to declare which display modes they support. This enables hosts to compute the intersection of host and app capabilities and only offer appropriate display mode controls.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 23, 2026

Open in StackBlitz

@modelcontextprotocol/ext-apps

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/ext-apps@331

@modelcontextprotocol/server-basic-react

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-basic-react@331

@modelcontextprotocol/server-basic-vanillajs

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-basic-vanillajs@331

@modelcontextprotocol/server-budget-allocator

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-budget-allocator@331

@modelcontextprotocol/server-cohort-heatmap

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-cohort-heatmap@331

@modelcontextprotocol/server-customer-segmentation

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-customer-segmentation@331

@modelcontextprotocol/server-map

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-map@331

@modelcontextprotocol/server-pdf

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-pdf@331

@modelcontextprotocol/server-scenario-modeler

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-scenario-modeler@331

@modelcontextprotocol/server-shadertoy

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-shadertoy@331

@modelcontextprotocol/server-sheet-music

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-sheet-music@331

@modelcontextprotocol/server-system-monitor

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-system-monitor@331

@modelcontextprotocol/server-threejs

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-threejs@331

@modelcontextprotocol/server-transcript

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-transcript@331

@modelcontextprotocol/server-video-resource

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-video-resource@331

@modelcontextprotocol/server-wiki-explorer

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/server-wiki-explorer@331

commit: 3d182cc

Copy link
Contributor

@ochafik ochafik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Martina!


### App Capabilities in `ui/initialize`

When the Guest UI sends an `ui/initialize` request to the Host, it MUST include its capabilities in the `appCapabilities` field:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now just "view" (cf. #325)

*
* @example ["inline", "fullscreen"]
*/
availableDisplayModes?: Array<"inline" | "fullscreen" | "pip">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would clarify the purpose of this (which is to allow the host to change the view's display mode).

In the carousel app example you mentioned, the app might support fullscreen but only on its own terms (e.g. when user clicks somewhere specific in their UI), although not sure if that's a use-case worth the complexity.

@idosal wdyt?

Copy link
Collaborator

@idosal idosal Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that's the intent, we should remove the requirement for the host to validate intersections, and instead suggest that it honors requests for its declared supported display modes (Host SHOULD honor requests for its declared supported display modes). We may enforce validation (e.g., Host MUST reject the request if the app's display mode isn't supported).

EDIT: I saw you've addressed this in your other comments. Completely agree :)

Copy link
Collaborator

@liady liady Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which is to allow the host to change the view's display mode

Yes, this part is not clear from this PR. Also the dynamic use case (availableDisplayModes changing as a result of user interaction like you mentioned) is not covered here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, didn't consider a dynamic value for this (this might be even more niche), more like the app doesn't want the host to initiate the fullscreen for it, it wants to be in control of when it wants to go fullscreen. But then again, maybe a bit niche, let's forget it for now ;-)

**Host Behavior:**

- Host SHOULD intersect its own `availableDisplayModes` with the app's declared modes
- When responding to `ui/request-display-mode`, host SHOULD only allow modes both support
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for separation of concerns, host should only bother checking against its own supported modes. Would be good to spec out what happens when receiving an invalid mode, not sure it that's already covererd in the other availableDisplayModes section

}
```

#### `availableDisplayModes`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#### `availableDisplayModes`
#### View `availableDisplayModes`

(have clear local disambiguation w/ the other

#### Host `availableDisplayModes`

- Host SHOULD intersect its own `availableDisplayModes` with the app's declared modes
- When responding to `ui/request-display-mode`, host SHOULD only allow modes both support
- Host MAY include the computed available modes in `HostContext.availableDisplayModes`
- Host MAY assume that all apps support `inline` display mode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

host should only assume this if the spec says they MUST support inline above (which I'm not think if fair, e.g. some apps might wanna start in pip from the get go)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. We shouldn't force inline

@ochafik ochafik requested review from idosal and liady January 23, 2026 16:02

### App Capabilities in `ui/initialize`

When the Guest UI sends an `ui/initialize` request to the Host, it MUST include its capabilities in the `appCapabilities` field:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@martinalong martinalong requested review from liady and ochafik January 23, 2026 17:32
@martinalong
Copy link
Collaborator Author

Made those changes!

@martinalong
Copy link
Collaborator Author

Oop I realized that the reason this whole thing was missing in the first place was b/c my PR to add it to the app capabilities was merged into the wrong branch earlier. Added a commit that actually adds this field to app capabilities!

@martinalong
Copy link
Collaborator Author

cc @idosal @liady @ochafik for re-review!

Copy link
Contributor

@ochafik ochafik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @martinalong !


**Host Behavior:**

- Host SHOULD honor requests for its declared supported display modes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like this belongs to the Host availableDisplayModes / ui/request-display-mode sections no?

- If omitted, hosts MAY assume the app supports all modes, or only `inline`. Apps that do not specify this field may not be able to take over fullscreen automatically.
- Apps MUST handle graceful degradation if placed in an unsupported mode

**Host Behavior:**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The host MUST NOT switch the view to a display mode that does not appear in its AppCapabilities.availableDisplayModes, if it is set.

}
```

#### View `availableDisplayModes`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there's already an untitled section:

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.

Could we merge it and the new material to a #### Display Modes section?

Starts w/ the types

  • Declaring support from View (AppCapabilities.availableDisplayModes)
  • Declaring support from Host (HostCapabilities.availableDisplayModes)
    Then the methods:
  • Requesting change from View (ui/request-display-mode)
  • Notifiying change from Host (ui/notifications/host-context-changed)
    Then the MUSTs and SHOULDs.

And this can be referenced from this and other sections.

*
* @example ["inline", "fullscreen"]
*/
availableDisplayModes?: Array<"inline" | "fullscreen" | "pip">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, didn't consider a dynamic value for this (this might be even more niche), more like the app doesn't want the host to initiate the fullscreen for it, it wants to be in control of when it wants to go fullscreen. But then again, maybe a bit niche, let's forget it for now ;-)


- Apps SHOULD declare all display modes they are designed to support
- If omitted, hosts MAY assume the app supports all modes, or only `inline`. Apps that do not specify this field may not be able to take over fullscreen automatically.
- Apps MUST handle graceful degradation if placed in an unsupported mode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that from inline to fullscreen, they just need to be reactive and respect insets (which they need to do anyway).

But anyway, why wouldn't we guarantee to an app we won't go against its express wishes?


**App Behavior:**

- Apps SHOULD declare all display modes they are designed to support
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd even say MUST, and say that Hosts MAY decline display mode requests from apps that didn't declare said modes in the capabilities.

ochafik
ochafik previously approved these changes Jan 23, 2026
Copy link
Contributor

@ochafik ochafik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last nit otherwise looks good, thanks @martinalong !

- 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 coerce modes on certain platforms (e.g., "pip" to "fullscreen" on mobile).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this conflicts w/ host MUST NOT switch to unsupported display mode above, just drop?

martinalong and others added 7 commits January 23, 2026 12:54
Document the availableDisplayModes field in McpUiAppCapabilities that allows
apps to declare which display modes they support. This enables hosts to
compute the intersection of host and app capabilities and only offer
appropriate display mode controls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Change "Guest UI" to "View" terminology
- Add "View" prefix to availableDisplayModes heading for disambiguation
- Remove intersection logic - host only checks its own supported modes
- Remove assumption that apps must support inline mode
- Simplify host behavior to honor/reject based on its own capabilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add `availableDisplayModes` field to `McpUiAppCapabilities` so apps can
  declare which display modes they support
- Change `HostContext.availableDisplayModes` type from `string[]` to
  `McpUiDisplayMode[]` for type safety
- Regenerate schemas

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove separate "App Capabilities" section for availableDisplayModes
- Add display mode requirements to existing ui/request-display-mode section:
  - Host MUST NOT switch View to mode not in appCapabilities.availableDisplayModes
  - Host MAY decline requests from Views that didn't declare modes
  - View MUST declare supported modes during initialization

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Restore McpUiAppCapabilities interface documentation with availableDisplayModes
- Restore "View MUST check if the requested mode is in availableDisplayModes
  from host context" clause that was accidentally removed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Consolidate all display mode documentation into a single section:
- Display mode types (inline, fullscreen, pip)
- Declaring support from View (appCapabilities.availableDisplayModes)
- Declaring support from Host (HostContext.availableDisplayModes)
- Requesting changes (ui/request-display-mode)
- Notifying changes (ui/notifications/host-context-changed)
- All MUST/SHOULD requirements for View and Host behavior

The ui/request-display-mode in Requests section now references
the Display Modes section for behavior details.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@martinalong martinalong force-pushed the martinalong/app-capabilities-docs branch from 30c2c7c to b4a9a5e Compare January 23, 2026 20:54
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@ochafik ochafik merged commit 89f58bf into main Jan 23, 2026
18 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants