本次更新内容: 1. 修复 json-render-catalog.tsx - 简化 translate_text case,只保留 translated 和 termsUsed 字段 2. 修复 json-render-registry.tsx - 简化 TranslationResult 组件,移除原文/语言标签,只显示译文和术语 3. 添加复制按钮反馈 - 点击后显示"已复制!",2秒后恢复 4. 修复数据解析逻辑 - 处理 dataObj.result 不存在的情况 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
21 KiB
AI MCP Web UI - 模板 240 项目说明
项目概述
AI MCP Web UI 是一个通用的 Web 界面,让用户通过浏览器与 Claude AI 对话,AI 调用后台 MCP 服务器完成各种任务。
一个界面,连接所有 MCP:
- ✅ Novel Translator MCP - 翻译工具
- ✅ Novel Platform User MCP - 读者功能
- ✅ Novel Platform Admin MCP - 管理员功能
- ✅ 未来任何 MCP - 通用扩展
关键配置要求
前端服务必须运行在端口 `8080` 才能被外网访问!
| 服务 | 端口 | 说明 |
|---|---|---|
| Next.js 前端 | 8080 | 外网访问入口 |
| FastAPI 后端 | 8081 | 内部服务(通过 Next.js 代理访问) |
- 内网前端: `http://localhost:8080`
- 内网后端: `http://localhost:8081` (仅供内部调试)
- 外网前端: `https://d8d-ai-vscode-8080-223-240-template-6-group.dev.d8d.fun/`
⚠️ 重要:
- 前端必须运行在 8080 端口才能被外网访问
- 后端运行在 8081 端口,通过 Next.js rewrites 代理 `/api/*` 到后端
- 外网只能访问前端,无法直接访问后端
技术架构
前端技术栈
| 技术 | 版本 | 用途 |
|---|---|---|
| Next.js | 14.2.18 | React 框架,App Router |
| React | 18.3.1 | UI 库 |
| TypeScript | 5 | 类型安全 |
| Tailwind CSS | 3.4.1 | 样式框架 |
| @json-render/* | 0.14.1 | 生成式 UI 系统 |
| TanStack Query | 5.62.0 | 状态管理 |
| Zod | 4.3.6 | 数据验证 |
| SuperJSON | 2.2.2 | 序列化 |
React 组件系统
json-render 组件(15 个):
基础组件 (8 个):
- `Card` - 卡片容器
- `Stack` - 弹性布局容器
- `Heading` - 标题(h1-h6)
- `Text` - 文本内容
- `Button` - 按钮(支持 onClick 回调)
- `Input` - 输入框(支持 onChange 回调)
- `Badge` - 徽章标签
- `Separator` - 分隔线
MCP 专用组件 (7 个):
- `TranslationResult` - 翻译结果展示
- `NovelList` - 小说列表
- `ChapterReader` - 章节阅读器
- `McpToolCall` - 工具调用可视化
- `LoginPanel` - 登录面板
- `CodeBlock` - 代码块
- `DataTable` - 数据表格
MCP 管理组件:
- `McpServerCard` - MCP 服务器卡片组件,显示连接状态和登录表单
聊天组件:
- `ChatInput` - 聊天输入框,支持发送和中断
- `ChatMessage` - 聊天消息显示组件
- `Header` - 页面头部导航
- `ToolCallPanel` - 工具调用面板(侧边栏)
项目结构
``` /mnt/code/223-240-template-6/ ├── backend/ # FastAPI 后端服务 │ ├── app_fastapi.py # 主应用入口(SSE 流式端点) │ ├── config.py # 配置文件 │ ├── mcp_client.py # MCP 客户端 │ ├── conversation_manager.py # 对话管理器 │ ├── tool_handler.py # 工具调用处理器 │ └── tool_converter.py # 工具格式转换器 ├── frontend-v2/ # Next.js 14 前端 │ ├── app/ # Next.js App Router │ │ ├── page.tsx # 主页面(聊天界面) │ │ ├── layout.tsx # 根布局 │ │ ├── mcp/page.tsx # MCP 管理页面 │ │ └── auth/page.tsx # 认证页面 │ ├── components/ # React 组件 │ │ ├── JsonRenderer.tsx # json-render 渲染器 │ │ ├── McpServerCard.tsx # MCP 服务器卡片 │ │ ├── ChatInput.tsx # 聊天输入框 │ │ ├── ChatMessage.tsx # 聊天消息 │ │ ├── Header.tsx # 页面头部 │ │ └── ToolCallPanel.tsx # 工具调用面板 │ └── lib/ # 工具库 │ ├── api-client.ts # SSE 客户端 │ ├── hooks.ts # useChat() Hook │ ├── mcp-token-manager.ts # MCP Token 管理器 │ ├── json-render-catalog.tsx # 组件 Schema │ └── json-render-registry.tsx # 组件注册 ├── frontend/ # 旧版前端(参考) │ └── index.html # 单页面应用 ├── CLAUDE.md # 本文档 └── JSON_RENDER_USAGE.md # json-render 使用文档 ```
核心功能
1. 流式输出(SSE)
使用 Server-Sent Events (SSE) 实现实时 token 输出,解决 504 超时问题。
SSE 事件类型:
| 事件 | 说明 |
|---|---|
| `start` | 开始处理 |
| `tools` | 显示可用工具 |
| `token` | 实时文本片段 |
| `tool_call` | 调用工具 |
| `tool_done` | 工具执行完成 |
| `tool_error` | 工具执行错误 |
| `complete` | 完成 |
| `error` | 发生错误 |
2. MCP 工具调用
完整的 tool_use 流程支持:
- 工具调用可视化(`McpToolCall` 组件)
- 工具执行状态追踪
- 工具结果渲染
3. 身份认证
JWT Token 登录(Platform MCP):
- 登录面板:`LoginPanel` 组件
- Token 自动附加到请求头
- 支持三个 MCP 服务器切换
4. MCP 管理架构
MCP Token 管理机制:
``` ┌─────────────────────────────────────────────────────────────────────────┐ │ MCP Token 管理流程 │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ 登录请求 ┌─────────────────────────────────┐ │ │ │ 用户界面 │ ─────────────→ │ 后端代理端点 │ │ │ │ /mcp 页面 │ │ /api/auth/login │ │ │ └─────────────┘ │ /api/auth/admin-login │ │ │ ↑ └──────────────┬──────────────────┘ │ │ │ │ │ │ │ ↓ │ │ │ ┌─────────────────────────────────┐ │ │ │ │ Novel Platform 后端 │ │ │ │ │ (模板 238) │ │ │ │ └──────────────┬──────────────────┘ │ │ │ │ │ │ │ ↓ │ │ │ ┌─────────────────────────────────┐ │ │ │ │ 返回 JWT Token │ │ │ │ └──────────────┬──────────────────┘ │ │ │ │ │ │ │ Token 存储 ↓ │ │ │ ┌─────────────────────────────────────────────────────────┐│ │ └─ │ McpTokenManager (localStorage) ││ │ │ - mcp_token_novel-platform-user ││ │ │ - mcp_token_novel-platform-admin ││ │ │ - mcp_username_* ││ │ │ - mcp_token_*_time (存储时间) ││ │ └──────────────────────────┬──────────────────────────────┘│ │ │ │ │ │ X-MCP-Tokens header │ │ ↓ │ │ ┌─────────────────────────────────────────────────────────┐│ │ │ API 客户端 ││ │ │ chatStreamFetch() 自动附加所有已登录的 MCP Token ││ │ └──────────────────────────┬──────────────────────────────┘│ │ │ │ │ ↓ │ │ ┌─────────────────────────────────────────────────────────┐│ │ │ 后端处理 (ConversationManager) ││ │ │ - 解析 X-MCP-Tokens header ││ │ │ - 创建 ToolCallHandler 时传入 tokens ││ │ │ - 调用 MCP 工具时自动附加 Authorization header ││ │ └─────────────────────────────────────────────────────────┘│ │ │ └─────────────────────────────────────────────────────────────────────────┘ ```
核心组件:
| 组件 | 文件路径 | 职责 |
|---|---|---|
| `McpTokenManager` | `lib/mcp-token-manager.ts` | Token 管理单例,负责存储、获取、清除 Token |
| `McpServerCard` | `components/McpServerCard.tsx` | MCP 服务器卡片组件,显示登录状态 |
| MCP 管理页面 | `app/mcp/page.tsx` | MCP 管理主页面 |
MCP 服务器配置:
```typescript export const MCP_SERVERS: Record<string, McpServerConfig> = { 'novel-translator': { id: 'novel-translator', name: 'Novel Translator MCP', url: '...', authType: 'none', // 无需登录 }, 'novel-platform-user': { id: 'novel-platform-user', name: 'Novel Platform User MCP', url: '...', authType: 'jwt', // 需要登录 loginApi: '/api/v1/auth/login', }, 'novel-platform-admin': { id: 'novel-platform-admin', name: 'Novel Platform Admin MCP', url: '...', authType: 'jwt', // 需要登录 loginApi: '/api/v1/auth/admin-login', }, }; ```
Token 传递流程:
- 用户在 `/mcp` 页面登录某个 MCP 服务器
- `McpTokenManager.loginMcp()` 调用后端代理端点 `/api/auth/login`
- 后端代理到 Novel Platform 后端获取 JWT Token
- Token 保存到 `localStorage`
- 用户发起聊天时,`ApiClient.chatStreamFetch()` 自动附加所有已登录的 Token 到 `X-MCP-Tokens` header
- 后端解析 Token 并在调用 MCP 工具时附加到请求头
预设 MCP 服务器
| MCP | URL | 认证 |
|---|---|---|
| Novel Translator | `https://d8d-ai-vscode-8080-223-236-template-6-group.dev.d8d.fun/mcp` | 无需登录 |
| Platform User | `https://d8d-ai-vscode-8080-223-238-template-6-group.dev.d8d.fun/mcp/` | JWT Token |
| Platform Admin | `https://d8d-ai-vscode-8080-223-238-template-6-group.dev.d8d.fun/admin-mcp/` | JWT Token |
开发指南
环境准备
```bash
安装前端依赖
cd frontend-v2 npm install
安装后端依赖
cd ../backend pip install -r requirements.txt ```
启动服务
使用启动脚本(推荐):
```bash
启动后端(端口 8081,热重载模式)
./scripts/start_dev.sh
停止后端
./scripts/stop_dev.sh
启动前端(端口 8080)
cd frontend-v2 npm run dev -- --port 8080 ```
手动启动:
```bash
启动后端(端口 8081)
cd backend python3 -m uvicorn app_fastapi:app --host 0.0.0.0 --port 8081 --reload
启动前端(端口 8080)
cd frontend-v2 npm run dev -- --port 8080 ```
验证服务
- 检查后端:访问 `http://localhost:8081/api/health`
- 检查前端:访问 `http://localhost:8080`
- 检查代理:访问 `http://localhost:8080/api/health`(通过前端代理到后端)
- 外网访问:使用外网地址格式
json-render 使用
定义组件 Spec
```typescript import { CardSchema, StackSchema, TextSchema } from '@/lib/json-render-catalog';
const cardSpec = { type: 'card', title: '翻译结果', children: [ { type: 'text', content: 'Lin Feng is an outer disciple.', variant: 'body' } ] }; ```
渲染组件
```tsx import { JsonRenderer } from '@/components/JsonRenderer';
\`\`\`从工具调用创建 Spec
```typescript import { specFromToolCall } from '@/lib/json-render-catalog';
const toolCall = { tool_id: 'translate_text__123', name: 'translate_text', result: '{"success": true, "translated": "..."}' };
const spec = specFromToolCall(toolCall); ```
故障排除
问题 1: 外网无法访问
症状: 使用外网地址访问时显示连接失败
原因: 服务未运行在 8080 端口
解决方案: ```bash
检查服务端口
netstat -tuln | grep 8080
确保后端以端口 8080 启动
cd backend python app_fastapi.py ```
问题 2: CORS 错误
症状: 前端请求被 CORS 策略阻止
解决方案: 确认 `backend/app_fastapi.py` 中已正确配置 CORS
问题 3: MCP 工具调用失败
症状: AI 响应显示工具调用错误
检查项目:
- 后端日志是否有错误信息
- MCP 配置是否正确
- Claude API 密钥是否有效
问题 4: 翻译结果不显示
症状: 工具执行成功但结果不显示
解决方案: 检查 `lib/json-render-catalog.tsx` 中的 `specFromToolCall` 函数是否正确解析 result 字段
更新日志
- 2026-03-18: 添加 MCP 管理架构 - MCP Token 管理机制
- 2026-03-18: 新增 MCP 管理页面 (`/mcp`) 和 `McpServerCard` 组件
- 2026-03-18: 实现 `McpTokenManager` 单例类管理多个 MCP 的登录状态
- 2026-03-18: 更新架构说明 - Next.js 14 + json-render 架构完成
- 2026-03-18: 添加 15 个 json-render 组件文档
- 2026-03-16: 实现流式输出解决 504 超时问题
- 2026-03-16: 前端 UI 优化 - 工具调用过程可视化
- 2026-03-16: 实现完整的 MCP 工具调用管道
测试结果与已知问题
测试通过项
| 功能 | 状态 | 说明 |
|---|---|---|
| MCP Token 存储 | ✅ | Token 正确保存到 localStorage |
| MCP Token 读取 | ✅ | Token 正确从 localStorage 读取 |
| MCP 登录界面 | ✅ | `/mcp` 页面正常显示 |
| 登录状态显示 | ✅ | 已登录/未连接状态正确显示 |
| Token 传递到后端 | ✅ | `X-MCP-Tokens` header 正确传递 |
| 多 MCP 同时登录 | ✅ | 支持同时登录多个 MCP 服务器 |
已知问题
| 问题 | 影响 | 解决方案 |
|---|---|---|
| SSR 兼容性 | `localStorage` 在服务端不可用 | 使用 `typeof window === 'undefined'` 检查 |
| Token 过期处理 | Token 过期后不会自动刷新 | 需要用户手动重新登录 |
| Token 持久化 | 刷新页面后 Token 可能丢失 | 确保 `localStorage` 正常工作 |
调试建议
-
检查 Token 存储: ```javascript // 在浏览器控制台运行 localStorage.getItem('mcp_token_novel-platform-user') localStorage.getItem('mcp_username_novel-platform-user') ```
-
检查请求头: ```javascript // 在浏览器开发者工具 Network 面板查看 // 请求头应包含: X-MCP-Tokens: {"novel-platform-user":"..."} ```
-
检查后端日志: ```
后端应输出:
[DEBUG /api/chat/stream] mcp_tokens type: <class 'str'> [DEBUG /api/chat/stream] mcp_tokens value: {"novel-platform-user":"..."} [DEBUG ConversationManager.init] mcp_tokens keys: ['novel-platform-user'] ```
内外层架构
本项目采用双层 BMAD 专家协作架构:
┌─────────────────────────────────────────────────────────────────┐
│ 外层 BMAD 专家 │
│ (本地协调会话) │
│ │
│ 职责: │
│ • 协调指挥多个容器内的子代理 │
│ • 传达用户需求和任务指令 │
│ • 审查子代理的工作进度和结果 │
│ • 管理项目间的依赖关系 │
│ │
│ ⚠️ 注意:外层不存储代码、不提交 Git │
└────────┬────────────────────────────────────┬────────────────────┐
│ │ │
│ MCP 调用 │ MCP 调用 │
│ d8d_invoke_dev_container_subagent │ d8d_invoke_dev... │
↓ ↓ ↓
┌─────────────────────────────┐ ┌─────────────────────────────────┐ ┌───────────────────┐
│ 容器内 BMAD 专家 A │ │ 容器内 BMAD 专家 B │ │ 容器内 BMAD 专家 C│
│ (模板 236 - 序灵助手) │ │ (模板 238 - Novel Platform) │ │ (模板 240 - Web UI)│
│ │ │ │ │ │
│ • 翻译工具开发 │ │ • 小说平台开发 │ │ • Next.js 14 UI │
│ • 清洗/术语/翻译/上传 │ │ • 读者端/作者端 │ │ • json-render 组件│
│ • PyQt6 桌面应用 │ │ • 支付/提现/后台 │ │ • SSE 流式输出 │
│ │ │ │ │ • MCP 工具调用 │
│ 📁 /mnt/code/223-236-... │ │ 📁 /mnt/code/223-238-... │ │ 📁 /mnt/code/223-240│
│ ✅ 100% 完成 │ │ ✅ 后端完成 (100%) │ │ ✅ 完成 │
└─────────────────────────────┘ └─────────────────────────────────┘ └───────────────────┘
核心原则:
- 容器是主工作区:所有代码、文档、任务、Git 提交都在容器内完成
- 外层是指挥官:只负责协调和指挥,不产生实际工作产物
- 工作空间共享:模板 236、238、240 同属工作空间 223,便于管理
开发者注意事项
- 端口固定: 服务端口固定为 8080,不可随意更改
- 外网地址格式: `https://d8d-ai-vscode-8080-{workspace_id}-{item_id}-template-6-group.dev.d8d.fun/`
- 流式响应: 使用 Server-Sent Events (SSE) 实现流式输出
- CORS 配置: 后端需要正确配置 CORS 以支持前端跨域请求
- json-render: 使用 Zod Schema 定义组件,确保类型安全