Skip to content

feat: add mcp-ui support for Goose (backend logic, interfaces, frontend components)#3432

Closed
mgd1984 wants to merge 31 commits intoblock:feature/diff-viewer-sidecarfrom
mgd1984:feature/mcp-ui-integration
Closed

feat: add mcp-ui support for Goose (backend logic, interfaces, frontend components)#3432
mgd1984 wants to merge 31 commits intoblock:feature/diff-viewer-sidecarfrom
mgd1984:feature/mcp-ui-integration

Conversation

@mgd1984
Copy link

@mgd1984 mgd1984 commented Jul 15, 2025

Adds support for MCP-UI inside of Goose.

MCP-UI allows devs to "Build rich, dynamic user interfaces for their MCP applications with TypeScript SDKs that bring UI to AI interactions."

This PR introduces support for interactive UI components in the Goose framework by extending the Model Context Protocol (MCP) to include UI resource capabilities. The changes span the Rust backend and the TypeScript frontend, adding new capabilities for detecting, rendering, and handling UI resources while maintaining backward compatibility with existing functionality.

Note: MCP-UI is not currently part of the official MCP Specification (or any popular LLM/agent host...yet), but offers a compelling vision for how to extend its capabilities. As an extensible, open-source agent framework, Goose felt like a natural fit for MCP-UI. h/t @idosal

Backend Enhancements (Rust)

  • Added ui_capable_extensions to the ExtensionManager for tracking extensions that support UI resources and implemented methods to query and manage these capabilities (supports_ui, extension_supports_ui) in crates/goose/src/agents/extension_manager.rs. [1] [2] [3]
  • Introduced the UICapabilities struct in crates/mcp-core/src/protocol.rs to represent server-side UI resource support, including supported formats. This is integrated into ServerCapabilities. [1] [2]
  • Enhanced the McpClient in crates/mcp-client/src/client.rs to declare and detect UI capabilities during initialization and to handle UI-aware tool calls (call_tool_with_ui). [1] [2] [3] [4]

Frontend Enhancements (TypeScript)

  • Added the @mcp-ui/client library for rendering UI components in an iframe-based sandboxed environment. Updated package.json and package-lock.json to include this dependency. [1] [2]
  • Implemented a new UIResourceRenderer component in the frontend to detect and render UI resources, and modified the ToolCallWithResponse component to support UI-aware interactions.

Documentation

  • Created goose-mcp-ui-integration.md, a detailed document explaining the implementation, usage, and technical details of the MCP UI integration in Goose.

mgd1984 added 5 commits July 11, 2025 23:56
This commit implements comprehensive MCP UI capabilities, enabling Goose to render
interactive web components from MCP servers instead of static JSON responses.

Backend Changes:
- Enhanced MCP protocol with UICapabilities in mcp-core
- Added UI capability negotiation in mcp-client
- Implemented call_tool_with_ui() for UI-aware tool calls
- Added UI capability tracking in ExtensionManager
- Updated MCP server router to support UI capabilities

Frontend Changes:
- Added @mcp-ui/client dependency for standards-compliant UI rendering
- Created UIResourceRenderer component for interactive UI components
- Enhanced ToolCallWithResponse to detect and render UI resources
- Added proper Accept headers for content negotiation
- Updated message stream handling for UI resources

Features:
- Automatic UI capability detection and negotiation
- Interactive component rendering with @mcp-ui/client
- Backward compatibility with existing text/JSON responses
- Secure iframe-based UI rendering with proper sandboxing
- Support for all MCP UI resource types (remote-dom, HTML, etc.)

This enables rich, interactive experiences for MCP servers like phantasmo-toolkit
that can now display product catalogs, design previews, and interactive tools
directly in the Goose interface.
- Remove promotional language and emojis
- Make content more concise and technical
- Focus on implementation details rather than marketing claims
- Structure as proper technical documentation
- Fix TypeScript error in UIResourceRenderer
- Integrate UIResourceRenderer directly in main message body
- UI resources now appear as first-class message content, not just tool outputs
- Add proper type filtering for MessageContent to Content conversion
- UI resources render alongside text and images in assistant messages
- UI resources now only appear in main message body, not in tool results
- Prevents double rendering of interactive UI components
- Remove unused imports from ToolCallWithResponse
- UI resources are typically returned as tool results, not message content
- Check both message content and tool responses for UI resources
- Check tool responses from subsequent messages for tool calls in current message
- This ensures UI resources show up in main message body instead of tool results
@mgd1984
Copy link
Author

