vercel/ai · error · Error

MCP App resource not found in read result: ${uri}

Error message

MCP App resource not found in read result: ${uri}

What it means

Thrown by getMCPAppResourceFromReadResult after calling resources/read on an MCP App UI resource: the result contents array contained no entry whose uri matches the requested uri. The read succeeded at the transport level, but the server did not return the expected resource content for that exact URI.

Source

Thrown at packages/mcp/src/tool/mcp-apps.ts:240

        .filter((uri): uri is string => uri != null),
    ),
  ];
}

/**
 * Extracts app HTML and rendering metadata from a `resources/read` result.
 */
export function getMCPAppResourceFromReadResult({
  uri,
  resource,
}: {
  uri: string;
  resource: ReadResourceResult;
}): MCPAppResource {
  const content = resource.contents.find(content => content.uri === uri);

  if (content == null) {
    throw new Error(`MCP App resource not found in read result: ${uri}`);
  }

  if (content.mimeType !== MCP_APP_MIME_TYPE) {
    throw new Error(
      `Unsupported MCP App resource MIME type: ${content.mimeType}`,
    );
  }

  const html =
    'text' in content && typeof content.text === 'string'
      ? content.text
      : 'blob' in content && typeof content.blob === 'string'
        ? new TextDecoder().decode(convertBase64ToUint8Array(content.blob))
        : undefined;

  if (html == null) {
    throw new Error(`Unsupported MCP App resource content format: ${uri}`);
  }

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Fix the MCP server's resources/read handler to return a contents entry whose uri exactly equals the requested uri.
  2. Verify the resource is registered (resources/list) under the exact uri being read.
  3. Check for URI normalization mismatches (encoding, trailing slash, case) between client and server.
  4. If the server intentionally redirects/renames, return the resource under the originally requested uri instead of a substituted one.

Example fix

// before (server read handler)
return { contents: [{ uri: 'ui://server/app.html.js', mimeType: 'text/html', text }] };
// after
return { contents: [{ uri: requestedUri, mimeType: 'text/html', text }] };
Defensive patterns

Strategy: try-catch

Validate before calling

const listed = await client.listResources();
if (!listed.resources.some(r => r.uri === uri)) {
  throw new Error(`Server does not expose resource ${uri}; check resources/list`);
}

Try / catch

let resource;
try {
  resource = await readMCPAppResource({ client, uri });
} catch (e) {
  if (e instanceof Error && e.message.startsWith('MCP App resource not found in read result')) {
    console.error(`MCP server returned no content for ${uri}; verify resources/read handler and URI match`);
    throw e;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling readMCPAppResource (or accessing an MCP App's resource) for a uri where the MCP server's read handler returns contents with a different/normalized uri, an empty contents array, or content for a substituted URI.

Common situations: MCP server registering the resource under one ui:// URI but returning contents with a rewritten or relative uri; server bugs where the read handler returns an empty contents array; URI string mismatches from trailing slashes, encoding, or case differences.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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