交互式聊天UI演示

一个使用模型上下文协议(MCP)的交互式聊天演示应用,允许LLM在聊天消息中显示交互式表单和UI组件。

  • by arashigaoka
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 arashigaoka/jsconf-mcp-ui-demo

使用说明

MCP-UI演示项目

使用带有UI扩展的模型上下文协议(MCP)的交互式聊天演示应用程序。

项目概述

该项目演示了如何将MCP-UI集成到聊天应用程序中,允许LLM在聊天消息中显示交互式表单和UI组件。

当前状态: 第4阶段完成-功能齐全的聊天用户界面✅

建筑

┌─────────────┐
│   User      │
└──────┬──────┘
       │
       ▼
┌─────────────────────────┐
│   Chat UI (React)       │  Port: 5173
│  - Vite dev server      │
└──────┬──────────────────┘
       │
       ▼
┌─────────────────────────┐
│  Express Server         │  Port: 3000
│  - API endpoints        │
│  - OpenAI integration   │
└──────┬──────────────────┘
       │
       ▼
┌─────────────────────────┐
│  MCP Server             │  Port: 3001
│  - UIResource generation│
└─────────────────────────┘

先决条件

  • Node.js>=18.0.0
  • npm>=9.0.0

快速开始

1.安装依赖项

npm install

2.设置环境变量

cp .env.example .env

编辑 .env 并添加您的OpenAI API密钥:

OPENAI_API_KEY=sk-your-api-key-here

3.启动开发服务器

选项A:一次启动所有服务器

npm run dev

选项B:单独启动服务器

终端1-反应客户端:

npm run dev:client

2号航站楼-快递服务器:

npm run dev:server

终端3-MCP服务器:

npm run dev:mcp

4.访问应用程序

  • 客户: http://localhost:5173
  • 服务器API: http://localhost:3000/api
  • 服务器运行状况: http://localhost:3000/health
  • MCP服务器: http://localhost:3001/tools
  • MCP健康: http://localhost:3001/health

5.设置环境变量

测试前,复制 .env.example 到 .env 并添加您的OpenAI API密钥:

cp .env.example .env

编辑 .env 并设置您的OpenAI API密钥:

OPENAI_API_KEY=sk-your-actual-api-key-here

6.测试MCP服务器(第2阶段)

列出可用工具:

curl -s http://localhost:3001/tools | jq .

生成预订表格:

curl -s -X POST http://localhost:3001/tools/show_reservation_form \
  -H 'Content-Type: application/json' \
  -d '{"restaurantName":"イタリアンレストラン"}' \
  | jq .

提交预订:

curl -s -X POST http://localhost:3001/tools/submit_reservation \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "山田太郎",
    "date": "2025-11-15",
    "time": "19:00",
    "partySize": 4,
    "contact": "090-1234-5678",
    "restaurantName": "イタリアンレストラン"
  }' \
  | jq .

7.测试聊天API(第三阶段)

注: 需要有效的OpenAI API密钥 .env

发送聊天消息:

curl -s -X POST http://localhost:3000/api/chat \
  -H 'Content-Type: application/json' \
  -d '{"message":"レストランを予約したいです"}' \
  | jq .

预期响应包括预订表格的UIResource:

{
  "success": true,
  "conversationId": "conv_...",
  "message": "フォームを表示しました",
  "uiResource": {
    "type": "resource",
    "resource": {
      "uri": "ui://reservation-form/...",
      "mimeType": "text/html",
      "text": "<!DOCTYPE html>..."
    }
  }
}

项目结构

jsconf-mcp-ui-demo/
├── client/               # React + Vite frontend
│   ├── src/
│   │   ├── components/  # React components
│   │   ├── hooks/       # Custom hooks
│   │   ├── types/       # TypeScript types
│   │   ├── App.tsx      # Main app component
│   │   └── main.tsx     # Entry point
│   └── package.json
│
├── server/              # Express backend
│   ├── src/
│   │   ├── routes/      # API routes
│   │   ├── services/    # Business logic
│   │   ├── config/      # Configuration
│   │   └── index.ts     # Server entry point
│   └── package.json
│
├── mcp-server/          # MCP server
│   ├── src/
│   │   ├── tools/       # MCP tools
│   │   └── index.ts     # MCP server entry point
│   └── package.json
│
├── shared/              # Shared types
│   └── src/
│       └── types/       # Common TypeScript types
│
└── package.json         # Root workspace config

可用脚本

根级

  • npm run dev -同时启动所有服务器
  • npm run dev:client -仅启动React客户端
  • npm run dev:server -仅启动Express服务器
  • npm run dev:mcp -仅启动MCP服务器
  • npm run build -构建所有包
  • npm run lint -轻敲所有包裹
  • npm run format -使用Prettier格式化代码
  • npm run clean -删除所有node_modules

包裹级别

每个包(客户端、服务器、mcp服务器)都有自己的脚本:

  • npm run dev --workspace=<package-name>
  • npm run build --workspace=<package-name>
  • npm run lint --workspace=<package-name>

发展路线图

✅ 第一阶段:项目设置

  • [x] 使用npm工作区进行Monrepo配置
  • [x] TypeScript配置
  • [x] ESLint和Prettier设置
  • [x] 基本客户端、服务器和mcp服务器脚手架
  • [x] 开发环境就绪
  • [x] MCP-UI SDK集成(@MCP UI/客户端v5.14.1,@MCP UI/服务器v5.13.1)