mgd1984 commented Jul 15, 2025

@iandouglas - thanks for organizing the Goose hacknight during Toronto Tech Week (and for the OpenRouter tokens!)
@angiejones - thanks for your talk at the MCP Developers Summit - love the passion, learned a ton.
@jackjackbits - I had to double-take when scanning merged-PRs for good examples and came across the token-counter component. So sick to see OG's shipping code (is it really you 👀)?

Would be great to have your esteemed human eyes review my AI-generated code. It's not fully baked yet, but I suspect the juice is worth the squeeze - https://x.com/tobi/status/1942628740909130167?s=61

🍻

mgd1984 added 2 commits July 15, 2025 12:34
- Added new entries to .gitignore for workspace and example files
- Updated Accept headers in SSE and StreamableHttp transport implementations to support application/vnd.mcp-ui.remote-dom+javascript for improved content negotiation
- Add @mcp-ui/client dependency for standards-compliant UI rendering
- Implement UIResourceRenderer component with smart mimeType detection
- Add UI resource detection and scanning logic in GooseMessage component
- Support Remote DOM, HTML, and URI-list resource types with proper iframe sandboxing
- Integrate UI actions (tool calls, intents, prompts) with Goose chat flow
- Add backend UI capabilities declaration in MCP client
- Maintain backward compatibility with existing text/image responses
- Clean up verbose debug logging while preserving essential diagnostics

Successfully renders interactive UI components from MCP servers like Phantasmo
product catalog with full user interaction support.
@michaelneale
Copy link
Collaborator

@mgd1984 would you mind updating to main - we now have the new GUI merged, and would be good to look at this next if possible - looks like small adjustments (was a big change, but hopefully still works!)

@michaelneale michaelneale self-assigned this Jul 16, 2025
@michaelneale
Copy link
Collaborator

@mgd1984 oh yeah - and that is really jack BTW - keen to see MCP UI happen!

Resolved merge conflicts in:
- ui/desktop/package.json: Merged dependencies from both branches, kept newer versions, added @mcp-ui/client
- ui/desktop/package-lock.json: Regenerated based on resolved package.json
- ui/desktop/src/components/GooseMessage.tsx: Kept UI resources rendering from feature branch
- ui/desktop/src/components/ToolCallWithResponse.tsx: Accepted upstream version

All merge conflicts have been resolved and the branch is ready for development.
@michaelneale
Copy link
Collaborator

@mgd1984 do you have a test server which shows some MCP ui that you use?

@mgd1984
Copy link
Author

mgd1984 commented Jul 17, 2025

@michaelneale - thanks for all the feedback. Much appreciated.

  • Pulled from & resolved conflicts with main
  • Stumbled upon @aharvard's PR integrate MCP UI #2948 - great discussion! Reviewed thread re: secure sandboxing via iframes - would appreciate input on whether the implementation here adequately addresses those concerns. I'd imagine it'll take some tweaking to get right (i.e. should UIResources be displayed in ToolCallWithResponse.tsx or GooseMessage.tsx?)
  • @idosal & @liady for visibility - thanks for the great libraries you guys are shipping. gitmcp is 🌌🧠 level stuff.
  • Note: given the recent version bumps to the Goose 1.1.0 and mcp-ui 4.1.4, the video below is out-of-date, as I attempt to incorporate the latest changes from the respective repos.
  • Will try to post an (updated) example (and test server) shortly 🤞
Goose.MCP-UI.Demo.remote-dom.mp4

@michaelneale
Copy link
Collaborator

yeah I am liking this - wonder how we can unify efforts with @aharvard?

I am also curious about the remoteDom script - and, crucially, component libraries. I expect in goose we will want to provide goose L&F components so when it uses that, it will show up nicely in goose?

Also - there is the concept of a visual "sidecar" in goose - I like the idea of MCP UI stuff showing in that side car (to the right) vs inline, but would need to play with it to see if it makes sense. The reason is - we can use that to extend goose itself for nice things like automatic graph/chart visualisation in parallel to the main chat output - but this is all really just ideas in heads so far, but lets keep going!

