AI MCP Web UI 是一个通用的 Web 界面,让用户通过浏览器与 Claude AI 对话,AI 调用后台 MCP 服务器完成各种任务。
一个界面,连接所有 MCP:
前端服务必须运行在端口 `8080` 才能被外网访问!
| 服务 | 端口 | 说明 |
|---|---|---|
| Next.js 前端 | 8080 | 外网访问入口 |
| FastAPI 后端 | 8081 | 内部服务(通过 Next.js 代理访问) |
⚠️ 重要:
- 前端必须运行在 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 | 序列化 |
json-render 组件(15 个):
基础组件 (8 个):
MCP 专用组件 (7 个):
MCP 管理组件:
聊天组件:
``` /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 使用文档 ```
使用 Server-Sent Events (SSE) 实现实时 token 输出,解决 504 超时问题。
SSE 事件类型: | 事件 | 说明 | |------|------| | `start` | 开始处理 | | `tools` | 显示可用工具 | | `token` | 实时文本片段 | | `tool_call` | 调用工具 | | `tool_done` | 工具执行完成 | | `tool_error` | 工具执行错误 | | `complete` | 完成 | | `error` | 发生错误 |
完整的 tool_use 流程支持:
JWT Token 登录(Platform 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 ││ │ │ - mcpusername* ││ │ │ - mcptoken*_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 = { '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 | 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
./scripts/start_dev.sh
./scripts/stop_dev.sh
cd frontend-v2 npm run dev -- --port 8080 ```
手动启动:
```bash
cd backend python3 -m uvicorn app_fastapi:app --host 0.0.0.0 --port 8081 --reload
cd frontend-v2 npm run dev -- --port 8080 ```
```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';
```
```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); ```
症状: 使用外网地址访问时显示连接失败
原因: 服务未运行在 8080 端口
解决方案: ```bash
netstat -tuln | grep 8080
cd backend python app_fastapi.py ```
症状: 前端请求被 CORS 策略阻止
解决方案: 确认 `backend/app_fastapi.py` 中已正确配置 CORS
症状: AI 响应显示工具调用错误
检查项目:
症状: 工具执行成功但结果不显示
解决方案: 检查 `lib/json-render-catalog.tsx` 中的 `specFromToolCall` 函数是否正确解析 result 字段
| 功能 | 状态 | 说明 |
|---|---|---|
| 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: [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%) │ │ ✅ 完成 │
└─────────────────────────────┘ └─────────────────────────────────┘ └───────────────────┘
核心原则: