{"record":{"id":"a8448714a1a66ce9","repo":"vercel/ai","slug":"resources-read-is-limited-to-ui-resources-pa","errorCode":null,"errorMessage":"resources/read is limited to ui:// resources: ${params.uri}","messagePattern":"resources/read is limited to ui:// resources: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react/src/mcp-apps/bridge.ts","lineNumber":74,"sourceCode":"  if (!isJSONObject(params) || typeof params.name !== 'string') {\n    throw new Error('Invalid tools/call params');\n  }\n\n  return {\n    name: params.name,\n    arguments: isJSONObject(params.arguments) ? params.arguments : undefined,\n  };\n}\n\n/**\n * Validates `resources/read` params and limits reads to `ui://` app resources.\n */\nfunction assertResourceReadParams(params: unknown): { uri: string } {\n  if (!isJSONObject(params) || typeof params.uri !== 'string') {\n    throw new Error('Invalid resources/read params');\n  }\n  if (!params.uri.startsWith('ui://')) {\n    throw new Error(\n      `resources/read is limited to ui:// resources: ${params.uri}`,\n    );\n  }\n  return { uri: params.uri };\n}\n\n/**\n * Validates `ui/open-link` params and allows only `https:`/`http:`/`mailto:`\n * URLs.\n */\nfunction assertOpenLinkParams(params: unknown): { url: string } {\n  if (!isJSONObject(params) || typeof params.url !== 'string') {\n    throw new Error('Invalid ui/open-link params');\n  }\n\n  let scheme: string;\n  try {\n    scheme = new URL(params.url).protocol;","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/react/src/mcp-apps/bridge.ts#L56-L92","documentation":"This is a deliberate security restriction: the bridge only allows MCP App iframes to read `ui://` scheme resources via `resources/read`. Any other scheme (e.g. `https://`, `file://`) is rejected. This keeps untrusted app frames from exfiltrating or reading arbitrary server resources.","triggerScenarios":"The iframe calls `resources/read` with a valid string `uri` that does not start with `ui://`, e.g. `https://example.com/data` or `server://logs`.","commonSituations":"App tries to read regular MCP server resources that were never exposed for app use; developer expects all server resources to be readable from the iframe; migrating an existing MCP client integration that used `https://` or custom scheme URIs.","solutions":["Serve app-visible resources with a `ui://` URI so the iframe can read them.","If the host needs the app to access other data, expose it through an allow-listed tool via `tools/call` instead of resources/read.","Fetch non-ui resources on the host side and pass them to the iframe via tool results or `ui/update-model-context`.","Confirm the resource URI was not truncated or mis-prefixed by the app."],"exampleFix":"// before\nreadResource({ uri: 'https://cdn.example.com/widget.json' })\n// after\nreadResource({ uri: 'ui://widget/config' })","handlingStrategy":"validation","validationCode":"// app-side, before requesting:\nif (!uri.startsWith('ui://')) {\n  throw new Error(`App may only read ui:// resources, got: ${uri}`);\n}","typeGuard":"function isUiResourceUri(uri: string): boolean {\n  return uri.startsWith('ui://');\n}","tryCatchPattern":"try {\n  await readResource({ uri });\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith('resources/read is limited to ui://')) {\n    // fall back to fetching the data through an allow-listed tool instead\n    await callTool({ name: 'getData', arguments: { uri } });\n  }\n}","preventionTips":["Publish app-facing resources only under `ui://` URIs.","Never expect `https://` or server-scheme resources to be readable from the iframe.","Route non-ui data needs through allow-listed tools.","Document the ui:// restriction in your app's resource naming conventions."],"tags":["mcp-apps","security","iframe","policy"],"backgroundTag":"resource-scheme-restricted","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}