On security front: there is good discussion in that other PR, but I wonder if at a high level, given these are MCPs, the risk isn't from the MCP itself (if you are installing a bad MCP - you have already lost and would attack at execution level directly), perhaps the concern is more content injection/prompt injection (similarly in that case, there are a plenthora of tools for an injected prompt to try to use - this is another one of those but I am not sure it would be the worst one) so I am still confused as to what the security concern is in the case of a desktop implementation. I understand untrusted/browser would be very different though.

mgd1984 added 7 commits July 17, 2025 22:12
Upgrades @mcp-ui/client library to latest version for improved
UI resource rendering capabilities and bug fixes
- Add automatic UI resource detection in extension manager
- Implement content conversion for flattened UI resources
- Update provider formats to handle UI resource metadata
- Add UI-aware content processing in toolshim module

Enables backend to detect when interactive content has been
returned as text and converts it to proper UI resource format
Updates message content types to properly handle UI resource content,
enabling frontend components to detect and process interactive MCP UI resources
- Add comprehensive UI content detection in tool responses
- Implement automatic JSON parsing for structured UI resources
- Add JavaScript and HTML content recognition and rendering
- Support both direct UI resources and text-embedded UI content
- Provide robust fallback handling for various content formats

Enables automatic detection and rendering of interactive MCP UI content
from tool responses while maintaining backward compatibility

Note: Contains some eslint warnings for complex MCP protocol types
that will be addressed in follow-up commit
- Update context management to handle resource content types
- Enhance message streaming hooks for UI resource processing
- Add UI resource handling to GooseMessage component
- Update main.ts and index.html for UI rendering support

Provides necessary frontend infrastructure changes to support
MCP UI resource detection, processing, and rendering throughout
the application

Note: Contains eslint warnings for generated API types that
will be addressed in follow-up commit
- Replace 'any' type with proper interface for toolCall prop
- Add eslint-disable comments for complex MCP resource types
- Ensures clean linting while maintaining type safety

Resolves remaining linting issues from MCP-UI integration
- Fix mimeType typing in UIResourceRenderer to avoid ReactNode type errors
- Remove HTMLIFrameElement reference causing no-undef error
- Add eslint-disable comments for complex generated API types
- Ensure proper string conversion for display values

All linting and type checking now passes cleanly
@mgd1984
Copy link
Author

mgd1984 commented Jul 18, 2025

Love the sidecar concept (although, wingmate miiiight be a better name...jus' sayin' 😉). It feels similar to ChatGPT's Canvas or Claude's Artifact from a UX/UI perspective, both of which were both big usability improvements.

Catching up on @Kvadratni's #3493 to see how the SidecarLayout.tsx (WingmateLayout.tsx?) component could be leveraged as the target component to render mcp-ui resources in.

As for a "Goosified L&F" via remoteDom components, I found this on Shopify's remote-dom repo that seems like it might be helpful:

Adding custom elements

Now, just mirroring HTML strings isn’t very useful. Remote DOM works best when you define custom elements for the remote environment to render, which map to more complex, application-specific components on the host page. In fact, most of Remote DOM’s receiver APIs are geared towards you providing an allowlist of custom elements that the remote environment can render, which allows you to keep tight control over the visual appearance of the resulting output.

Remote DOM adopts the browser’s native API for defining custom elements to represent these “remote custom elements”. To make it easy to define custom elements that can communicate their changes to the host, @remote-dom/core provides the RemoteElement class. This class, which is a subclass of the browser’s HTMLElement, lets you define how properties, attributes, methods, and event listeners on the element should be transferred.

Further reading: https://shopify.engineering/remote-rendering-ui-extensibility

Update (April 9, 2024): we recently renamed remote-ui to Remote DOM. The new version of the library uses the full browser DOM API to manage UI components in an extension’s sandbox, instead of the DOM-like Remote Root object provided by remote-ui. Other aspects of our extension approach, including the RPC layer described below, continue to work similarly with the new library. We’ll be migrating UI extensions to use this more flexible DOM-based approach in a future API version.

mgd1984 and others added 5 commits July 18, 2025 00:37
This commit combines two major enhancements to create a unified interactive UI system:

