-
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?
@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! |
|
@cliffhall did you try the React Renderer for hosts? It should be plug and play and has most of the spec implementations needed by hosts etc. It is what I have been using at Postman (soon to be used by MCPJam and Goose) Let me know if you want to take a look https://github.com/MCP-UI-Org/mcp-ui/blob/main/sdks/typescript/client/src/components/AppRenderer.tsx it is released on the latest version of the mcp-ui package so you can just npm install it |
This commit implements the integration of `@mcp-ui/client` to handle the
rendering of Model Context Protocol (MCP) applications within the inspector.
It includes refactoring the rendering logic, improving resource fetching
in the main application state, and setting up a secure sandbox environment.
Changes per file:
- client/package.json:
- Added `@mcp-ui/client` as a dependency.
- client/src/components/AppRenderer.tsx:
- Refactored to use `McpUiAppRenderer` from `@mcp-ui/client`.
- Implemented HTML parsing logic for MCP resource responses.
- Configured host context (theme) and sandbox URL for the renderer.
- Replaced iframe-based manual rendering with the official component.
- client/src/App.tsx:
- Added `fetchingResources` state to prevent duplicate concurrent resource requests.
- Enhanced `readResource` with better error handling and state tracking.
- Optimized resource content mapping to better support application state.
- client/src/components/AppsTab.tsx:
- Updated to use `getToolUiResourceUri` utility from `@modelcontextprotocol/ext-apps`
instead of manual metadata property access.
- Simplified tool filtering and selection logic.
- client/public/sandbox_proxy.html:
- Added a sandbox proxy page to facilitate secure communication between
the inspector and the rendered MCP applications.
- client/bin/client.js:
- Added server rewrites to ensure `sandbox_proxy.html` is served correctly.
- Implemented specific `Cache-Control` headers for `sandbox_proxy.html` to
prevent stale cached versions.
- client/vite.config.ts:
- Explicitly configured `publicDir: "public"` to ensure the sandbox proxy
is included in the build output.
- client/src/components/__tests__/AppRenderer.test.tsx:
- Updated tests to mock the new `@mcp-ui/client` component.
- Adjusted assertions to verify correct props are passed to the renderer.
- Enhanced mock MCP client to include required methods like `getServerCapabilities`.
…scripting Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
- npm install - npm audit fix
…scripting Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…scripting Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Ola Hungerford <olahungerford@gmail.com>
…app rendering. Will sort out what best practices for this HTML is later
In AppsTab.tsx
- Add app window
- when an app is selected,
- show input form for apps that have an input schema
- button shows app
- if app is shown, show maximize button
- if maximized,
- show minimize button
- hide app list
* In AppsTab.test.tsx
- test new layout and controls
* In AppRenderer.tsx
- accept toolInput
- pass to McpUiAppRenderer
… show the form and the "back to form" button when showing the app. * In AppsTab.test.tsx - test new behavior * In ListPane.tsx - remove the Clear button * In ListPane.test.tsx - remove test for clear button
Quick update
|
- remove onReadResource and resourceContent, not needed since mcpClient is being passed * In App.tsx and AppsTab.tsx, - remove the passing of these variables
- remove tests that fail after having removed onReadResource and resourceContent
…instead of the webclient server. * In App.tsx - pass the path to the sandbox endpoint on the proxy to the AppsTab * In AppsTab.tsx - accept the sandboxPath property and pass it to the AppRenderer * In AppRenderer.tsx - accept the sandboxPath property and pass it to the McpUiAppRenderer * In client.js - remove the rewrite and header config for sandbox_proxy.html * In server/src/index.ts - add a /sandbox endpoint that reads and returns the sandbox_proxy.html file with no-cache header * In server/package.json - add shx for cross-platform copy function - in build script, copy static folder to build folder * Moved sandbox_proxy.html from client/public to server/static
- return to original state
- return to original state
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
| className="flex-1 border rounded overflow-hidden" | ||
| style={{ minHeight: "400px" }} | ||
| > | ||
| <McpUiAppRenderer |
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.
@cliffhall I think the only thing missing is wiring the callbacks for the actions. Here's what we need to pass:
// log the ui event and open the link in a new tab
onOpenLink={async ({ url }) => {
if (url.startsWith('https://') || url.startsWith('http://')) {
window.open(url);
}
}}
// log the UI event (maybe logging it somehwere in the inspector so the message is visible and acknowledged?
onMessage={async (params) => {
console.log('Message from tool UI:', params);
return { isError: false };
}}
/** Handler for logging messages from the guest UI */
// this one should be sent to the inspector's notifications list
onLoggingMessage?: (params: LoggingMessageNotification['params']) => void;
You can test all this functionality with the ext-apps/react-server demo that has the get time to test tool calling, the send message, send notification etc.
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.
WIP. Added onOpenLink handler. Adding video to PR.
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.
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.
Still need to handle logging messages
- add open link handler that handles link requests from the UI. Makes sure that the URL starts with http or https
- refactor to match [basic-host](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-host) example - creates an nested iframe for security. - in this implementation, for simplicity the sandbox.ts is inlined in sandbox_proxy.html as javascript
- add support for handling McpUiMessageRequest messages from the UI - show message in a toast



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.tsxserver/static/sandbox_proxy.html- sandbox proxy similar to In sandbox_proxy.htmlsandbox.tsis inlined insandbox_proxy.htmlas javascript example. Served on a different port via the proxy server.Files Modified:
client/src/App.tsx- Added Apps tab integration, auto-fetch logic, and resource wiringclient/src/components/ListPane.tsx- Only show Clear button if aclearItemsfunction was passed inclient/src/components/__tests__/ListPane.test.tsx- Make sure Clear button is not shown if noclearItemsfunction was passed inclient/src/components/__tests__/AuthDebugger.test.tsx- Fix @ imports that were not resolving to be relativeclient/package.json- Added@modelcontextprotocol/ext-apps^1.0.0,@mcp-ui/client^6.0.0dependenciesclient/jest.config.cjs- Updated to handle ES modules from@modelcontextprotocol/ext-appsserver/src/index.ts- add/sandboxendpoint which reads and servesstatic/sandbox_proxy.htmlwith no-cache header and rate limitingserver/package.json- Addedshx^0.3.4andexpress-rate-limit:^8.2.1dependencies. Copy static folder to build in build script.Key Features
✅ App Detection - Automatically identifies tools with MCP Apps extension metadata
✅ Auto-population - Apps list loads when Apps tab becomes active
✅ Resource Fetching - Fetches
ui://resources via MCP protocol✅ MCP-UI AppRenderer Integration - Renders the app, given an MCP client, tool name, resource content, and host context (custom settings like theme)
✅ 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 (18 tests):
AppRenderer Tests (8 tests):
All 477 tests pass successfully
Quality Checks
Closes #1041
Videos
Map Server
map.mov
Cohort Heatmap Server
cohort.mov
Wiki Explorer Server - Navigation
wiki.mov
Wiki Explorer Server - Open Links
wiki-open-link.mov
Generated with Claude Code
Fixed with Junie and plenty of old-school hacking.