MCP 工作流:将 Flow 发布为 MCP Server
学习目标
- 理解 Langflow 中 MCP Server 的两种部署模式(独立 vs 内嵌)
- 掌握将组件标记为 MCP 工具的方法(
tool_mode=True/component_as_tool) - 学会通过 MCP 协议从外部 Agent 调用 Langflow Flow
前置知识
本章涉及 MCP 协议的通用原理,建议先阅读:
下文假设你已理解 MCP 的基本协议和传输层,直接聚焦 Langflow 将 Flow 暴露为 MCP 工具的具体实现。
项目实践
1. 两种 MCP 部署模式
Langflow 提供两种 MCP Server 部署方式:
模式一:独立 MCP Server(stdio 传输)
# 作为独立进程运行,连接已启动的 Langflow 实例lfx-mcp --url http://localhost:7860 --api-key your-key独立 MCP Server 通过 REST API 与 Langflow 通信,提供以下工具集:
| 工具类别 | 工具示例 | 功能 |
|---|---|---|
| 组件搜索 | list_components | 按名称、类型、描述搜索可用组件 |
| Flow 构建 | add_component | 向 Flow 添加组件节点 |
| Flow 构建 | configure_component | 修改组件的输入参数 |
| Flow 构建 | add_connection | 在两个组件间建立连线 |
| Flow 执行 | run_flow | 执行指定 Flow 并返回结果 |
| 组件描述 | describe_component | 获取组件的详细文档 |
模式二:内嵌 MCP 端点(SSE 传输)
内嵌 MCP 直接挂载在 Langflow 的 FastAPI 路由上(/api/v1/mcp),将启用了 tool_mode=True 的组件输出自动注册为 MCP 工具。
选择策略:
| 维度 | 独立模式 | 内嵌模式 |
|---|---|---|
| 用途 | Agent 构建和修改 Flow | Agent 调用已部署的 Flow |
| 传输 | stdio(进程间通信) | SSE(HTTP 流式) |
| 工具集 | Flow 构建工具(增删改组件) | Flow 执行工具(运行工作流) |
| 认证 | 需要 API Key | 复用 Langflow 的认证体系 |
2. 将组件输出暴露为 MCP 工具
在 Langflow 中,任何组件的输出都可以通过 tool_mode 标记变为 MCP 工具:
class VectorStoreComponent: outputs = [ Output( name="as_tool", display_name="作为工具使用", method="retrieve_as_tool", # 执行方法 tool_mode=True, # 标记为 MCP 工具 types=["Tool"], ), ]
def retrieve_as_tool(self, query: str) -> str: """根据查询文本,从向量数据库中检索相关文档并返回。""" results = self.vector_store.similarity_search(query, k=self.top_k) return "\n".join(doc.page_content for doc in results)自动注册流程:
工具的名称和描述自动从组件推导:
- 工具名:
{component_display_name}_{output_display_name} - 描述:
Output的description或组件的description - 参数:执行方法的函数签名推导为 JSON Schema
3. 零缓存策略
独立 MCP Server 采用零缓存策略:每次 mutating 操作(添加组件、修改连线)都执行 GET → modify → PATCH,不在本地缓存 Flow 状态。
为什么不用缓存:
- Flow 可能被多个 Agent 或用户同时修改,缓存会导致状态不一致
- 每次 GET 保证获取最新状态,避免”基于过期状态修改”的冲突
- 代价是每次操作多一次网络往返,但保证了强一致性
4. 多 Agent 并发隔离
在 SSE 模式下,多个 Agent 可能同时连接同一个 Langflow MCP 端点。Langflow 使用 contextvars 实现 per-session 隔离:
# 每个 SSE 连接有独立的 contextvar_client_var: contextvars.ContextVar[LangflowClient | None] = contextvars.ContextVar("_client", default=None)_registry_var: contextvars.ContextVar[dict | None] = contextvars.ContextVar("_registry", default=None)
# stdio 模式(单 Agent)使用模块级共享变量_shared_client: LangflowClient | None = None_shared_registry: dict | None = None关键设计:
- stdio 模式:单一 Agent 连接,模块级共享变量简单高效
- SSE 模式:多 Agent 并发连接,
contextvars确保每个连接的组件注册表和客户端实例独立
问题与规避
| 陷阱 | 现象 | 对策 |
|---|---|---|
| 工具名冲突 | 两个 Flow 导出同名 MCP 工具 | 为 Flow 设置唯一的 endpoint_name,工具名自动带上端点前缀 |
| Flow 状态不一致 | 多个 Agent 同时修改同一 Flow | 独立模式天然一致(GET-PATCH);内嵌模式建议每个 Flow 独立部署 |
| 工具描述过短 | Agent 无法理解工具的用途 | 在 Output(description="...") 中编写清晰的工具描述,这是 Agent 的唯一参考 |
| MCP Server 连接失败 | Langflow 未启动或 API Key 错误 | 确保 uv run langflow run 已启动,MCP Server 的 --url 和 --api-key 匹配 |
设计取舍
Flow-as-MCP vs Flow-as-REST-API:
| 维度 | Flow-as-MCP | Flow-as-REST-API |
|---|---|---|
| 调用方 | 支持 MCP 的 Agent(Claude、Codex) | 任意 HTTP 客户端 |
| 工具发现 | Agent 自动发现可用工具 | 需要手动查阅 API 文档 |
| 参数传递 | 结构化 JSON,由 Agent 推导 | 需要手动构建请求体 |
| 组合能力 | Agent 可组合多个 MCP 工具 | 需要外部编排 |
推荐策略:对内(开发调试)使用 REST API;对外(Agent 集成)使用 MCP。
参考来源
- 源码:
src/lfx/src/lfx/mcp/server.py - 源码:
src/backend/base/langflow/api/v1/mcp.py - 源码:
src/backend/base/langflow/agentic/mcp/server.py