Skip to content
Closed
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
42 changes: 14 additions & 28 deletions client/src/components/chat-v2/thread/mcp-apps-renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ export function MCPAppsRenderer({
[isPlaygroundActive, playgroundSafeAreaInsets],
);

// Get device type and custom viewport from playground store for platform/viewport derivation (SEP-1865)
// Get device type and custom viewport from playground store for platform/containerDimensions derivation (SEP-1865)
const playgroundDeviceType = useUIPlaygroundStore((s) => s.deviceType);
const customViewport = useUIPlaygroundStore((s) => s.customViewport);

Expand All @@ -234,23 +234,6 @@ export function MCPAppsRenderer({
}
}, [isPlaygroundActive, playgroundDeviceType]);

// Derive viewport dimensions from device type (using shared config + custom viewport)
const viewportWidth = useMemo(() => {
if (!isPlaygroundActive) return 400;
if (playgroundDeviceType === "custom") {
return customViewport.width;
}
return DEVICE_VIEWPORT_CONFIGS[playgroundDeviceType].width;
}, [isPlaygroundActive, playgroundDeviceType, customViewport]);

const viewportHeight = useMemo(() => {
if (!isPlaygroundActive) return 400;
if (playgroundDeviceType === "custom") {
return customViewport.height;
}
return DEVICE_VIEWPORT_CONFIGS[playgroundDeviceType].height;
}, [isPlaygroundActive, playgroundDeviceType, customViewport]);