✅ 第2阶段:MCP服务器实施

  • [x] 集成@mcp用户界面/服务器SDK
  • [x] 实现预订表单UI生成工具
  • [x] 实现submit_reservation工具
  • [x] 使用rawHtml创建UIResource生成器
  • [x] 用于工具执行的REST API端点
  • [x] 本地测试完成

✅ 第3阶段:Express服务器实施

  • [x] OpenAI GPT-4 Turbo集成
  • [x] MCP工具的函数调用实现
  • [x] 用于服务器到服务器通信的MCP客户端
  • [x] 聊天API端点(POST/API/聊天,获取/删除)
  • [x] 内存对话管理
  • [x] 服务器包的ES模块迁移

✅ 第四阶段:React客户端实现(完成)

  • [x] 聊天UI组件(聊天UI、消息列表、消息项、输入区)
  • [x] 带有iframe沙盒的UIResource渲染器
  • [x] postMessage处理与源验证
  • [x] 与后端API集成
  • [x] 错误处理和加载状态
  • [x] 类型安全实现(无“任何”类型)
  • [x] 安全改进(源验证、基于环境的日志记录)
  • [x] 内存管理(TTL、清理、限制)

✨ 生产就绪功能

  • [x] 具有完全类型安全的TypeScript严格模式
  • [x] 安全性:邮件来源验证
  • [x] 内存管理:对话TTL(1小时)和自动清理
  • [x] 错误处理:全面的try-catch块
  • [x] 基于环境的日志记录(仅限DEV)
  • [x] React最佳实践:正确的钩子依赖关系

用例

1.餐厅预订表

用户请求预订→ LLM显示交互式表单→ 用户填写表单→ 已提交预订

2.选择

用户请求推荐→ LLM显示选择按钮→ 用户选择选项→ 对话继续

餐厅预约演示的处理流程

下图显示了餐厅预订演示的完整流程:

sequenceDiagram
    participant User as ユーザー
    participant Client as クライアント<br/>(React)
    participant Server as Expressサーバー
    participant OpenAI as OpenAI API
    participant MCPServer as MCPサーバー

    User->>Client: 「レストランを予約したい」
    Client->>Server: POST /api/chat
    Server->>OpenAI: Chat completion with function calling
    OpenAI->>Server: Function call: show_reservation_form
    Server->>MCPServer: POST /tools/show_reservation_form
    MCPServer->>Server: UIResource (予約フォーム)
    Server->>Client: Response with UIResource
    Client->>User: 予約フォームUI表示<br/>(店名, 名前, 日付, 時間, 人数, 連絡先)

    User->>Client: フォーム入力 → 送信
    Client->>Server: POST /api/tool-call<br/>(submit_reservation)
    Server->>MCPServer: POST /tools/submit_reservation
    MCPServer->>Server: UIResource (予約完了パネル)
    Server->>OpenAI: Process tool result
    OpenAI->>Server: Response message
    Server->>Client: Response with UIResource
    Client->>User: 予約完了パネルUI表示<br/>「予約しました。他に確認したいことはありますか?」<br/>[アレルギーについて] [個室ですか]

    User->>Client: 「アレルギーについて」ボタンクリック
    Client->>Server: POST /api/tool-call<br/>(ask_allergy)
    Server->>MCPServer: POST /tools/ask_allergy
    MCPServer->>Server: UIResource (アレルギー問い合わせフォーム)
    Server->>OpenAI: Process tool result
    OpenAI->>Server: Response message
    Server->>Client: Response with UIResource
    Client->>User: アレルギー問い合わせフォームUI表示

    User->>Client: 「小麦アレルギー」入力 → 送信
    Client->>Server: POST /api/tool-call<br/>(submit_allergy_inquiry)
    Server->>MCPServer: POST /tools/submit_allergy_inquiry
    MCPServer->>Server: UIResource (最終メッセージ)
    Server->>OpenAI: Process tool result
    OpenAI->>Server: Response message
    Server->>Client: Response with UIResource
    Client->>User: 最終メッセージUI表示<br/>「✓ アレルギー情報を承知いたしました」

处理流程详细信息

  1. 保留表单显示

    • 用户输入“想预约餐厅”
    • LLM的show_reservation_form调用函数
    • 保留表单UI(店名、名称、日期、时间、人数、联系方式)
  2. 预约发送和完成面板显示

    • 用户在表单中输入并提交
    • submit_reservation调用并处理保留
    • 显示“保留完成”面板并显示相关操作按钮
  3. 过敏咨询

    • 点击“关于过敏”按钮
    • ask_allergy被调用,显示过敏咨询表格
  4. 过敏信息发送和最终消息

    • 输入“小麦过敏”发送
    • submit_allergy_inquiry被调用,最后一条消息UI显示

环境变量

变量 描述 默认值
PORT Express服务器端口 3000
OPENAI_API_KEY OpenAI API密钥 (必需)
MCP_PORT MCP服务器端口 3001
MCP_SERVER_URL MCP服务器URL http://localhost:3001
VITE_API_URL 客户端 的API URLhttp://localhost:3000

技术栈

  • 前端: React 18、TypeScript、Vite
  • 后端: Express、TypeScript、OpenAI SDK
  • MCP: 模型上下文协议SDK
  • 工具: ESLint、Prettier、tsx、并发

贡献

这是JSConf的一个演示项目。如有疑问或建议,请打开一个问题。

许可证

麻省理工学院

参考文献