-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add MCP Apps support to Inspector #1044
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Fixed AppRenderer useEffect dependency array to include resourceContent This ensures the component re-evaluates when resource content arrives - Added detailed console logging throughout the app lifecycle: * Resource fetch and response tracking in App.tsx * Setup conditions and AppBridge creation in AppRenderer.tsx * HTML parsing and iframe rendering steps * PostMessageTransport and AppBridge connection status * App tool filtering and selection in AppsTab.tsx - Refactored AppsTab selectedTool rendering for better tracking The issue was that resourceContent prop updates weren't triggering the AppRenderer setup effect. Now the effect properly responds to both resourceUri and resourceContent changes. Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
The app was getting stuck on 'Loading MCP App...' because the iframe was hidden (display: none) until the oninitialized event fired. However, the PostMessage handshake requires the iframe to be visible to complete. This fix: - Sets loading to false immediately after writing HTML to the iframe - Makes the iframe visible before establishing PostMessage transport - Allows the AppBridge initialization handshake to complete successfully - Removes redundant setLoading(false) from oninitialized callback The iframe is now visible and ready for PostMessage communication before the AppBridge connect() call, enabling proper initialization. Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
The AppRenderer was incorrectly checking for a 'type' field in resource contents, but TextResourceContents objects only have uri, mimeType, and text fields according to the MCP specification. Fixed by checking for the presence of the 'text' field directly instead of checking a non-existent 'type' field. This allows the HTML content to be properly extracted and rendered in the iframe. Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
- Add tests for AppsTab component (13 tests) - Add tests for AppRenderer component (17 tests) - Update jest.config.cjs to handle ES modules from @modelcontextprotocol/ext-apps - All 478 tests pass successfully Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
- Add AppsTab component for detecting and listing MCP apps - Add AppRenderer component with full AppBridge integration - Implement UI resource fetching and sandboxed iframe rendering - Add PostMessage transport for bidirectional JSON-RPC communication - Include comprehensive test coverage (30 new tests) - Auto-populate apps when tab becomes active - Support theme awareness and configurable permissions Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
olaservo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few suggestions.
I'm still testing with a few more servers too, since I still can't tell if some weirdness is due to the servers or the inspector yet. For example, some servers are rendering with a black background (this one) or just render a black rectangle for me (like this one). So far I think its the servers that need some adjustment?
It also looks like there are a lot of console.log statements, so I wasn't sure if we should keep all those as-is or if they were meant to be more temporary?
| // Create AppBridge with the MCP client | ||
| bridge = new AppBridge( | ||
| mcpClient, | ||
| { name: "MCP Inspector", version: "0.19.0" }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this version is hardcoded instead of matching the package version?
| }); | ||
| if (parsed.contents && Array.isArray(parsed.contents)) { | ||
| // MCP resource response format: TextResourceContents has uri, mimeType?, and text | ||
| const textContent = parsed.contents.find( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be checking for text/html mimeType explicitly?
| console.log("[AppRenderer] Iframe now visible, ready for PostMessage"); | ||
|
|
||
| // Wait for iframe to load | ||
| await new Promise<void>((resolve) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be a timeout here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're using iframe.contentWindow.addEventListener("load", () => resolve(), { once: true }); to wait for the contentWindow to load (if it is present).
| <div className="mt-6 border-t pt-6"> | ||
| <div className="flex items-center justify-between mb-4"> | ||
| <h3 className="text-xl font-semibold">{selectedTool.name}</h3> | ||
| <Button onClick={handleCloseApp} variant="ghost" size="sm"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| <Button onClick={handleCloseApp} variant="ghost" size="sm"> | |
| <Button onClick={handleCloseApp} variant="ghost" size="sm" aria-label="Close app"> |
@olaservo that's the cohort-heatmap-server, which was working for me in the screenshot and video above. I'm using Chrome on macOS. You?
I get the app rendering, and the scaling buttons are present, but it doesn't seem to load the data. When I run it in the ext-apps browser demo, I see the content...
I sort of thought they might be useful for a time, until we are certain everything is working properly. I can take them out. |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Some MCP servers return different data in structuredContent vs content fields. This change ensures that when structuredContent is present, it is used exclusively for display instead of showing both fields. Changes: - Modified ToolResults.tsx to only show content when structuredContent is absent - Removed unused checkContentCompatibility function - Updated test cases to reflect new behavior Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
This reverts commit 3b054b4. Claude did not do the right thing.
@cliffhall I'm using Chrome on Windows and have a dark system theme on, so I think that's why the heatmap hows with a dark theme. Otherwise I think that one is actually ok since the source code for that server seems to prefer the system theme.
Sure that makes sense! |


Summary
Implements complete MCP Apps support in the Inspector, enabling detection, listing, and interactive rendering of MCP apps with full bidirectional communication.
Implementation
New Components:
_meta.ui.resourceUrifieldFiles Added:
client/src/components/AppsTab.tsxclient/src/components/AppRenderer.tsxclient/src/components/__tests__/AppsTab.test.tsxclient/src/components/__tests__/AppRenderer.test.tsxFiles Modified:
client/src/App.tsx- Added Apps tab integration, auto-fetch logic, and resource wiringclient/package.json- Added@modelcontextprotocol/ext-apps^1.0.0dependencyclient/jest.config.cjs- Updated to handle ES modules from@modelcontextprotocol/ext-appsKey Features
✅ App Detection - Automatically identifies tools with MCP Apps extension metadata
✅ Auto-population - Tools list loads when Apps tab becomes active
✅ Resource Fetching - Fetches
ui://resources via MCP protocol✅ AppBridge Integration - Proxies tools, resources, and prompts to MCP server
✅ PostMessage Transport - Secure JSON-RPC communication between iframe and host
✅ Sandboxed Rendering - Secure iframe rendering with configurable permissions
✅ Theme Support - Passes Inspector's light/dark theme to apps
✅ Error Handling - Comprehensive error states and user feedback
Architecture
Test Coverage
AppsTab Tests (13 tests):
AppRenderer Tests (17 tests):
All 478 tests pass successfully
Quality Checks
Closes #1041
Video
Screen.Recording.2026-01-26.at.5.30.06.PM.mov
Screenshot
Generated with Claude Code