Skip to content

Claude MCP App renders blank (works in Inspector) #615

Closed

Description

@Vamshidhar-0814

Summary

A remote MCP App renders correctly in MCP Inspector but appears blank in claude.ai, despite successful tool execution and resource retrieval.


Expected Behavior

When invoking an MCP tool with a ui:// resource, Claude should render the returned HTML app inside the inline app container.


Actual Behavior

In claude.ai:

  • Tool executes successfully
  • resources/read is called successfully
  • Claude shows UI indicating the app is opened
  • App container remains blank (no HTML rendered)

In MCP Inspector:

  • Same MCP server
  • Same ui:// resource
  • App renders correctly

Reproduction Steps

  1. Start MCP server exposed via HTTPS (ngrok)

  2. Connect to claude.ai

  3. Invoke tool:

    open_visual_search_app
    
  4. Observe:

    • Claude shows tool response
    • “Open Visual Search App” appears
    • App container opens
    • Container is blank
  5. Open MCP Inspector:

    npx @modelcontextprotocol/inspector
  6. Connect to same MCP endpoint

  7. Navigate to Apps tab

  8. Open open_visual_search_app

  9. Observe:

    • App renders correctly

MCP Configuration

  • Transport: Streamable HTTP

  • Server: Remote (ngrok HTTPS)

  • Tool name: open_visual_search_app

  • Resource URI:

    ui://visual-search/view.html
    

resources/read Response

  • MIME type:

    text/html;profile=mcp-app
    
  • Includes _meta.ui:

    • CSP (connectDomains, resourceDomains)
    • Claude sandbox domain (*.claudemcpcontent.com)
  • HTML:

    • Fully inline
    • No external assets required
    • Valid static content renders in Inspector

Minimal Repro

Even with minimal HTML:

<!DOCTYPE html>
<html>
  <body>
    <h1>HELLO MCP</h1>
  </body>
</html>
  • Inspector: renders
  • Claude: blank

Key Observation

The exact same ui:// resource renders correctly in MCP Inspector but not in claude.ai.

This suggests:

  • MCP server implementation is correct
  • Resource format is valid
  • Issue is specific to Claude’s MCP app rendering/runtime

Debugging Performed

  • Verified /mcp endpoint connectivity

  • Verified tools/call works

  • Verified resources/read returns correct content

  • Verified MIME type is text/html;profile=mcp-app

  • Tested with:

    • full app
    • minimal static HTML
  • Confirmed rendering works in MCP Inspector


Screenshots

Claude (blank app container):

Image

MCP Inspector (correct rendering):

Image

Impact

Blocks use of MCP Apps UI in claude.ai despite valid implementation.
Forces fallback to non-UI tool flows.


Question

  • Are remote MCP Apps fully supported in claude.ai?
  • Are there additional constraints required for rendering ui:// resources?
  • Is this a known issue with the Claude MCP app host?

Additional Context

This appears similar to cases where:

resources/read succeeds but the app iframe/container fails to mount or render the returned HTML.

Activity

  1. iraritchiemeek commented on Apr 20, 2026

    @iraritchiemeek

    @Vamshidhar-0814 It's not possible to debug this without seeing your actual codebase.
    I suggest opening claude in browser (not the desktop app) and checking the network tab & console logs for errors. There may be an issue the bundle being sent to Claude.
    Also, you need a cache-busting version suffix on your UI URI (ui://@v2). After each deployment you will need to disconnect and re-connect your MCP server (or connector) in claude to ensure is not using a cached version of you app.

  2. ochafik commented on Apr 21, 2026

    @ochafik
    Contributor

    Thanks @iraritchiemeek for the debugging tips.

    @Vamshidhar-0814 — the bare-<h1> minimal repro is the key clue: a View with no SDK at all is expected to render blank in Claude.ai. The host keeps the iframe hidden / zero-height until it receives the ui/initialize handshake and a size notification from the SDK's App.connect(). Inspector gives the iframe a fixed container so it shows regardless, which is why it "works" there. So the bare-h1 case is working as designed — the SDK handshake is required.

    For your actual visual-search app: if it does call App.connect() and still renders blank, the next release (#623) adds a console.error (or a thrown error if you pass strict: true to new App(...)) when the app calls callServerTool/sendMessage/etc. before connect() has resolved — that's a common cause of this symptom. Worth retesting with that once it ships.

    If neither applies, the devtools steps above (cache-bust the resource URI, inspect the iframe console) are the next move.

  3. ochafik commented on Apr 21, 2026

    @ochafik
    Contributor

    Closing for now since the bare-HTML repro is expected behavior — Claude.ai requires the App.connect() handshake before it will size/show the iframe.

    For your real app, please verify it does await app.connect(transport) before any other SDK calls, and try the next release with new App(appInfo, capabilities, { strict: true }) — that will throw (rather than just print console warnings) if anything is called too early.

    Happy to reopen if it still renders blank after that — just drop the iframe's devtools console output here and we'll dig in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions