Skip to content

Conversation

@martinalong
Copy link
Collaborator

Motivation and Context

  • Host passing viewport.width and viewport.maxWidth were unnecessary because the width of the app always needs to be 100%
  • Host passing viewport.height is unnecessary because the app decides the height
  • So all we really need is viewport.maxHeight. Thus, viewport has been simplified to just maxHeight
  • As a result, onsizechange can also be updated to onheightchange since we don't do anything with the width change notifications

How Has This Been Tested?

Manually tested with examples

Breaking Changes

Yes, any users using the viewport property will have to update their behavior

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 15, 2025

Open in StackBlitz

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

commit: 2eb8e31

@martinalong martinalong force-pushed the martinalong/mcp-apps/max-height-only branch 2 times, most recently from ac1d83c to 33fa759 Compare December 15, 2025 04:22
@ochafik
Copy link
Collaborator

ochafik commented Dec 15, 2025

@claude please review this PR in depth, and give your assessment / recommendations wrt/ backwards compatibility

jonathanhefner
jonathanhefner previously approved these changes Dec 15, 2025
Copy link
Member

@jonathanhefner jonathanhefner left a comment

Choose a reason for hiding this comment

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

Agreed this makes much more sense. It makes it easier for MCP Apps to determine their dimensions because one dimension is essentially fixed, and it simplifies the responsibilities of the host application.

@liady
Copy link
Collaborator

liady commented Dec 15, 2025

Yes - we also discussed this earlier in the SEP process, since ChatGPT Apps and MCP-UI were treating this question in different ways.
Eventually it should be very similar to a web page - the host effectively sets the width (and I agree it doesn't have to be communicated to the iframe) - and the UI just responds to it responsively. The UI should be able to dynamically set the outer height, since this is usually the dynamic dimension.

Two points here:

  1. We might have different display modes in the future where the dynamic dimension is the width and not necessarily just the height. It might be a good idea to keep the size change event generic in that sense.
  2. I agree that when the UI runs in an iframe it can check and be responsive to its dimensions by itself (using media queries or js) so there's no need to communicate the size from the outside. However we just need to remember that this is true as long as it runs inside a web iframe. Again - since this is our only render target right now it's not an issue right.

@martinalong
Copy link
Collaborator Author

martinalong commented Dec 16, 2025

@liady for both of those two points, can you give some specific examples where those would be true? I'm having a hard time imagining a situation for both of these

Also for 2, what are you saying is the implication of that? And what is the way that we would account for that future?

@martinalong martinalong force-pushed the martinalong/mcp-apps/max-height-only branch from 04b60b9 to 8614792 Compare December 16, 2025 00:30
@liady
Copy link
Collaborator

liady commented Dec 16, 2025

@martinalong for #1 there are several use cases like rendering the UI in a modal (where it can dynamically expand vertically and horizontally), or in a sidebar where it can affect the width, etc. Since we're not targeting only inlined UIs inside chats - and perhaps more display modes in the future - the horizontal axis size changes inside the UI might still be relevant.

For #2 - there is no concrete example other than rendering the UI not inside an iframe (for example inside a modal that's not an iframe). In that case media queries / js apis won't work. However that's not something we currently allow in the SEP, so it's not an issue. If we'll add render targets that are not web iframes, we can re-introduce passing the host's dimensions in the future.

@martinalong martinalong force-pushed the martinalong/mcp-apps/max-height-only branch from 8614792 to 189f525 Compare December 16, 2025 00:32
@martinalong
Copy link
Collaborator Author

@antonpk1 expressed concern over DM about potentially breaking existing WIP apps by updating onsizechange -> onheightchange, so I've reverted that back.

Coincidentally this should also address point 1 that you raised @liady !

@martinalong
Copy link
Collaborator Author

there are several use cases like rendering the UI in a modal (where it can dynamically expand vertically and horizontally), or in a sidebar where it can affect the width, etc. Since we're not targeting only inlined UIs inside chats - and perhaps more display modes in the future - the horizontal axis size changes inside the UI might still be relevant.

Ahh I see what you mean. Like basically any view where the app doesn't have to take up the full width.

Hmm yeah, I was trying to match the OpenAI spec here which just passes maxHeight alone, but I don't think it'll extend well to use cases that. B/c right now, undefined maxHeight = unlimited height in OpenAI's implementation. But maxWidth (by nature of not existing yet) is effectively undefined. Yet undefined in that case means something different: that there is indeed a maxWidth and the app needs to take up the full width available.

We should probably go back to passing viewport for the sake of future extensibility. Let me know if you are on board with this slight update to the type of viewport, and outline of how it would work @liady :

type Viewport = ({ height: number } | { maxHeight?: number }) &
  ({ width: number } | { maxWidth?: number });

The viewport has two independent dimension pairs:

  • Height: Either height (fixed) or maxHeight (flexible), never both
  • Width: Either width (fixed) or maxWidth (flexible), never both

These pairs are independent—you can have a fixed height with flexible width, or any other combination.

  • Fixed dimensions (height/width): The host controls the size. Set height: 100% (recommended) or use the pixel value directly.
  • Flexible dimensions (maxHeight/maxWidth or undefined): The app controls the size, up to the max if specified. If undefined, there is no limit.

Example usage:

if ("height" in hostContext.viewport) {                                                                                                 
  body.style.height = "100%";                                                                                                           
} else if (hostContext.viewport.maxHeight) {                                                                                            
  body.style.maxHeight = `${hostContext.viewport.maxHeight}px`;                                                                         
}  

// ...and repeat the same for width and maxWidth

For #2 - there is no concrete example other than rendering the UI not inside an iframe (for example inside a modal that's not an iframe). In that case media queries / js apis won't work.

Oh I was imagining apps would be measuring "full width" through just width: 100%, which should still work in that case?

@liady
Copy link
Collaborator

liady commented Dec 16, 2025

@martinalong sounds good, just few points:

  • We have the container measurements (height/width) that the host (always) sets - since it's an iframe. They can decide to change it when the inner app size changes (by listening to events), or to keep it fixed.
  • The inner app should:
    • Know what the outer dimensions are (for responsive design purposes, media queries, js api, etc)
    • Know when a dimension is fixed and when it can change it, and up to which size.
    • Decide when an inner dimension change requires an outer dimension change, and when not (for example a hortizontal scroll bar in a carousel view is ok)

So for our purposes I think:

  • The host should communicate height/width/maxHeight/maxWidth - I think it's ok that they'll be exclusive like you proposed
  • These should be constantly updated by the host - so for example if the host changed the iframe fixed dimensions (for any reason) it should (imo) communicate it to the app.
  • We should keep it onsizechange and not just onheightchange - since both dimensions can be relevant (even if for now it's mostly the vertical dimension).

Oh I was imagining apps would be measuring "full width" through just width: 100%, which should still work in that case?
There are several mechanisms for responsive design (for example media queries according to the window size or container size) - so a lot of the time it's not just about setting the width, but also responding to the dimensions and changing the entire style according to the size of the app.

So all in all I think that keeping onsizechange and having the Viewport defining dim/maxDim like you proposed (so that the apps will know what they can control and what is fixed) - is flexible enough for our use cases.

@idosal
Copy link
Collaborator

idosal commented Dec 16, 2025

Thanks @martinalong!
I agree with @liady's take. It's critical that the spec remains extensible and accounts for different hosts.

@martinalong
Copy link
Collaborator Author

Yep what you said is my understanding of it as well! I'll make the updates

@martinalong martinalong force-pushed the martinalong/mcp-apps/max-height-only branch from 189f525 to c47b970 Compare December 17, 2025 05:53
@martinalong martinalong requested review from idosal and liady December 17, 2025 06:08
@martinalong
Copy link
Collaborator Author

PTAL @liady @idosal!

@martinalong martinalong changed the title [MCP Apps] Replace viewport with maxHeight [MCP Apps] Update viewport type Dec 17, 2025
// Handle height
if ("height" in viewport) {
// Fixed height: fill the container
document.body.style.height = "100%";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure we need to add reference implementations here, or just let apps handle it their own way like they handle any browser window. (some apps might want scrolling content like a scrolling carousel).
If we do want - we should make some adjustments -

  1. Use document.documentElement everywhere instead of document.body - since this is the element that actually takes the iframe size. It also fixes issues if the HTML has paddings, the body has margins, etc.
  2. Use vh/vw units since for the app the iframe is the actual viewport
  3. Clarify why we're limiting the app size - if we need the app to at least fill the container it might need to be style.minHeight/minWidth. If we want to force the app to have fixed size no matter what then .width is ok.
    Again - we can also leave it to the internal implementation of the app.

Copy link
Collaborator Author

@martinalong martinalong Dec 18, 2025

Choose a reason for hiding this comment

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

some apps might want scrolling content like a scrolling carousel

I think it's informative to have an example, even if that example doesn't cover all the ways you can use it!

But overall 1 and 2 sound good to me! Will update

On the topic of minHeight: height/maxHeight to refer to the iframe height, not the app height. Apps can do whatever they want within that height (scroll or not)

@martinalong martinalong force-pushed the martinalong/mcp-apps/max-height-only branch from b35a4e2 to 010ff33 Compare December 18, 2025 05:34
width: number;
height: number;
/** Viewport width (if fixed). Only pass width or maxWidth, not both. */
width?: number;
Copy link
Collaborator Author

@martinalong martinalong Dec 18, 2025

Choose a reason for hiding this comment

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

@ochafik I realized that no matter what, we have to make this change (making these fields optional), which is is a minor breaking change

I don't think there's really a way around it if we want to adopt this new shape. Wdyt should be the plan here? I think we may as well just update it to the type i originally proposed and announce the next version will be a breaking change

@martinalong martinalong requested a review from liady December 18, 2025 05:46
@martinalong martinalong force-pushed the martinalong/mcp-apps/max-height-only branch from 96f017b to aed8cbe Compare December 18, 2025 05:53
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.

6 participants