🎯 MCP-UI Integration:
- Add @mcp-ui/client dependency for rendering interactive UI components
- Implement UIResourceRenderer component with secure iframe sandboxing
- Add UI resource detection and automatic UI/text content switching
- Update Accept headers to support MCP-UI content types (remote-dom, HTML, URI lists)
- Enhance Content Security Policy to allow iframe rendering with ui: scheme

🔧 Checkpoint & Sidecar System (from PR block#3493):
- Add SidecarLayout component for side-by-side UI rendering
- Implement checkpoint system with automatic file backup and versioning
- Add intelligent diff generation with file-type aware context sizing
- Create RestoreModal and MessageRestoreLink for file restoration workflow
- Add list_checkpoints and restore_checkpoint tools to developer router

🔗 Unified Architecture:
- Sidecar can display both diff content AND interactive MCP-UI components
- Enhanced message filtering to support tool request/response matching
- Resource type system handles both UI resources and checkpoint data
- Integrated debug logging for MCP-UI resource detection

This creates a comprehensive interactive AI agent interface that combines:
- Rich, interactive UI components via MCP-UI standard
- File versioning and diff management via checkpoint system
- Side-by-side layout for optimal workflow management

Resolves: Unifies MCP-UI integration efforts with checkpoint/sidecar functionality
@mgd1984 mgd1984 changed the base branch from main to feature/diff-viewer-sidecar July 18, 2025 15:08
mgd1984 and others added 7 commits July 18, 2025 11:30
🎯 Sidecar UI Resource Integration:
- Add UIResourceViewer component to SidecarLayout for seamless UI display
- Implement showUIResource/hideUIResource methods with proper state management
- Add placeholder cards in chat when UI resources move to sidecar
- Enhance iframe styling with full-space utilization and proper backgrounds

🔒 Type Safety & Stability:
- Add getResourceText and isTextResource helper functions
- Replace unsafe (resource as any).text patterns with proper type guards
- Fix infinite loop issues by replacing useEffect with useRef pattern
- Implement showInSidecarOnce helper to prevent resource re-rendering

🎨 UI/UX Improvements:
- Remove padding constraints limiting iframe display area
- Add absolute positioning for optimal space usage
- Inject CSS rules ensuring 100% iframe dimensions
- Improve visual feedback with 'Opened in side panel' indicators

⚡ Performance & Reliability:
- Eliminate continuous re-render cycles causing message streams
- Add proper resource content validation and error handling
- Optimize resource detection and processing workflow
- Resolved module refactoring from sub_recipe_execution_tool to subagent_execution_tool
- Fixed SidecarLayout implementation with Monaco diff viewer and UI resource support
- Updated CSP in index.html to support MCP UI functionality
- Added missing ToolCallWithResponse exports for diff content detection
- Resolved import conflicts and mutual file additions
- All TypeScript compilation passes successfully
- Fix SidecarLayout to use UIResourceRenderer instead of placeholder
- Add adaptive sidecar width (600px for UI resources, 500px for diffs)
- Improve UIResourceRenderer styling with proper iframe dimensions
- Add conditional overflow handling for different content types
- Include CSS styling for iframe content with rounded corners and shadows
- Ensure UI resources render properly without truncation

Resolves UI resource display issues in the sidecar panel.
@Kvadratni Kvadratni force-pushed the feature/diff-viewer-sidecar branch from b7df644 to aa57f48 Compare July 18, 2025 17:59
@mgd1984
Copy link
Author

mgd1984 commented Jul 18, 2025

Update: merged with feature/diff-viewer-sidecar branch and integrated MCP-UI rendering into the existing SidecarLayout.tsx component. Hopefully not too messy to see what I'm getting at here - could use some tips on how to cleanly merge these changes while so much is still in flux.

Key changes:

  • Extended SidecarLayout.tsx to handle UI resources alongside diff viewing (rename to WingmateLayout.tsx🤔???)
  • UI resources render in sandboxed iframes within the sidecar (addresses security concerns from integrate MCP UI #2948)
  • Added smart detection for UI content that gets flattened to text during MCP transport (klugey - could use refinement)
  • Sidecar adapts width automatically: 600px for UI resources, 500px for diffs

Re: security - Using iframe sandboxing similar to @aharvard's approach, but integrated into the existing sidecar rather than inline chat.

@idosal
Copy link

idosal commented Jul 18, 2025

This is awesome @mgd1984! Super exciting.

Trying to follow up on some threads -

  1. You can find docs on adding custom component libraries to render remoteDom resource here. The awesome Radix team is working on shared remote elements and a starter component library! (cc @tobinsouth)
  2. Security - all resource types are equally secure (UIResourceRenderer runs all untrusted Javascript in a sandboxed iframe from a different origin).

Please LMK if there's anything you need. Happy to contribute to the effort.

@liady
Copy link

liady commented Jul 18, 2025

@mgd1984 thanks! Great to see it taking shape :)

As for the Sidecar Wingmate idea - I like it, it really shows the power of using UI resources anywhere , to create streamlined, native experiences, and not just being inline of the chat.

As Ido mentioned - we're happy to help.

For testing - there's a sample mcp-ui server we built to demonstrate(but it's fully functioning), it's built on top of the existing Shopify MCP server and enriches it with MCP-UI components. It's returning iframes but can be used to test some of the flows: https://mcpstorefront.com

