157 reads

Your AI Assistant Can Now Show You Options Before Making Decisions — Thanks to a Clever Browser Hack

by Sergey BunasApril 27th, 2025
Read on Terminal Reader
Read this story w/o Javascript

Too Long; Didn't Read

Model Calling Protocol (MCP) allows AI assistants to invoke external tools to perform specialized tasks. MCP has no built-in user interface for interaction. We've developed a system that enables communication with MCPs through a browser interface. The result is a seamless integration that maintains the power of MCP.

Company Mentioned

Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Your AI Assistant Can Now Show You Options Before Making Decisions — Thanks to a Clever Browser Hack
Sergey Bunas HackerNoon profile picture

The Model Calling Protocol (MCP) has significantly improved the way AI assistants interact with external tools, allowing for more powerful and versatile applications. However, a key limitation exists within the standard MCP implementation: tool callings are essentially "black box" operations with no built-in user interface for interaction. This creates a disconnect in user experience, particularly in cases where visual feedback or user input would be beneficial during the tool execution process.


In this article, I'll explore an innovative approach we've developed in 21st Magic MCP to overcome this limitation by creating a browser-based interface for MCP communications, specifically focused on UI component generation with our 21st.dev integration.


UI of web selection in Magic MCP


Problem: Limited User Interaction in MCP

Model Calling Protocol allows AI assistants to invoke external tools to perform specialized tasks. While powerful, the standard implementation has a significant drawback:


This restriction is particularly problematic when generating UI components. When an AI suggests a UI component, users often need to:

  1. See various design options

  2. Compare different implementations

  3. Customize details before integration

  4. Make informed choices based on visual representation


The standard MCP approach offers no built-in mechanism for this kind of interactive feedback loop.


Solution: Browser-Based MCP Communication

To address this limitation, we've developed a system that enables communication with MCPs through a browser interface. This approach:


  1. Creates a local MCP that can host a bundle and open a web browser
  2. Serves a local bundle alongside the MCP in NPM
  3. Automatically opens a browser that redirects to a user interface
  4. Allows users to interact with and select from available options
  5. Shuts down the server and resumes execution with the user's selection


The result is a seamless integration that maintains the power of MCP while adding the visual feedback and interaction capabilities users need.

Technical implementation

Let's look at how this is implemented.


Callback Server

At the core of our solution is a callback server that facilitates communication between the MCP and the browser interface:


export class CallbackServer {
  private server: Server | null = null;
  private port: number;
  private sessionId = Math.random().toString(36).substring(7);
  // ... other properties
  
  async promptUser(
    config: CallbackServerConfig = {}
  ): Promise<CallbackResponse> {
    const { initialData = null, timeout = 300000 } = config;
    this.config = config;

    try {
      const availablePort = await this.findAvailablePort();
      this.server = createServer(this.handleRequest);
      this.server.listen(availablePort, "127.0.0.1");

      // Set up promise to handle user selection
      return new Promise<CallbackResponse>((resolve, reject) => {
        this.promiseResolve = resolve;
        this.promiseReject = reject;
        
        // ... server setup code
        
        // Open browser with unique session ID
        const url = `http://127.0.0.1:${availablePort}?id=${this.sessionId}`;
        open(url).catch((error) => {
          console.warn("Failed to open browser:", error);
          resolve({ data: { browserOpenFailed: true } });
          this.shutdown();
        });
      });
    } catch (error) {
      await this.shutdown();
      throw error;
    }
  }
}


This server:

  1. Dynamically finds an available port
  2. Creates a unique session ID for each request
  3. Serves the UI bundle
  4. Opens the browser to display options
  5. Receives the user's selection through a callback
  6. Resolves the promise with the selected data

Integration with MCP tool

We've applied this approach to enhance our 21st_magic_component_builder tool, which generates UI components:

export class CreateUiTool extends BaseTool {
  name = UI_TOOL_NAME;
  description = UI_TOOL_DESCRIPTION;
  
  // ... schema definition
  
  async execute({
    message,
    searchQuery,
    absolutePathToCurrentFile,
    context,
  }: z.infer<typeof this.schema>): Promise<{
    content: Array<{ type: "text"; text: string }>;
  }> {
    try {
      // Fetch UI component variations from API
      const response = await twentyFirstClient.post<{
        data1: { text: string };
        data2: { text: string };
        data3: { text: string };
      }>("/api/create-ui-variation", {
        message,
        searchQuery,
        fileContent: await getContentOfFile(absolutePathToCurrentFile),
        context,
      });
      
      // Handle billing or error cases
      if (response.status !== 200) {
        open("https://21st.dev/settings/billing");
        return {
          content: [
            {
              type: "text" as const,
              text: response.data.text as string,
            },
          ],
        };
      }

      // Create server and prompt user through browser
      const server = new CallbackServer();
      const { data } = await server.promptUser({
        initialData: {
          data1: response.data.data1,
          data2: response.data.data2,
          data3: response.data.data3,
        },
      });
      
      // Process user selection and return formatted response
      const componentData = data || {
        text: "No component data received. Please try again.",
      };
      
      // Return formatted response to user
      // ...
    } catch (error) {
      console.error("Error executing tool", error);
      throw error;
    }
  }
}

User Experience Flow

Here's how the user experience flows when requesting a UI component:


  1. Tool Invocation: The AI assistant invokes the 21st_magic_component_builder tool when a user requests a new UI component.
  2. API Request: The tool sends a request to the 21st.dev API to generate multiple UI component variations based on the user's message and context.
  3. Browser Launch: A local server starts and a browser window automatically opens, displaying the generated UI component options.
  4. User Interaction: The user can view, interact with, and select their preferred component variation.
  5. Selection Capture: When the user makes a selection, the browser sends the selection back to the callback server.
  6. Execution Resumption: The server shuts down, and execution resumes with the selected component data.
  7. Integration Guidance: The AI assistant receives the selected component and provides guidance on integrating it into the user's codebase.


This approach creates a seamless experience that allows users to make informed decisions about UI components while maintaining the overall MCP workflow.

Security and Privacy Considerations

Our implementation takes several security measures:


  1. Local Hosting: All communication happens locally on the user's machine (127.0.0.1)
  2. Unique Session IDs: Each browser session has a unique ID to prevent cross-session interference
  3. Timeout Mechanism: Sessions automatically time out after a configurable period (default 5 minutes)
  4. Port Safety: The server dynamically finds an available port to avoid conflicts

Conclusion

The browser-based approach to MCP communication represents a significant improvement to the user experience when working with tools that benefit from visual interaction. By bridging the gap between the powerful capabilities of MCP and the interactive nature of web interfaces, we've created a more intuitive workflow for users. This approach is particularly valuable for UI component generation, where visual representation is crucial for making informed decisions. However, the pattern could be extended to other tools that would benefit from user interaction during execution.


Source code is available on GitHub.

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks