Repository navigation
Claude MCP App renders blank (works in Inspector) #615
Description
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/readis 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
-
Start MCP server exposed via HTTPS (ngrok)
-
Connect to claude.ai
-
Invoke tool:
open_visual_search_app -
Observe:
- Claude shows tool response
- “Open Visual Search App” appears
- App container opens
- Container is blank
-
Open MCP Inspector:
npx @modelcontextprotocol/inspector
-
Connect to same MCP endpoint
-
Navigate to Apps tab
-
Open
open_visual_search_app -
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)
- CSP (
-
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
/mcpendpoint connectivity -
Verified
tools/callworks -
Verified
resources/readreturns 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):
MCP Inspector (correct rendering):
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/readsucceeds but the app iframe/container fails to mount or render the returned HTML.
Activity
iraritchiemeek commentedon Apr 20, 2026
@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.
ochafik commentedon Apr 21, 2026
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 theui/initializehandshake and a size notification from the SDK'sApp.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 aconsole.error(or a thrown error if you passstrict: truetonew App(...)) when the app callscallServerTool/sendMessage/etc. beforeconnect()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.
ochafik commentedon Apr 21, 2026
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 withnew 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.