From e019c9e8b3875b80652c3b75d9781a7733fb409b Mon Sep 17 00:00:00 2001 From: samanhappy Date: Wed, 28 May 2025 18:20:43 +0800 Subject: [PATCH] fix: simplify server status labels in English and Chinese locales (#128) --- README.md | 33 ++- README.zh.md | 33 ++- assets/smart-routing.png | Bin 0 -> 32561 bytes assets/smart-routing.zh.png | Bin 0 -> 32674 bytes doc/smart-routing.md | 271 ++++++++++++++++++++++ frontend/src/components/AddServerForm.tsx | 2 +- frontend/src/locales/en.json | 8 +- frontend/src/locales/zh.json | 10 +- frontend/src/pages/ServersPage.tsx | 20 +- 9 files changed, 355 insertions(+), 22 deletions(-) create mode 100644 assets/smart-routing.png create mode 100644 assets/smart-routing.zh.png create mode 100644 doc/smart-routing.md diff --git a/README.md b/README.md index 0464892..134bfac 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ MCPHub makes it easy to manage and scale multiple MCP (Model Context Protocol) s ## 🔧 Quick Start -### Optional Configuration +### Configuration Create a `mcp_settings.json` file to customize your server settings: @@ -96,6 +96,31 @@ This endpoint provides a unified streamable HTTP interface for all your MCP serv - Easily integrate with various AI clients and tools - Use the same endpoint for all servers, simplifying your integration process +**Smart Routing (Experimental)**: + +Smart Routing is MCPHub's intelligent tool discovery system that uses vector semantic search to automatically find the most relevant tools for any given task. + +``` +http://localhost:3000/mcp/$smart +``` + +**How it Works:** + +1. **Tool Indexing**: All MCP tools are automatically converted to vector embeddings and stored in PostgreSQL with pgvector +2. **Semantic Search**: User queries are converted to vectors and matched against tool embeddings using cosine similarity +3. **Intelligent Filtering**: Dynamic thresholds ensure relevant results without noise +4. **Precise Execution**: Found tools can be directly executed with proper parameter validation + +**Setup Requirements:** + +![Smart Routing](assets/smart-routing.png) + +To enable Smart Routing, you need: + +- PostgreSQL with pgvector extension +- OpenAI API key (or compatible embedding service) +- Enable Smart Routing in MCPHub settings + **Group-Specific Endpoints (Recommended)**: ![Group Management](assets/group.png) @@ -131,6 +156,12 @@ Connect AI clients (e.g., Claude Desktop, Cursor, DeepChat, etc.) via: http://localhost:3000/sse ``` +For smart routing, use: + +``` +http://localhost:3000/sse/$smart +``` + For targeted access to specific server groups, use the group-based SSE endpoint: ``` diff --git a/README.zh.md b/README.zh.md index da77511..8971274 100644 --- a/README.zh.md +++ b/README.zh.md @@ -18,7 +18,7 @@ MCPHub 通过将多个 MCP(Model Context Protocol)服务器组织为灵活 ## 🔧 快速开始 -### 可选配置 +### 配置 通过创建 `mcp_settings.json` 自定义服务器设置: @@ -96,6 +96,31 @@ http://localhost:3000/mcp - 轻松与各种 AI 客户端和工具集成 - 对所有服务器使用相同的端点,简化集成过程 +**智能路由(实验性功能)**: + +智能路由是 MCPHub 的智能工具发现系统,使用向量语义搜索自动为任何给定任务找到最相关的工具。 + +``` +http://localhost:3000/mcp/$smart +``` + +**工作原理:** + +1. **工具索引**:所有 MCP 工具自动转换为向量嵌入并存储在 PostgreSQL 与 pgvector 中 +2. **语义搜索**:用户查询转换为向量并使用余弦相似度与工具嵌入匹配 +3. **智能筛选**:动态阈值确保相关结果且无噪声 +4. **精确执行**:找到的工具可以直接执行并进行适当的参数验证 + +**设置要求:** + +![智能路由](assets/smart-routing.zh.png) + +为了启用智能路由,您需要: + +- 支持 pgvector 扩展的 PostgreSQL +- OpenAI API 密钥(或兼容的嵌入服务) +- 在 MCPHub 设置中启用智能路由 + **基于分组的 HTTP 端点(推荐)**: ![分组](assets/group.zh.png) 要针对特定服务器分组进行访问,请使用基于分组的 HTTP 端点: @@ -131,6 +156,12 @@ http://localhost:3000/mcp/{server} http://localhost:3000/sse ``` +要启用智能路由,请使用: + +``` +http://localhost:3000/sse/$smart +``` + 要针对特定服务器分组进行访问,请使用基于分组的 SSE 端点: ``` diff --git a/assets/smart-routing.png b/assets/smart-routing.png new file mode 100644 index 0000000000000000000000000000000000000000..561c05f63ef66dcf603219a696844b4d56fa3221 GIT binary patch literal 32561 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 literal 0 HcmV?d00001 diff --git a/assets/smart-routing.zh.png b/assets/smart-routing.zh.png new file mode 100644 index 0000000000000000000000000000000000000000..95b4a5f3557c40e8a6ce9a6d5a347d103f0b1ac2 GIT binary patch literal 32674 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 KRe07m`2PVrh@%4l literal 0 HcmV?d00001 diff --git a/doc/smart-routing.md b/doc/smart-routing.md new file mode 100644 index 0000000..5dcee9e --- /dev/null +++ b/doc/smart-routing.md @@ -0,0 +1,271 @@ +# 智能工具发现,精准调用:MCPHub 智能路由重新定义 AI 工具选择 + +## 概述 + +在现代 AI 应用中,随着 MCP 服务器数量的快速增长和工具种类的日益丰富,如何从数百个可用工具中快速找到最适合当前任务的工具,成为了一个日益突出的挑战。传统方式下,AI 助手要么被迫处理所有可用工具的庞大列表,导致 token 消耗激增和响应延迟,要么依赖开发者手动分组,缺乏灵活性和智能化。MCPHub 的智能路由功能基于向量语义搜索技术,实现了自然语言驱动的工具发现与精准推荐,让 AI 助手能够像人类专家一样,根据任务描述智能地选择最合适的工具组合,大幅提升工作效率和用户体验。 + +## 智能路由是什么 + +### 技术原理 + +智能路由是 MCPHub 的核心创新功能,它基于现代向量语义搜索技术,将每个 MCP 工具的描述、参数和功能特征转换为高维向量表示。当用户提出任务需求时,系统将需求同样转换为向量,通过计算向量间的余弦相似度,快速定位最相关的工具集合。这种方法不依赖精确的关键词匹配,而是理解语义层面的相关性,能够处理自然语言的模糊性和多样性。 + +### 核心组件 + +**向量嵌入引擎**:支持 OpenAI text-embedding-3-small、BGE-M3 等多种主流嵌入模型,将工具描述转换为 1536 维或 1024 维向量表示,捕获工具功能的语义特征。 + +**PostgreSQL + pgvector 数据库**:采用业界领先的向量数据库解决方案,支持高效的向量索引和相似度搜索,能够在毫秒级时间内从大量工具中找到最相关的候选。 + +**动态阈值算法**:根据查询复杂度和具体程度自动调整相似度阈值,确保既不遗漏相关工具,也不引入无关噪声。简单查询使用较低阈值(0.2)获得更多样化结果,具体查询使用较高阈值(0.4)确保精确匹配。 + +**两步工作流**:`search_tools` 负责工具发现,`call_tool` 负责工具执行,清晰分离发现和执行逻辑,提供更好的可控性和调试体验。 + +## 为什么要使用智能路由 + +### 1. 解决工具选择的认知负荷 + +- **信息过载问题**:当 MCP 服务器数量超过 10 个、工具总数超过 100 个时,AI 助手面临严重的信息过载,难以在合理时间内做出最优选择。 +- **智能路由优势**:通过语义搜索将候选工具缩减到 5-10 个最相关的选项,让 AI 助手能够专注于理解和使用最合适的工具,而不是被迫处理庞大的工具清单。 + +### 2. 大幅降低 Token 消耗 + +- **传统方式的成本**:向 AI 模型传递完整的工具列表会消耗大量 token,特别是当工具描述详细时,单次请求可能消耗数千 token。 +- **智能路由的效益**:只传递最相关的工具信息,通常可以将工具相关的 token 消耗降低 70-90%,显著减少 API 调用成本,特别是在频繁交互的场景中。 + +### 3. 提升工具使用的准确性 + +- **语义理解能力**:智能路由能够理解"图片处理"、"数据分析"、"文档转换"等抽象概念,将其映射到具体的工具实现,避免了传统关键词匹配的局限性。 +- **上下文感知**:考虑工具的输入输出模式和使用场景,推荐最适合当前任务流程的工具组合。 + +![智能路由工作原理](../assets/smart-routing-flow.png) + +## 如何使用智能路由 + +### 配置智能路由 + +#### 1. 数据库配置 + +智能路由需要 PostgreSQL 数据库支持 pgvector 扩展: + +```bash +# 使用 Docker 快速启动支持 pgvector 的 PostgreSQL +docker run --name mcphub-postgres \ + -e POSTGRES_DB=mcphub \ + -e POSTGRES_USER=mcphub \ + -e POSTGRES_PASSWORD=your_password \ + -p 5432:5432 \ + -d pgvector/pgvector:pg16 +``` + +#### 2. 在 MCPHub 控制台配置智能路由 + +访问 MCPHub 设置页面(http://localhost:3000/settings),在"智能路由配置"部分填写: + +- **数据库 URL**:`postgresql://mcphub:your_password@localhost:5432/mcphub` +- **OpenAI API Key**:您的 OpenAI API 密钥 +- **API Base URL**:可选,默认为 `https://api.openai.com/v1` +- **嵌入模型**:推荐使用 `text-embedding-3-small`(1536 维,性价比最佳) + +![智能路由配置界面](../assets/smart-routing-config.png) + +#### 3. 启用智能路由 + +配置完成后,开启"启用智能路由"开关。系统将自动: + +- 为所有已连接的 MCP 服务器工具生成向量嵌入 +- 建立向量索引以支持快速搜索 +- 在后续新增工具时自动更新向量数据库 + +### 智能工具发现的使用方式 + +启用智能路由后,MCPHub 会自动提供两个核心工具: + +#### search_tools - 智能工具搜索 + +```typescript +// 使用示例 +{ + "name": "search_tools", + "arguments": { + "query": "help me process images and resize them", // 自然语言查询 + "limit": 10 // 返回结果数量 + } +} +``` + +**查询策略建议**: + +- **宽泛查询**:使用较高的 limit(20-30),如"数据处理工具" +- **精确查询**:使用较低的 limit(5-10),如"将 PNG 图片转换为 WebP 格式" +- **分步查询**:复杂任务可以分解为多个具体查询 + +#### call_tool - 精准工具执行 + +```typescript +// 使用示例 +{ + "name": "call_tool", + "arguments": { + "toolName": "image_resize", // 从 search_tools 结果中获取的工具名 + "arguments": { // 根据工具的 inputSchema 提供参数 + "input_path": "/path/to/image.png", + "width": 800, + "height": 600 + } + } +} +``` + +### 实际应用场景演示 + +#### 场景 1:图像处理工作流 + +```markdown +用户请求:我需要批量处理一些产品图片,调整大小并转换格式 + +AI 工作流: + +1. search_tools("image processing batch resize convert format") + → 返回:image_batch_processor, format_converter, image_optimizer +2. call_tool("image_batch_processor", {...}) + → 执行批量图像处理 +``` + +#### 场景 2:数据分析任务 + +```markdown +用户请求:分析这个 CSV 文件的销售数据,生成可视化图表 + +AI 工作流: + +1. search_tools("CSV data analysis visualization charts") + → 返回:csv_analyzer, chart_generator, statistics_calculator +2. call_tool("csv_analyzer", {"file_path": "sales.csv"}) +3. call_tool("chart_generator", {"data": analysis_result}) +``` + +#### 场景 3:文档处理流水线 + +```markdown +用户请求:将 Word 文档转换为 PDF,然后提取其中的文本内容 + +AI 工作流: + +1. search_tools("document conversion Word to PDF") + → 返回:doc_converter, pdf_generator +2. call_tool("doc_converter", {"input": "document.docx", "output_format": "pdf"}) +3. search_tools("PDF text extraction") + → 返回:pdf_text_extractor, ocr_processor +4. call_tool("pdf_text_extractor", {"pdf_path": "document.pdf"}) +``` + +### 高级配置选项 + +#### 多模型支持 + +智能路由支持多种嵌入模型,可根据需求选择: + +```json +{ + "embeddingModel": "text-embedding-3-small", // OpenAI,1536维,平衡性能和成本 + "embeddingModel": "text-embedding-3-large", // OpenAI,3072维,最高精度 + "embeddingModel": "bge-m3" // 开源模型,1024维,支持多语言 +} +``` + +#### 自定义 API 端点 + +支持使用自建的嵌入服务或其他 OpenAI 兼容的 API: + +```json +{ + "openaiApiBaseUrl": "https://your-api-endpoint.com/v1", + "openaiApiKey": "your-custom-api-key" +} +``` + +## 性能优化与最佳实践 + +### 查询优化策略 + +**分层查询**:对于复杂任务,使用从宽泛到具体的查询策略: + +``` +1. 宽泛查询:"文档处理工具" (limit: 20) +2. 具体查询:"PDF 转 Word 转换器" (limit: 5) +``` + +**上下文相关性**:在查询中包含任务上下文信息: + +``` +好:search_tools("为电商网站批量压缩产品图片") +较好:search_tools("图片压缩工具") +``` + +**动态调整**:根据返回结果质量动态调整查询词和限制数量。 + +### 数据库性能调优 + +**索引优化**:智能路由自动创建最优的向量索引: + +```sql +CREATE INDEX idx_vector_embeddings_embedding +ON vector_embeddings USING ivfflat (embedding vector_cosine_ops) +WITH (lists = 100); +``` + +**内存配置**:对于大规模部署,建议增加 PostgreSQL 内存配置: + +``` +shared_buffers = 256MB +effective_cache_size = 1GB +work_mem = 64MB +``` + +### 监控与调试 + +**相似度阈值监控**:观察搜索结果的相似度分数,调整阈值以获得最佳效果。 + +**查询效果分析**:定期检查常用查询的返回结果,优化工具描述以提高搜索准确性。 + +## 智能路由的技术优势 + +### 语义理解能力 + +与传统的关键词匹配相比,智能路由能够理解: + +- **同义词和近义词**:"图片"和"图像"、"转换"和"变换" +- **上下层级概念**:"数据可视化"包含"图表生成"、"统计图绘制"等 +- **任务意图推理**:"我要做一个数据报告"自动关联数据分析、图表生成、文档创建等工具 + +### 多语言支持 + +智能路由支持中英文混合查询,能够处理: + +``` +search_tools("图片 resize 和 format conversion") +search_tools("将文档转换为 PDF 格式") +search_tools("image processing and 格式转换") +``` + +### 容错能力 + +具备一定的容错能力,能够处理: + +- 拼写错误:自动纠正常见拼写错误 +- 模糊描述:从不完整的描述中推导完整意图 +- 领域术语:理解特定领域的专业术语 + +## 结语 + +MCPHub 的智能路由功能代表着 MCP 生态系统向智能化方向发展的重要一步。通过引入向量语义搜索技术,它不仅解决了工具数量激增带来的选择困难,更为 AI 助手提供了类似人类专家的工具发现和选择能力。 + +随着 MCP 服务器生态的不断丰富,智能路由将成为连接用户需求与丰富工具资源的关键桥梁。它让开发者无需担心工具管理的复杂性,让用户享受到更加智能和高效的 AI 助手体验。 + +未来,我们还将继续优化智能路由的算法,引入更多先进的 AI 技术,如基于强化学习的工具推荐、多模态工具理解等,为 MCP 生态系统注入更强的智能化动力。 + +智能路由不仅仅是一个技术功能,更是 MCPHub 对于"让 AI 工具使用变得简单而智能"这一愿景的具体实现。在这个工具爆炸的时代,智能路由让我们重新定义了 AI 与工具的交互方式。 + +项目地址:https://github.com/samanhappy/mcphub + +![智能路由架构图](../assets/smart-routing-architecture.png) diff --git a/frontend/src/components/AddServerForm.tsx b/frontend/src/components/AddServerForm.tsx index a8e4fee..084712f 100644 --- a/frontend/src/components/AddServerForm.tsx +++ b/frontend/src/components/AddServerForm.tsx @@ -69,7 +69,7 @@ const AddServerForm = ({ onAdd }: AddServerFormProps) => {
diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index c41c394..28f662a 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -153,10 +153,10 @@ "pages": { "dashboard": { "title": "Dashboard", - "totalServers": "Total Servers", - "onlineServers": "Online Servers", - "offlineServers": "Offline Servers", - "connectingServers": "Connecting Servers", + "totalServers": "Total", + "onlineServers": "Online", + "offlineServers": "Offline", + "connectingServers": "Connecting", "recentServers": "Recent Servers" }, "servers": { diff --git a/frontend/src/locales/zh.json b/frontend/src/locales/zh.json index 0a859a2..db1b3d8 100644 --- a/frontend/src/locales/zh.json +++ b/frontend/src/locales/zh.json @@ -154,10 +154,10 @@ "pages": { "dashboard": { "title": "仪表盘", - "totalServers": "服务器总数", - "onlineServers": "在线服务器", - "offlineServers": "离线服务器", - "connectingServers": "连接中服务", + "totalServers": "总数", + "onlineServers": "在线", + "offlineServers": "离线", + "connectingServers": "连接中", "recentServers": "最近的服务器" }, "servers": { @@ -283,7 +283,7 @@ "installConfig": "安装配置", "systemConfigUpdated": "系统配置更新成功", "enableSmartRouting": "启用智能路由", - "enableSmartRoutingDescription": "开启智能路由功能,根据输入自动搜索最合适的工具", + "enableSmartRoutingDescription": "开启智能路由功能,根据输入自动搜索最合适的工具(使用 $smart 分组)", "dbUrl": "PostgreSQL 连接地址(支持 pgvector)", "dbUrlPlaceholder": "例如: postgresql://user:password@localhost:5432/dbname", "openaiApiBaseUrl": "OpenAI API 基础地址", diff --git a/frontend/src/pages/ServersPage.tsx b/frontend/src/pages/ServersPage.tsx index 7a2c78d..293f9dc 100644 --- a/frontend/src/pages/ServersPage.tsx +++ b/frontend/src/pages/ServersPage.tsx @@ -10,16 +10,16 @@ import { useServerData } from '@/hooks/useServerData'; const ServersPage: React.FC = () => { const { t } = useTranslation(); const navigate = useNavigate(); - const { - servers, - error, - setError, - isLoading, - handleServerAdd, - handleServerEdit, - handleServerRemove, + const { + servers, + error, + setError, + isLoading, + handleServerAdd, + handleServerEdit, + handleServerRemove, handleServerToggle, - triggerRefresh + triggerRefresh } = useServerData(); const [editingServer, setEditingServer] = useState(null); const [isRefreshing, setIsRefreshing] = useState(false); @@ -54,7 +54,7 @@ const ServersPage: React.FC = () => {