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

featured-image

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.

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. Problem: Limited User Interaction in MCPModel 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:See various design optionsCompare different implementationsCustomize details before integrationMake informed choices based on visual representationThe standard MCP approach offers no built-in mechanism for this kind of interactive feedback loop.Solution: Browser-Based MCP CommunicationTo address this limitation, we've developed a system that enables communication with MCPs through a browser interface.

This approach:Creates a local MCP that can host a bundle and open a web browserServes a local bundle alongside the MCP in NPMAutomatically opens a browser that redirects to a user interfaceAllows users to interact with and select from available optionsShuts down the server and resumes execution with the user's selectionThe result is a seamless integration that maintains the power of MCP while adding the visual feedback and interaction capabilities users need.Technical implementationLet's look at how this is implemented. Callback ServerAt 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 { 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((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:Dynamically finds an available portCreates a unique session ID for each requestServes the UI bundleOpens the browser to display optionsReceives the user's selection through a callbackResolves the promise with the selected dataIntegration with MCP toolWe've applied this approach to enhance our 21stmagiccomponent_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): Promise; }> { try { // Fetch UI component variations from API const response = await twentyFirstClient.post("/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 FlowHere's how the user experience flows when requesting a UI component:Tool Invocation: The AI assistant invokes the 21stmagiccomponent_builder tool when a user requests a new UI component.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.Browser Launch: A local server starts and a browser window automatically opens, displaying the generated UI component options.User Interaction: The user can view, interact with, and select their preferred component variation.

Selection Capture: When the user makes a selection, the browser sends the selection back to the callback server.Execution Resumption: The server shuts down, and execution resumes with the selected component data.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 ConsiderationsOur implementation takes several security measures:Local Hosting: All communication happens locally on the user's machine (127.0.

0.1)Unique Session IDs: Each browser session has a unique ID to prevent cross-session interferenceTimeout Mechanism: Sessions automatically time out after a configurable period (default 5 minutes)Port Safety: The server dynamically finds an available port to avoid conflictsConclusionThe 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.

.