9223ceca50
- 规则重组:全局/ 下 8 个规则合并为 6 个(01+02→01,05+06→04),序号顺延 - 新增项目规则 05-多入口功能同步规范(UI/语音入口覆盖检查) - 新增 MCP 服务基础设施:Mcp/ 目录(DI 注册、端点扩展、动态工具描述符)、单元测试 - v1.3.0 工单文档:03 系列(会议任务拆分)、04(富文本描述与附件管理) - MCP 接口与前端集成指南:docs/manual/08、09
5.7 KiB
5.7 KiB
MCP 前端集成指南(Hua.Todo 内部使用)
适用范围:Hua.Todo 前端(Vue / TypeScript)团队,通过 MCP 协议与后端交互。 外部系统接入请参阅 08-MCP服务接口文档.md。
一、背景
v1.3.0 起,Hua.Todo 后端在原有 Dynamic API(/api/*)基础上,新增了 MCP(Model Context Protocol)服务端点。前端可根据场景选择:
| 通道 | 端点 | 适用场景 |
|---|---|---|
| Dynamic API | /api/task/* |
WebView 内常规 CRUD、已有逻辑兼容 |
| MCP | /mcp |
AI 辅助、语音指令、外部工具集成 |
两套通道共享同一 ITaskService 业务层,数据一致。
二、连接方式
2.1 嵌入式模式(MAUI / Avalonia + WebView)
MCP 端点:http://localhost:5057/mcp
当前嵌入式宿主仅暴露 Dynamic API,MCP 端点在嵌入式模式下同样可用(AddMcpServerServices 已注册)。
2.2 Host 模式(独立服务端)
MCP 端点:http://<host>:5173/mcp
开发环境通过 Vite proxy 可直接访问 /mcp。
三、前端 MCP 客户端选型
3.1 推荐方案:@modelcontextprotocol/sdk
官方 TypeScript MCP SDK,支持 Streamable HTTP 传输。
npm install @modelcontextprotocol/sdk
3.2 连接示例
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamablehttp.js";
const transport = new StreamableHTTPClientTransport(
new URL("http://localhost:5057/mcp")
);
const client = new Client({
name: "hua-todo-frontend",
version: "1.3.0",
});
await client.connect(transport);
// 列出所有可用工具
const tools = await client.listTools();
console.log("可用工具:", tools);
// 调用工具
const result = await client.callTool({
name: "ListActiveTodos",
arguments: {},
});
console.log("未完成待办项:", result);
3.3 封装建议
在 src/Hua.Todo.Web/src/api/ 下新增 mcpClient.ts:
// src/api/mcpClient.ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamablehttp.js";
const MCP_BASE_URL = window.__API_BASE_URL__
? window.__API_BASE_URL__.replace("/api", "/mcp")
: "/mcp";
let client: Client | null = null;
/** 获取或创建 MCP 客户端单例 */
export async function getMcpClient(): Promise<Client> {
if (!client) {
const transport = new StreamableHTTPClientTransport(
new URL(MCP_BASE_URL, window.location.origin)
);
client = new Client({
name: "hua-todo-frontend",
version: "1.3.0",
});
await client.connect(transport);
}
return client;
}
/** 断开 MCP 连接 */
export async function disconnectMcp(): Promise<void> {
if (client) {
await client.close();
client = null;
}
}
四、工具调用映射(MCP vs Dynamic API)
| 业务操作 | Dynamic API | MCP Tool | MCP 参数 |
|---|---|---|---|
| 获取所有待办项 | GET /api/task |
ListAllTodos |
无 |
| 获取未完成待办项 | GET /api/task/active |
ListActiveTodos |
无 |
| 获取已完成待办项 | GET /api/task/completed |
ListCompletedTodos |
无 |
| 获取单个待办项 | GET /api/task/{id} |
GetTodoById |
id: number |
| 创建待办项 | POST /api/task |
CreateTodo |
title, priority?, parentTaskId? |
| 更新待办项 | PUT /api/task |
UpdateTodo |
id, title?, priority? |
| 切换完成状态 | PATCH /api/task/{id}/toggle |
ToggleTodoComplete |
id: number |
| 删除待办项 | DELETE /api/task/{id} |
DeleteTodo |
id: number |
| 获取子待办项 | GET /api/task/{pid}/subtasks |
ListSubTodos |
parentTaskId: number |
五、返回格式差异
Dynamic API 返回
{
"success": true,
"data": [{ "id": 1, "title": "...", ... }],
"message": "",
"errors": []
}
MCP Tool 返回
MCP 工具返回 string 类型,分两种格式:
列表类(可读文本):
未完成待办项(共 2 项):
[1] 完成报告 | 优先级:High | 进行中
[3] 买菜 | 优先级:Low | 进行中 | 父ID:2
单条/创建/更新类(JSON):
{
"id": 1,
"title": "完成报告",
"priority": "High",
"isCompleted": false,
"createdAt": "2026-06-16T08:00:00Z",
"updatedAt": "2026-06-16T08:00:00Z",
"parentTaskId": null,
"subTasks": []
}
前端如果需要结构化数据,建议仍使用 Dynamic API;MCP 通道主要用于 AI 场景和文本交互。
六、典型场景
6.1 AI 对话式操作
用户通过 AI 助手(接入 MCP 的 LLM 客户端)用自然语言操作待办项:
用户:帮我看看还有哪些事没做完
AI:→ 调用 ListActiveTodos
AI:您有 2 项未完成的待办:[1] 完成报告 [3] 买菜
用户:把"完成报告"标为已完成
AI:→ 调用 ToggleTodoComplete(id=1)
AI:已将"完成报告"标记为完成
6.2 语音指令
语音 → STT → 文本 → LLM 解析意图 → MCP Tool 调用 → TTS 播报结果。
6.3 外部工具集成
IDE 插件、自动化脚本等通过 MCP 协议直接操作待办项,无需理解 HTTP API 细节。
七、注意事项
- MCP 无状态模式:当前配置为 Stateless,不支持服务端→客户端通知;如需实时推送仍走 Dynamic API 或 WebSocket
- CORS:开发环境
AllowAll策略已覆盖/mcp;生产环境需按需配置 - 认证:当前 MCP 端点未接入认证中间件;如需鉴权,需在
MapMcpServer后追加.RequireAuthorization() - 生命周期:MCP 客户端连接为长连接,建议在组件
onUnmounted时调用disconnectMcp()