// Display mode: controlled (via props) or uncontrolled (internal state)
const isControlled = displayModeProp !== undefined;
const [internalDisplayMode, setInternalDisplayMode] = useState<DisplayMode>(
Expand Down Expand Up @@ -289,7 +272,7 @@ export function MCPAppsRenderer({
],
);

// maxHeight is sent to guest UI as part of viewport info (SEP-1865 protocol)
// maxHeight is sent to guest UI as part of containerDimensions (SEP-1865 protocol)
// Note: We no longer use this to clamp resize, but apps may use it for layout decisions
const maxHeight = useMemo(() => {
if (!isPlaygroundActive) return 800;
Expand Down Expand Up @@ -333,7 +316,8 @@ export function MCPAppsRenderer({
const onRequestPipRef = useRef(onRequestPip);
const onExitPipRef = useRef(onExitPip);
const setDisplayModeRef = useRef(setDisplayMode);
const viewportWidthRef = useRef(viewportWidth);
const isPlaygroundActiveRef = useRef(isPlaygroundActive);
const playgroundDeviceTypeRef = useRef(playgroundDeviceType);
const effectiveDisplayModeRef = useRef(effectiveDisplayMode);
const serverIdRef = useRef(serverId);
const toolCallIdRef = useRef(toolCallId);
Expand Down Expand Up @@ -522,9 +506,7 @@ export function MCPAppsRenderer({
theme: themeMode,
displayMode: effectiveDisplayMode,
availableDisplayModes: ["inline", "pip", "fullscreen"],
viewport: {
width: viewportWidth,
height: viewportHeight,
containerDimensions: {
maxHeight,
maxWidth,
},
Expand All @@ -551,8 +533,6 @@ export function MCPAppsRenderer({
[
themeMode,
effectiveDisplayMode,
viewportWidth,
viewportHeight,
maxHeight,
maxWidth,
locale,
Expand All @@ -576,7 +556,8 @@ export function MCPAppsRenderer({
onRequestPipRef.current = onRequestPip;
onExitPipRef.current = onExitPip;
setDisplayModeRef.current = setDisplayMode;
viewportWidthRef.current = viewportWidth;
isPlaygroundActiveRef.current = isPlaygroundActive;
playgroundDeviceTypeRef.current = playgroundDeviceType;
effectiveDisplayModeRef.current = effectiveDisplayMode;
serverIdRef.current = serverId;
toolCallIdRef.current = toolCallId;
Expand All @@ -587,7 +568,8 @@ export function MCPAppsRenderer({
onRequestPip,
onExitPip,
setDisplayMode,
viewportWidth,
isPlaygroundActive,
playgroundDeviceType,
effectiveDisplayMode,
serverId,
toolCallId,
Expand Down Expand Up @@ -746,7 +728,11 @@ export function MCPAppsRenderer({

bridge.onrequestdisplaymode = async ({ mode }) => {
const requestedMode = mode ?? "inline";
const isMobile = viewportWidthRef.current < 768;
// Use device type for mobile detection (defaults to mobile-like behavior when not in playground)
const isMobile = isPlaygroundActiveRef.current
? playgroundDeviceTypeRef.current === "mobile" ||
playgroundDeviceTypeRef.current === "tablet"
: true;
Comment on lines +731 to +735
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Search for viewport or mobile detection patterns in the file
cd client/src/components/chat-v2/thread && cat -n mcp-apps-renderer.tsx | sed -n '700,770p'

Repository: MCPJam/inspector

Length of output: 2978


🏁 Script executed:

#!/bin/bash

# Search for previous viewport/mobile detection in the entire codebase
rg -nP --type=ts --type=tsx 'viewportWidth|viewport.*width|isMobile' --max-count=20

Repository: MCPJam/inspector

Length of output: 87


🏁 Script executed:

#!/bin/bash

# Search for mobile detection patterns without file type restrictions
rg -n 'isMobile|viewport.*width|device.*type' client/src/components/chat-v2/thread/mcp-apps-renderer.tsx -A 3 -B 3

Repository: MCPJam/inspector

Length of output: 2221


🏁 Script executed:

#!/bin/bash

# Search for previous implementations or related device detection
rg -n 'playgroundDeviceType|isPlaygroundActive' client/src/components/chat-v2/thread/ -A 2 -B 2

Repository: MCPJam/inspector

Length of output: 14943


🏁 Script executed:

#!/bin/bash

# Look for viewport-based mobile detection anywhere in the codebase
rg -n 'window\.innerWidth|innerWidth.*mobile|viewport.*mobile' client/ --max-count=15

Repository: MCPJam/inspector

Length of output: 460


🏁 Script executed:

#!/bin/bash

# Check git history for this specific section
git log -p --all -S 'isMobile = isPlaygroundActiveRef' -- client/src/components/chat-v2/thread/mcp-apps-renderer.tsx 2>/dev/null | head -100

Repository: MCPJam/inspector

Length of output: 42


Clarify intent of mobile-default behavior in production.

Line 735 defaults isMobile to true outside the playground, converting all PiP requests to fullscreen in production. While the comment indicates this is intentional ("defaults to mobile-like behavior when not in playground"), this differs from viewport-based detection used elsewhere (e.g., chatgpt-app-renderer.tsx uses getDeviceType(), and the platform variable returns "web" in production). Confirm whether the hardcoded true is the desired behavior or if desktop device detection should be used instead.

🤖 Prompt for AI Agents
In @client/src/components/chat-v2/thread/mcp-apps-renderer.tsx around lines 731
- 735, The current logic sets isMobile to true when not in playground, forcing
PiP -> fullscreen in production; instead, update the fallback to use the app's
device/platform detection (e.g., call getDeviceType() or use the existing
platform variable) so production behavior matches other renderers: replace the
hardcoded true in the ternary with a runtime device check (e.g., treat
mobile/tablet as mobile) and keep isPlaygroundActiveRef.current handling
unchanged; reference isPlaygroundActiveRef, playgroundDeviceTypeRef and the
isMobile variable when making the change.

Copy link

Choose a reason for hiding this comment

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

Custom viewport mobile detection ignores actual width

Medium Severity

The mobile detection logic for onrequestdisplaymode was changed from checking viewport width (viewportWidthRef.current < 768) to checking device type names. However, the "custom" device type case is not handled - when a user configures a custom viewport with a narrow width (e.g., 400px), it would previously have pip mode automatically converted to fullscreen (treating it as mobile), but now it won't since "custom" is not included in the device type check. This could cause pip mode to be used on inappropriately narrow custom viewports.

Fix in Cursor Fix in Web

const actualMode: DisplayMode =
isMobile && requestedMode === "pip" ? "fullscreen" : requestedMode;

Expand Down