goose icon indicating copy to clipboard operation
goose copied to clipboard

feat: add mcp app renderer

Open aharvard opened this issue 2 weeks ago • 0 comments

Summary

Implements the front-end foundation for MCP Apps in Goose Desktop, following the MCP Apps specification. This PR sets up the rendering infrastructure, communication bridge, and mock handlers—preparing for a subsequent PR that will connect to actual MCP server resources.

Related: https://github.com/block/goose/discussions/6069

What This PR Adds

New Components (ui/desktop/src/components/McpApps/)

  • McpAppRenderer.tsx — Renders MCP App UI resources in sandboxed iframes with security boundaries
  • useSandboxBridge.ts — React hook managing the postMessage-based JSON-RPC 2.0 communication between host (Goose) and guest (iframe), including:
    • Sandbox initialization lifecycle (sandbox-readyinitializeinitialized)
    • Host context propagation (theme, viewport, locale, timezone, platform)
    • Tool lifecycle notifications (tool-input, tool-input-partial, tool-result, tool-cancelled)
    • Resource teardown on unmount
  • types.ts — TypeScript types for JSON-RPC messages, MCP App resources (ui:// scheme), host context, and all guest message types
  • utils.ts — Message creation helpers and stubbed handlers for MCP protocol methods
  • mockAppData.ts — Demo MCP App HTML with interactive buttons to test all protocol methods

Spec Alignment

  • Uses ui:// URI scheme for UI resources
  • Implements text/html;profile=mcp-app MIME type
  • Supports CSP metadata (connectDomains, resourceDomains, prefersBorder)
  • Full initialization handshake per spec
  • Host context with theme, viewport, locale, platform, device capabilities
  • CSP enforcement on the outer sandbox proxy

Current State

The McpAppRenderer integration in ToolCallWithResponse.tsx is commented out because Goose needs to dynamically fetch UI resources via resources/read when a tool's _meta.ui.resourceUri is present. The mock data demonstrates the expected flow.

Handlers Status

Method Status Action Required
ui/open-link ✅ Implemented
ui/message ✅ Implemented
ui/notifications/size-changed ✅ Implemented
tools/call 🔜 Stubbed Forward to MCP server; enforce "app" visibility
resources/list 🔜 Stubbed Return available resources from MCP server
resources/read 🔜 Stubbed Fetch resource content from MCP server
resources/templates/list 🔜 Stubbed Return resource templates from MCP server
prompts/list 🔜 Stubbed Return available prompts from MCP server
notifications/message 🔜 Stubbed Forward log message to MCP server
ping 🔜 Stubbed Forward to MCP server and return response

Future: @mcp-ui/client SDK

The useSandboxBridge hook is a temporary implementation. Once the @mcp-ui/client package provides its AppRenderer component, we can refactor to pass props directly to that component—which will internalize the sandbox communication logic. The handler functions in utils.ts are designed to be reusable and can be plugged directly into the SDK component's callback props.

Next Steps (Subsequent PRs)

  1. Resource fetching — Wire up resources/read to fetch UI resources when _meta.ui.resourceUri is present on tool results
  2. Handler integration — Connect stubbed handlers to forward requests to the appropriate MCP server
  3. Tool visibility — Implement filtering for ["model"] vs ["app"] visibility
  4. Host theming — Provide hostContext.styles.variables with standardized CSS custom properties (colors, typography, border radius) so MCP Apps can match Goose's visual style
  5. Custom fonts — Provide hostContext.styles.css.fonts with @font-face rules for Goose's fonts so MCP Apps can use them

aharvard avatar Dec 12 '25 21:12 aharvard