模型调用协议(MCP)显著改善了人工智能助理与外部工具的交互方式,允许更强大和多功能的应用程序。然而,标准MCP实施中存在一个关键的局限性:工具调用基本上是“黑匣子”操作,没有内置的用户界面进行交互。
在本文中,我将探索我们开发的创新方法第21集 魔法MCP通过创建基于浏览器的 MCP 通信界面来克服这一局限性,专注于通过我们的 21st.dev 集成来生成 UI 组件。
问题: MCP 中的有限用户互动
模型调用协议允许人工智能助理调用外部工具来执行专门任务.虽然强大,但标准实现有一个显著的缺点:
这种限制在生成 UI 组件时特别有问题,当 AI 建议 UI 组件时,用户通常需要:
-
See various design options
-
Compare different implementations
-
Customize details before integration
-
Make informed choices based on visual representation
标准的MCP方法不提供这种互动反馈循环的内置机制。
解决方案:基于浏览器的MCP通信
为了解决这一局限性,我们开发了一种系统,可以通过浏览器界面与MCP进行通信。
- 创建可托管包的本地 MCP 并打开 Web 浏览器
- 在 NPM 中与 MCP 一起提供本地包
- 自动打开重定向到用户界面的浏览器
- 允许用户互动并从可用的选项中选择
- 关闭服务器并与用户选择恢复执行
其结果是无缝集成,保持MCP的功率,同时增加用户需要的视觉反馈和交互能力。
技术实施
让我们看看它是如何实施的。
召回服务器
我们的解决方案的核心是调用服务器,可促进MCP和浏览器界面之间的通信:
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;
}
}
}
这个服务器:
- 动态找到可用的端口
- 为每个请求创建一个独特的会话 ID
- 使用 UI 包裹
- 打开浏览器以显示选项
- 通过回调接收用户的选择
- 用所选数据解决承诺
Integration with MCP tool
我们采用了这种方法来增强我们的 21st_magic_component_builder 工具,它会生成 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;
}
}
}
用户体验流
以下是用户体验在请求用户界面组件时如何流动:
- 工具召唤: AI 助手在用户要求新 UI 组件时召唤 21st_magic_component_builder 工具。
- API 请求:该工具向 21st.dev API 发送请求,以基于用户的消息和背景生成多个 UI 组件变异。
- 浏览器启动:一个本地服务器启动并自动打开浏览器窗口,显示生成的UI组件选项。
- 用户互动:用户可以查看、互动并选择自己喜爱的组件变量。
- 选择捕捉:当用户进行选择时,浏览器会将选择发送回回调服务器。
- Execution Resumption: The server shuts down, and execution resumes with the selected component data.
- 集成指南:AI助理接收所选组件,并提供将其集成到用户的代码库的指南。
这种方法创造了一个无缝的体验,允许用户对UI组件做出明智的决定,同时保持整体的MCP工作流程。
安全和隐私考虑
我们的实施需要采取若干安全措施:
- 局部托管:所有通信都发生在用户机器上(127.0.0.1)
- 独特的会话ID:每个浏览器会话都有一个独特的ID,以防止交叉会话干扰
- Timeout 机制:会话在可配置期限后自动结束(默认情况为 5 分钟)
- 端口安全:服务器动态地找到可用的端口以避免冲突
结论
基于浏览器的MCP通信方法在使用受益于视觉互动的工具时代表了用户体验的显著改善。通过弥合MCP的强大功能和Web接口的交互性质之间的差距,我们为用户创建了一个更直观的工作流程。这种方法对于UI组件生成尤其有价值,视觉表示对于做出明智的决定至关重要。
源代码可在吉普赛.