Flowise 的 MCP 协议集成与工具发现
学习目标
- 理解 Flowise MCPToolkit 的三种传输方式及其选择策略
- 掌握 MCP 工具自动发现的流程:连接 → tools/list → 转换为 LangChain Tool
- 了解 Flowise 的 MCP 安全设计:hostname deny list + secureFetch
前置知识
本章涉及 MCP 协议的通用原理,建议先阅读:
下文假设你已理解 MCP 协议的基本概念(Client/Server、Transport、Tool 等),直接聚焦 Flowise 的具体实现。
项目实践
MCPToolkit 架构
Flowise 的 MCP 集成位于 packages/components/nodes/tools/MCP/core.ts,核心类为 MCPToolkit:
三种传输方式
| 传输方式 | 适用场景 | 配置参数 |
|---|---|---|
| stdio | 本地 MCP Server(如 Claude CLI、自定义脚本) | command、args、env |
| SSE | 远程 MCP Server,服务端推送事件 | url、headers |
| Streamable HTTP | 远程 MCP Server,HTTP 流式响应 | url、headers |
工具自动发现流程
关键代码逻辑:
// 1. 初始化时连接并获取工具列表async initialize() { this.client = await this.createClient() this._tools = await this.client.request({ method: 'tools/list' }, ListToolsResultSchema) this.tools = await this.get_tools() await this.client.close() // 初始化后关闭}
// 2. 每次工具调用时新建连接(确保连接新鲜)async call() { this.client = await this.createClient(injectHeaders) const result = await this.client.request( { method: 'tools/call', params: { name, arguments: args } }, CallToolResultSchema ) // ...处理结果}传输回退策略
Flowise 实现了 SSE → HTTP 的回退机制:
try { transport = new StreamableHTTPClientTransport(baseUrl, { headers }) await client.connect(transport)} catch (error) { // HTTP 连接失败,回退到 SSE transport = new SSEClientTransport(baseUrl, { eventSourceInit: { fetch: secureFetch } }) await client.connect(transport)}MCP Server 类型
Flowise 内置了多种 MCP Server 集成:
| MCP Server | 传输方式 | 功能 |
|---|---|---|
| SequentialThinking | stdio | 结构化推理链 |
| GitHub | stdio | GitHub API 操作 |
| BraveSearch | stdio | Brave 搜索 |
| Browserless | stdio | 浏览器自动化 |
| Slack | stdio | Slack API |
| Pipedream | stdio | Pipedream 工作流 |
| Supergateway | http/stdio | MCP Server 网关 |
| Teradata | stdio | Teradata 数据库 |
问题与规避
连接生命周期管理
问题:每次工具调用都创建新连接会带来连接开销。
对策:Flowise 的设计选择是”初始化时获取工具列表后关闭,每次调用时新建连接”。这确保了连接新鲜度(MCP Server 可能重启),但增加了延迟。对于高频调用场景,可以考虑保持连接长开。
SSE 到 HTTP 回退的隐藏问题
问题:回退到 SSE 后,tools/call 的响应方式不同,可能导致某些工具的响应格式不兼容。
对策:MCP 协议规范了统一的 JSON-RPC 响应格式,理论上两种传输方式的结果一致。但某些 MCP Server 实现可能有差异,建议在开发时优先测试目标传输方式。
原型链污染防护
问题:lodash.get 在解析路径时会跟随 __proto__、constructor 等属性,导致原型链污染。
对策:Flowise 在 resolveWebhookRefs 中使用正则阻断:
if (/(^|\.)(__proto__|constructor|prototype)(\.|$)/.test(subPath)) return match设计取舍
每次调用新建连接 vs 连接池
| 方案 | 优势 | 代价 |
|---|---|---|
| 每次新建连接 | 连接新鲜度、无状态泄漏风险 | 连接开销 |
| 连接池 | 低延迟、减少握手次数 | 需要管理连接生命周期 |
Flowise 选择每次新建连接,原因是:
- MCP 工具调用频率通常不高(用户级别的 Agent 交互)
- MCP Server 可能随时重启或更新,保持长连接可能遇到断连问题
- 无状态设计更简单,不需要管理连接池的创建和回收
stdio vs 远程传输
| 维度 | stdio | SSE/HTTP |
|---|---|---|
| 延迟 | 最低(本地进程) | 受网络影响 |
| 安全性 | 高(本地隔离) | 需要 hostname deny list |
| 部署 | 需要本地安装 MCP Server | 只需 URL |
| 扩展性 | 单实例 | 可多实例共享 |