Liad.Yosef.s.Video.-.Jul.10.2025-VEED.2.mp4

mgd1984 added 2 commits July 20, 2025 23:25
- Update SidecarLayout to increase width for UI resources to 800px.
- Add logging to ToolCallWithResponse for detecting proper UI resources and skipping fallback processing.
- Modify ToolResultView to conditionally skip fallback UI detection if proper UI resources are present.
- Implement detection and extraction for @mcp-ui/server format in UIResourceRenderer, improving resource handling and logging.

These changes improve the rendering and processing of UI resources, ensuring a more robust integration with the new UI format.
@mgd1984
Copy link
Author

mgd1984 commented Jul 21, 2025

Thanks for the resources @idosal and the demo/sample server @liady!


I went back and did some further digging into the PRs, tweets, docs, and demos in the space - really trying to get the lay of the land here. The domain is still quite nascent, but it feels like some common terms & tools are starting to emerge.

Whether we call it Generative UI/GenUI, Invisible UX, Agent-native, or something Karpathy coins and we all jump on, the challenge seems to be in making the abstractions concrete enough to actually build with, yet flexible and familiar enough to be composable and adoptable by devs. To make matters more complex, all of the above must be done while models with larger context windows and better tool use continue to drop.

That said, devs have to start somewhere and React components seem to be a popular choice that many projects are converging on. Vercel literally includes it in their definition:

Generative UI is the process of connecting the results of a tool call to a React component (Vercel)

By piggy-backing on existing MCP primitives, mcp-ui seems like a wise bet, but I'm curious how it stacks up against:

What would be great for developers is to have a solid synthesis of the emerging alternatives, so that we can pick wisely. I feel like this is @kentcdodds' superpower.


re: the sample mcp-ui server - very cool and meta ("MCP-ify your Shopify store"). I tried to plug it in, but was still having problems rendering UIResources. Most of my testing has been with an MCP server that I deployed to Cloudflare, but it's quite complex (uses cloudflare-workers-oauth library, Durable Objects, KV, and subscription-gated scopes to determine a user's tool access) and likely the cause of me still getting text rendered responses in the Goose frontend.

Trying to isolate the issue, hope to have a working demo to share soon.

@aharvard
Copy link
Collaborator

Hey @mgd1984, this is really exciting! Apologies for the radio silence, I finally carved out some time to help unify some work streams. I'd love to have your input over in #3562 — hopefully we can ship something soon!

@Kvadratni Kvadratni force-pushed the feature/diff-viewer-sidecar branch 3 times, most recently from 3b7ad8a to b4b6bfb Compare July 21, 2025 20:50
@liady
Copy link

liady commented Jul 21, 2025

@mgd1984 ,super cool! I agree that we need to explore the ideal generalization, while in parallel already provide concrete starting point for developers.
May I ask what where the issues with rendering the mcpstorefront.com server resources? This is the code I used to render the returned resources on the page itself (using mcp-ui, of course): https://github.com/liady/sfr-mcp-ui/blob/main/app/components/UIResourceFrame.tsx

@michaelneale michaelneale removed their assignment Jul 28, 2025
@DOsinga
Copy link
Collaborator

DOsinga commented Aug 2, 2025

I think we have this now in a different version thanks to all people involved? closing for now, feel free to reopen if wrong

@DOsinga DOsinga closed this Aug 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants