In this article
September 8, 2025
September 8, 2025

MCP-UI: A Technical Overview of Interactive Agent Interfaces

MCP-UI represents more than an incremental improvement to agent interfaces—it's a fundamental shift toward interactive, context-aware AI systems that can deliver rich experiences directly within conversational flows.

The Model Context Protocol (MCP) has already proven its worth in connecting AI agents to real-world tools and data. But for all its architectural elegance, MCP has been fundamentally constrained by text-only interactions. Enter MCP-UI—an experimental extension that brings interactive web components directly into agent conversations, fundamentally changing how we think about human-AI interfaces.

As demonstrated at MCP Night 2.0, MCP-UI isn't just about prettier interfaces. It's about breaking down the text wall that forces users to manually translate agent responses into actionable UI elements, particularly for complex domains like commerce, data visualization, and form-driven workflows.

Architecture and Core Concepts

The UIResource Protocol

At its heart, MCP-UI extends MCP's existing embedded resources specification with a new UIResource interface. This isn't a complete protocol overhaul—it's a thoughtful extension that leverages MCP's existing infrastructure while adding rich interaction capabilities.

interface UIResource {
  type: 'resource';
  resource: {
    uri: string; // e.g., ui://component/id
    mimeType: 'text/html' | 'text/uri-list' | 'application/vnd.mcp-ui.remote-dom';
    text?: string; // Inline content
    blob?: string; // Base64-encoded content
  };
}

The uri field follows a ui:// scheme for consistent resource identification and caching. The mimeType determines the rendering strategy, while the content can be delivered either inline via text or encoded in blob for larger payloads.

Three Rendering Approaches

MCP-UI supports three distinct rendering mechanisms, each with specific use cases and security considerations.

Inline HTML Rendering

The simplest approach embeds HTML directly into sandboxed iframes using srcDoc. This works well for self-contained components that don't require external resources.

const htmlResource = createUIResource({
  uri: 'ui://greeting/1',
  content: { 
    type: 'rawHtml', 
    htmlString: '<div class="card"><h2>Task Status</h2><p>3 of 5 items completed</p></div>' 
  },
  encoding: 'text',
});

This approach provides immediate rendering with strong security isolation but limits dynamic behavior and external resource access.

External URL Resources

For more complex applications, MCP-UI can load complete external applications through iframe src attributes. This enables rich, fully-featured interfaces while maintaining sandbox security.

const externalResource = createUIResource({
  uri: 'ui://dashboard/analytics',
  content: { 
    type: 'externalUrl', 
    iframeUrl: 'https://analytics.example.com/embed' 
  },
  encoding: 'text',
});

This pattern works particularly well for existing web applications that need to be embedded within agent conversations, such as dashboard widgets or specialized tools.

Remote DOM Integration

The most sophisticated approach leverages Shopify's Remote DOM library to enable JavaScript-driven interfaces that can match the host application's design system.

const remoteDomResource = createUIResource({
  uri: 'ui://interactive/button',
  content: {
    type: 'remoteDom',
    script: `
      const button = document.createElement('ui-button');
      button.setAttribute('label', 'Process Data');
      button.addEventListener('press', () => {
        window.parent.postMessage({
          type: 'tool',
          payload: { toolName: 'processData', params: { action: 'start' } }
        }, '*');
      });
      root.appendChild(button);
    `,
    framework: 'react',
  },
  encoding: 'text',
});

Remote DOM executes JavaScript in a sandboxed environment while rendering UI changes through the host's component library. This enables sophisticated interactions while maintaining visual consistency with the host application.

Implementation Details

Server-Side SDK Design

The @mcp-ui/server SDK abstracts away the complexity of resource creation while providing type safety and validation. The Ruby SDK (mcp_ui_server) offers similar functionality for Ruby-based MCP servers.

import { createUIResource } from '@mcp-ui/server';

// The SDK handles validation, encoding, and resource structure
const resource = createUIResource({
  uri: 'ui://form/contact',
  content: { type: 'rawHtml', htmlString: formHTML },
  encoding: 'text',
});

The SDK validates URI schemes, ensures proper MIME type mappings, and handles encoding automatically. This reduces implementation errors and ensures compatibility across different MCP clients.

Client-Side Rendering

The @mcp-ui/client package provides both React components and Web Components for maximum compatibility.

import { UIResourceRenderer } from '@mcp-ui/client';

function AgentResponse({ mcpResource }) {
  return (
    <UIResourceRenderer 
      resource={mcpResource.resource}
      onUIAction={(action) => {
        // Handle tool calls, prompts, or other agent interactions
        handleAgentAction(action);
      }}
      autoResizeIframe={{ height: true, width: false }}
    />
  );
}

The renderer automatically detects resource types and applies appropriate security measures. The onUIAction callback provides a standardized interface for handling user interactions within embedded components.

Event System and Agent Integration

MCP-UI's event system preserves agent autonomy while enabling rich interactions. Components don't directly modify application state—instead, they emit structured events that agents interpret and act upon.

// Events follow a structured format
type UIAction = 
  | { type: 'tool', payload: { toolName: string, params: Record<string, unknown> } }
  | { type: 'intent', payload: { intent: string, params: Record<string, unknown> } }
  | { type: 'prompt', payload: { prompt: string } }
  | { type: 'notify', payload: { message: string } }
  | { type: 'link', payload: { url: string } };

This design ensures that agents maintain control over application logic while components handle presentation and immediate user interactions.

Real-World Implementation Patterns

Commerce Applications at Scale

