{"record":{"id":"89c72d01b370a660","repo":"vercel/ai","slug":"invalid-ui-request-display-mode-params","errorCode":null,"errorMessage":"Invalid ui/request-display-mode params","messagePattern":"Invalid ui/request-display-mode params","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/react/src/mcp-apps/bridge.ts","lineNumber":116,"sourceCode":"    throw new Error(`Disallowed ui/open-link scheme: ${scheme}`);\n  }\n\n  return { url: params.url };\n}\n\n/**\n * Validates params for `ui/request-display-mode`.\n */\nfunction assertDisplayModeParams(params: unknown): {\n  mode: 'inline' | 'fullscreen' | 'pip';\n} {\n  if (\n    !isJSONObject(params) ||\n    (params.mode !== 'inline' &&\n      params.mode !== 'fullscreen' &&\n      params.mode !== 'pip')\n  ) {\n    throw new Error('Invalid ui/request-display-mode params');\n  }\n  return { mode: params.mode };\n}\n\n/**\n * Host-side JSON-RPC bridge for one MCP App iframe.\n *\n * It handles the MCP Apps initialization handshake, sends tool input/result\n * notifications to the iframe, and proxies allowed iframe requests through\n * host-provided callbacks.\n *\n * @example\n * ```ts\n * const bridge = new MCPAppBridge({\n *   targetWindow: iframe.contentWindow!,\n *   handlers: {\n *     allowedTools: ['refreshDashboardData'],\n *     callTool: params => client.callTool(params),","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/react/src/mcp-apps/bridge.ts#L98-L134","documentation":"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.","triggerScenarios":"The iframe posts `ui/request-display-mode` with `mode` set to something like `\"maximized\"`, `\"window\"`, `\"popup\"`, or with params missing/`mode` undefined.","commonSituations":"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.","solutions":["Change the app to request only `inline`, `fullscreen`, or `pip`.","Clamp/whitelist the computed mode value app-side before sending.","Check the MCP Apps spec version used by the app for supported display modes.","Inspect the rejected request via the host `onError` callback to see the actual mode value."],"exampleFix":"// before\nrequestDisplayMode({ mode: 'maximized' })\n// after\nrequestDisplayMode({ mode: 'fullscreen' })","handlingStrategy":"validation","validationCode":"const MODES = ['inline', 'fullscreen', 'pip'] as const;\ntype Mode = typeof MODES[number];\nfunction requestMode(mode: string): mode is Mode {\n  return (MODES as readonly string[]).includes(mode);\n}\n// before requesting:\nif (!requestMode(desiredMode)) throw new Error(`Unsupported display mode: ${desiredMode}`);","typeGuard":"function isDisplayMode(v: unknown): v is 'inline' | 'fullscreen' | 'pip' {\n  return v === 'inline' || v === 'fullscreen' || v === 'pip';\n}","tryCatchPattern":"try {\n  await requestDisplayMode({ mode });\n} catch (error) {\n  if (error instanceof Error && error.message === 'Invalid ui/request-display-mode params') {\n    console.error(`mode must be inline|fullscreen|pip, got: ${mode}`);\n  }\n}","preventionTips":["Only use the literal mode values inline, fullscreen, pip.","Whitelist clamp dynamically computed modes before sending.","Check the MCP Apps spec version supported by the host for valid modes.","Type the mode as a union type app-side so invalid values fail at compile time."],"tags":["mcp-apps","validation","iframe","display"],"backgroundTag":"invalid-rpc-params","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}