vercel/ai · warning · Error

Invalid ui/request-display-mode params

Error message

Invalid ui/request-display-mode params

What it means

The bridge validates `ui/request-display-mode` requests and requires `params.mode` to be exactly one of `inline`, `fullscreen`, or `pip`. Any other value (or non-object params) is rejected before reaching the host's requestDisplayMode handler.

Source

Thrown at packages/react/src/mcp-apps/bridge.ts:116

    throw new Error(`Disallowed ui/open-link scheme: ${scheme}`);
  }

  return { url: params.url };
}

/**
 * Validates params for `ui/request-display-mode`.
 */
function assertDisplayModeParams(params: unknown): {
  mode: 'inline' | 'fullscreen' | 'pip';
} {
  if (
    !isJSONObject(params) ||
    (params.mode !== 'inline' &&
      params.mode !== 'fullscreen' &&
      params.mode !== 'pip')
  ) {
    throw new Error('Invalid ui/request-display-mode params');
  }
  return { mode: params.mode };
}

/**
 * Host-side JSON-RPC bridge for one MCP App iframe.
 *
 * It handles the MCP Apps initialization handshake, sends tool input/result
 * notifications to the iframe, and proxies allowed iframe requests through
 * host-provided callbacks.
 *
 * @example
 * ```ts
 * const bridge = new MCPAppBridge({
 *   targetWindow: iframe.contentWindow!,
 *   handlers: {
 *     allowedTools: ['refreshDashboardData'],
 *     callTool: params => client.callTool(params),

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Change the app to request only `inline`, `fullscreen`, or `pip`.
  2. Clamp/whitelist the computed mode value app-side before sending.
  3. Check the MCP Apps spec version used by the app for supported display modes.
  4. Inspect the rejected request via the host `onError` callback to see the actual mode value.

Example fix

// before
requestDisplayMode({ mode: 'maximized' })
// after
requestDisplayMode({ mode: 'fullscreen' })
Defensive patterns

Strategy: validation

Validate before calling

const MODES = ['inline', 'fullscreen', 'pip'] as const;
type Mode = typeof MODES[number];
function requestMode(mode: string): mode is Mode {
  return (MODES as readonly string[]).includes(mode);
}
// before requesting:
if (!requestMode(desiredMode)) throw new Error(`Unsupported display mode: ${desiredMode}`);

Type guard

function isDisplayMode(v: unknown): v is 'inline' | 'fullscreen' | 'pip' {
  return v === 'inline' || v === 'fullscreen' || v === 'pip';
}

Try / catch

try {
  await requestDisplayMode({ mode });
} catch (error) {
  if (error instanceof Error && error.message === 'Invalid ui/request-display-mode params') {
    console.error(`mode must be inline|fullscreen|pip, got: ${mode}`);
  }
}

Prevention

When it happens

Trigger: The iframe posts `ui/request-display-mode` with `mode` set to something like `"maximized"`, `"window"`, `"popup"`, or with params missing/`mode` undefined.

Common situations: App written against an older or different MCP Apps draft that allowed other display modes; typo in the mode string; mode value dynamically computed and falling through to undefined.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/89c72d01b370a660. Report an issue: GitHub.