Shopify's implementation demonstrates MCP-UI's potential for complex, domain-specific interfaces. Their product selection components handle variant dependencies, inventory constraints, and pricing rules that would be nearly impossible to represent effectively through text alone.

// Product component communicates through intent events
component.addEventListener('addToCart', (event) => {
  window.parent.postMessage({
    type: 'intent',
    payload: { 
      intent: 'add_to_cart',
      params: { 
        productId: event.detail.productId,
        variant: event.detail.selectedVariant,
        quantity: event.detail.quantity 
      }
    }
  }, '*');
});

The intent-based architecture allows agents to mediate complex purchase flows while components handle the intricate UI logic for variant selection, bundle configuration, and real-time inventory updates.

Agent Integration Examples

Block's Goose agent demonstrates client-side integration patterns. Their implementation shows how existing MCP hosts can add UI capabilities without significant architectural changes.

// Goose configuration for MCP-UI
{
  type: 'Remote Extension (Streaming HTTP)',
  endpoint: 'https://mcp-aharvard.netlify.app/mcp'
}

This simplicity belies the underlying complexity that MCP-UI handles—security sandboxing, event routing, and component lifecycle management all happen transparently.

Security and Sandboxing

Security remains paramount in MCP-UI's design. All remote code executes within sandboxed iframes with restricted permissions, while the event system provides controlled communication channels.

The sandbox prevents direct DOM access to the host application while enabling rich interactions through the structured event system. This balance maintains security without sacrificing functionality.

Development Ecosystem

SDK Architecture

MCP-UI's multi-language SDK approach reflects real-world MCP server diversity. The TypeScript SDK provides comprehensive functionality for Node.js environments, while the Ruby SDK enables integration with Rails applications and other Ruby-based tools.

# Ruby SDK mirrors TypeScript functionality
require 'mcp_ui_server'

resource = McpUiServer.create_ui_resource(
  uri: 'ui://status/dashboard',
  content: { type: :external_url, iframeUrl: 'https://status.internal.com' },
  encoding: :text
)

The consistent API across languages reduces cognitive overhead for teams working across different tech stacks.

Testing and Development Tools

The project includes several development utilities that streamline the implementation process. The ui-inspector provides local testing capabilities for MCP servers, while hosted demo servers enable rapid prototyping.

# Test MCP-UI servers locally
npx ui-inspector http://localhost:3000/mcp

These tools address a common pain point in MCP development—the need for quick iteration cycles when building and testing server functionality.

Integration Patterns

MCP-UI's design encourages incremental adoption. Existing MCP servers can add UI capabilities to specific tools without refactoring their entire codebase.

// Add UI to existing MCP tools
export async function listTasks(): Promise<ToolResult> {
  const tasks = await fetchTasks();
  
  // Return both text and UI representations
  return {
    content: [
      { type: 'text', text: `Found ${tasks.length} tasks` },
      createUIResource({
        uri: 'ui://tasks/list',
        content: { type: 'rawHtml', htmlString: renderTaskList(tasks) },
        encoding: 'text'
      })
    ]
  };
}

This pattern allows gradual enhancement of existing tools rather than requiring complete rewrites.

Technical Considerations and Limitations

Performance Implications

MCP-UI introduces additional complexity in client applications. Iframe rendering, event handling, and component lifecycle management all impact performance. The auto-resize functionality, while convenient, requires continuous DOM monitoring that can affect page performance with many active components.

Remote DOM rendering offers better performance characteristics by eliminating iframe overhead, but requires more sophisticated client-side infrastructure and component library management.

Framework Dependencies

The Remote DOM approach ties MCP-UI to specific frontend frameworks (currently React and Web Components). While this enables sophisticated functionality, it also limits adoption in environments using other frameworks or vanilla JavaScript.

Future versions may expand framework support, but this represents a fundamental architectural decision that affects both server and client implementations.

Security Model Complexity

While sandboxing provides strong security guarantees, it also introduces complexity in debugging and development. Component errors occur within iframe contexts, making troubleshooting more challenging than traditional web development.

The event-based communication model requires careful handling of message validation and origin checking to prevent security vulnerabilities.

Future Directions

Declarative UI Patterns

The MCP-UI roadmap includes support for declarative UI definitions that would allow agents to generate interfaces programmatically without requiring pre-built components.

// Hypothetical declarative interface
const formResource = createUIResource({
  uri: 'ui://form/dynamic',
  content: {
    type: 'declarative',
    definition: {
      type: 'form',
      fields: [
        { type: 'text', name: 'email', label: 'Email Address', required: true },
        { type: 'select', name: 'priority', options: ['low', 'medium', 'high'] }
      ]
    }
  }
});

This approach would enable more dynamic interfaces while maintaining the security and consistency benefits of the current architecture.

Cross-Platform Expansion

Future development may extend beyond web-based interfaces to native mobile components, voice interfaces, or even AR/VR environments. The underlying protocol design supports this evolution through its flexible resource and event system.

Generative UI Integration

The combination of MCP-UI's infrastructure with generative AI capabilities could enable interfaces that adapt to individual user needs, accessibility requirements, and context-specific optimizations.

The project's open-source nature and growing ecosystem adoption suggest that interactive agent interfaces are moving from experimental curiosity to production necessity. The text wall is indeed coming down, and MCP-UI is leading the charge.

This site uses cookies to improve your experience. Please accept the use of cookies on this site. You can review our cookie policy here and our privacy policy here. If you choose to refuse, functionality of this site will be limited.