Il Model Calling Protocol (MCP) ha significativamente migliorato il modo in cui gli assistenti AI interagiscono con strumenti esterni, consentendo applicazioni più potenti e versatili. Tuttavia, esiste una limitazione chiave all'interno dell'implementazione standard MCP: le chiamate agli strumenti sono essenzialmente operazioni "black box" senza interfaccia utente incorporata per l'interazione.
In questo articolo, esplorerò un approccio innovativo che abbiamo sviluppato in21° Magico MCPper superare questa limitazione creando un'interfaccia basata sul browser per le comunicazioni MCP, focalizzata specificamente sulla generazione di componenti UI con la nostra integrazione 21st.dev.
Problema: Interazione utente limitata in MCP
Model Calling Protocol consente agli assistenti AI di richiamare strumenti esterni per eseguire compiti specializzati.Mentre potente, l'implementazione standard ha uno svantaggio significativo:
Questa restrizione è particolarmente problematica quando si generano componenti UI. Quando un'IA suggerisce un componente UI, gli utenti spesso devono:
-
See various design options
-
Compare different implementations
-
Customize details before integration
-
Make informed choices based on visual representation
L'approccio MCP standard non offre un meccanismo integrato per questo tipo di loop di feedback interattivo.
Soluzione: Comunicazione MCP basata su browser
Per affrontare questa limitazione, abbiamo sviluppato un sistema che consente la comunicazione con i MCP attraverso un'interfaccia del browser.
- Crea un MCP locale che può ospitare un bundle e aprire un browser web
- Servisce un bundle locale accanto al MCP in NPM
- Apri automaticamente un browser che reindirizza a un'interfaccia utente
- Consente agli utenti di interagire con e selezionare tra le opzioni disponibili
- Chiude il server e riprende l'esecuzione con la selezione dell'utente
Il risultato è un'integrazione fluida che mantiene la potenza di MCP aggiungendo al contempo le capacità di feedback visivo e di interazione necessarie agli utenti.
Implementazione tecnica
Vediamo come viene implementato.
Servizio Callback
Al centro della nostra soluzione c’è un server callback che facilita la comunicazione tra il MCP e l’interfaccia del browser:
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;
}
}
}
Questo è il server:
- Trova dinamicamente un port disponibile
- Crea un ID di sessione unico per ogni richiesta
- Serves the UI bundle
- Apri il browser per visualizzare le opzioni
- Riceve la selezione dell'utente attraverso un callback
- Risolve la promessa con i dati selezionati
Integration with MCP tool
Abbiamo applicato questo approccio per migliorare il nostro strumento 21st_magic_component_builder, che genera componenti UI:
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;
}
}
}
Flusso di esperienza utente
Ecco come funziona l'esperienza utente quando si richiede un componente UI:
- Invocazione degli strumenti: l'assistente AI richiama lo strumento 21st_magic_component_builder quando un utente richiede un nuovo componente UI.
- Richiesta API: lo strumento invia una richiesta all'API 21st.dev per generare varie variazioni dei componenti dell'interfaccia utente in base al messaggio e al contesto dell'utente.
- Avvio del browser: si avvia un server locale e si apre automaticamente una finestra del browser, visualizzando le opzioni del componente UI generato.
- Interazione utente: l'utente può visualizzare, interagire con e selezionare la variante di componente preferita.
- Capture di selezione: quando l'utente fa una selezione, il browser invia la selezione indietro al server callback.
- Ripresa dell'esecuzione: il server si chiude e l'esecuzione si riprende con i dati dei componenti selezionati.
- Guida all'integrazione: l'assistente AI riceve il componente selezionato e fornisce istruzioni sull'integrazione nel codebase dell'utente.
Questo approccio crea un'esperienza senza problemi che consente agli utenti di prendere decisioni informate sui componenti dell'interfaccia utente pur mantenendo il flusso di lavoro complessivo di MCP.
Considerazioni di sicurezza e privacy
La nostra implementazione richiede diverse misure di sicurezza:
- Hosting locale: tutta la comunicazione avviene localmente sul computer dell'utente (127.0.0.1)
- ID di sessione uniche: ogni sessione del browser ha un ID univoco per prevenire interferenze tra le sessioni
- Timeout: le sessioni si esauriscono automaticamente dopo un periodo configurabile (per impostazione predefinita 5 minuti)
- Port Security: il server trova dinamicamente una porta disponibile per evitare conflitti
Conclusione
L'approccio basato sul browser alla comunicazione MCP rappresenta un miglioramento significativo per l'esperienza dell'utente quando si lavora con strumenti che beneficiano dell'interazione visiva. Collegando il divario tra le potenti capacità di MCP e la natura interattiva delle interfacce web, abbiamo creato un flusso di lavoro più intuitivo per gli utenti. Questo approccio è particolarmente prezioso per la generazione di componenti UI, dove la rappresentazione visiva è fondamentale per prendere decisioni informate.
Il codice sorgente è disponibile sudi Github.