Skip to content

mcp

2 posts with the tag “mcp”

MCP (Model Context Protocol) 系统实现说明

DeerFlow完整集成了MCP(Model Context Protocol)协议,支持无缝对接各类MCP服务器,实现工具能力的动态扩展。系统采用模块化设计,支持多种传输协议、OAuth 2.0认证、运行时热更新、自动缓存等企业级特性,无需修改代码即可通过配置扩展Agent的工具能力。


所有MCP相关代码集中在packages/harness/deerflow/mcp/目录下:

文件职责
mcp/__init__.py模块导出接口,统一暴露核心函数
mcp/cache.pyMCP工具缓存机制,支持自动失效与懒加载
mcp/client.pyMCP客户端实现,支持多传输类型配置构建
mcp/oauth.pyOAuth令牌管理,支持自动刷新与请求头注入
mcp/tools.py工具加载与同步适配,将MCP工具转换为LangChain兼容格式
config/extensions_config.py配置解析系统,定义MCP配置结构与加载逻辑
app/gateway/routers/mcp.pyGateway API层,提供MCP配置的REST管理接口
┌─────────────────────────────────────────────────────────┐
│ Agent Runtime │
└─────────────────┬─────────────────────────────────────────┘
┌─────────────────▼─────────────────────────────────────────┐
│ MCP Tool Cache │
│ (懒加载、自动失效、线程安全) │
└─────────────────┬─────────────────────────────────────────┘
┌─────────────────▼─────────────────────────────────────────┐
│ MultiServerMCPClient │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Stdio 服务 │ │ SSE 服务 │ │ HTTP 服务 │ │
│ └────────────┘ └────────────┘ └────────────┘ │
└─────────────────┬─────────────────────────────────────────┘
┌─────────────────▼─────────────────────────────────────────┐
│ OAuth 管理器 │
│ (令牌自动刷新、线程安全、请求头自动注入) │
└─────────────────┬─────────────────────────────────────────┘
┌─────────────────▼─────────────────────────────────────────┐
│ MCP 服务器集群 │
│ (本地进程、远程服务、第三方MCP服务) │
└───────────────────────────────────────────────────────────┘

MCP服务器配置存储在extensions_config.json文件中,示例:

{
"mcpServers": {
"github": {
"enabled": true,
"type": "stdio",
"command": "npx",
"args": ["-y", "@github/mcp-server-github"],
"env": {
"GITHUB_TOKEN": "$GITHUB_TOKEN"
},
"description": "GitHub API 工具集"
},
"internal-api": {
"enabled": true,
"type": "http",
"url": "https://mcp.example.com/tools",
"oauth": {
"enabled": true,
"token_url": "https://auth.example.com/oauth2/token",
"grant_type": "client_credentials",
"client_id": "$CLIENT_ID",
"client_secret": "$CLIENT_SECRET",
"scope": "read write"
},
"description": "内部系统API工具集"
}
}
}

支持三种传输协议:

类型适用场景配置参数
stdio本地MCP服务器,通过子进程启动commandargsenv
sse远程SSE协议的MCP服务器urlheaders
http远程HTTP协议的MCP服务器urlheaders
  1. 显式传入的config_path参数
  2. DEER_FLOW_EXTENSIONS_CONFIG_PATH环境变量
  3. 当前工作目录下的extensions_config.json
  4. 当前工作目录父目录下的extensions_config.json(推荐位置)
  5. 兼容旧版:查找mcp_config.json作为备选
  • 配置中所有以$开头的字符串会自动解析为环境变量
  • 示例:"GITHUB_TOKEN": "$GITHUB_TOKEN"会自动替换为对应环境变量的值
  • 未找到的环境变量自动替换为空字符串,避免运行错误

支持完整的OAuth 2.0客户端认证能力:

  • client_credentials:客户端凭证模式,适用于服务间通信
  • refresh_token:刷新令牌模式,适用于用户级授权场景
  • 自动刷新:提前60秒(可配置refresh_skew_seconds)自动刷新令牌,避免请求时令牌过期
  • 线程安全:每个MCP服务器独立的令牌获取锁,避免并发刷新导致的重复请求
  • 自动注入:工具调用拦截器自动将最新的Authorization头注入到所有MCP请求中
  • 初始化认证:首次连接MCP服务器时自动注入OAuth头,确保工具发现阶段的认证通过
  • 自动发现:自动加载所有启用MCP服务器暴露的工具,无需手动定义
  • 名称隔离:工具名称自动添加服务器前缀,避免不同服务器之间的命名冲突,格式为{server_name}_{tool_name}
  • 同步适配:异步MCP工具自动封装为同步调用,适配DeerFlow的同步执行模型,使用全局线程池避免嵌套事件循环问题
  • 类型转换:自动处理MCP工具参数与LangChain工具格式的转换,上层调用无感知
  • 全局单例缓存:MCP工具加载后全局缓存,避免重复初始化的性能开销
  • 自动失效:通过监控配置文件的修改时间(mtime),配置变更后自动失效缓存,下次访问时重新加载
  • 懒加载:支持首次使用时自动初始化,兼顾冷启动性能和资源占用
  • 线程安全:初始化过程使用异步锁,避免并发场景下的重复初始化问题
# 获取MCP工具(自动初始化、自动缓存)
from deerflow.mcp import get_cached_mcp_tools
tools = get_cached_mcp_tools()
# 手动重置缓存(配置更新后调用)
from deerflow.mcp import reset_mcp_tools_cache
reset_mcp_tools_cache()
  • 配置文件修改后,系统自动检测到mtime变化,缓存自动失效
  • 通过Gateway API更新配置后,自动触发缓存重置
  • 新配置在下次工具调用时自动生效,无需重启LangGraph或Gateway服务
  • 更新过程中不影响现有会话的运行

  1. 初始化触发:应用启动或首次调用MCP工具时,get_cached_mcp_tools()被调用
  2. 配置加载:从extensions_config.json加载所有启用的MCP服务器配置,解析环境变量
  3. OAuth初始化:为需要认证的服务器初始化OAuth令牌管理器,获取初始访问令牌
  4. 客户端创建:构建MultiServerMCPClient实例,连接所有MCP服务器
  5. 工具发现:自动从所有MCP服务器发现并加载工具定义
  6. 工具适配:将异步MCP工具封装为同步调用,添加服务器前缀,存入全局缓存
  7. 工具使用:Agent调用MCP工具时,OAuth拦截器自动注入最新令牌,同步包装器处理异步调用逻辑
  8. 缓存失效:当配置文件被修改时,缓存自动失效,下次访问时重新执行初始化流程

Gateway提供了REST接口用于管理MCP配置:

GET /api/mcp/config

返回所有MCP服务器和技能的配置信息。

PUT /api/mcp/config
Content-Type: application/json

请求体为新的MCP配置,保存到文件后自动重置缓存,新配置立即生效。

注意:更新MCP配置时不会覆盖已有的技能配置,实现MCP与技能配置的独立管理。


  1. 零代码扩展:新增MCP服务器只需修改配置文件,无需修改业务代码
  2. 运行时热更新:配置修改后自动生效,无需重启服务
  3. 多场景适配:支持本地命令行、远程SSE/HTTP等多种MCP服务器部署方式
  4. 企业级安全:完整的OAuth 2.0支持,满足内部API和第三方API的安全访问需求
  5. 高性能设计:缓存机制与自动失效平衡了性能和配置实时性
  6. 兼容现有架构:同步包装器完美适配DeerFlow现有的同步执行模型,无需修改上层调用逻辑

  1. 敏感信息管理:所有API密钥、令牌都通过环境变量传递,不要硬编码在配置文件中
  2. 命名规范:MCP服务器名称使用小写字母和连字符,避免特殊字符
  3. 权限最小化:为MCP服务器配置最小必要的权限,避免过度授权
  4. 版本锁定:本地stdio类型的MCP服务器推荐锁定版本号,避免意外升级导致兼容性问题
  5. 监控告警:对重要的MCP服务器添加健康检查,及时发现服务不可用问题

SSE and Streamable HTTP

MCP(Model Context Protocol) 里两种流式传输机制的差异是什么?以及为什么社区从 SSE(Server-Sent Events) 慢慢转向 Streamable HTTP


1. SSE 和 Streamable HTTP 在 MCP 里的区别

Section titled “1. SSE 和 Streamable HTTP 在 MCP 里的区别”
  • 协议:基于 HTTP/1.x 的单向推送,服务器持续通过 Content-Type: text/event-stream 推送事件。
  • 特性
    • 只能 服务器 → 客户端 单向流。
    • 事件是基于文本的、UTF-8 编码。
    • 连接保持长时间打开,数据通过 \n\n 分隔。
    • 浏览器原生支持 EventSource,实现简单。
  • 在 MCP 中的使用:主要用于模型响应的流式传输(像 ChatGPT 一样逐字输出)。

  • 协议:利用 HTTP 响应体本身作为流通道,客户端读取分块(chunked transfer)或 HTTP/2 帧。

  • 特性

    • 不依赖额外事件封装,直接在响应体中发送 JSON/二进制片段。
    • 支持 双向交互(尤其在 HTTP/2/HTTP/3 中可以用 request/response stream 组合实现)。
    • 传输效率更高,数据结构更灵活(不限制必须是 UTF-8 文本)。
  • 在 MCP 中的使用:作为替代 SSE 的新流式响应标准,既能流式传输模型输出,也能嵌入更多元数据。


2. 为什么 MCP 社区在放弃 SSE,转向 Streamable HTTP

Section titled “2. 为什么 MCP 社区在放弃 SSE,转向 Streamable HTTP”
问题SSE 的限制Streamable HTTP 的优势
双向流只能服务器推送,不能客户端回流数据可以在 HTTP/2 多路复用下实现双向流
传输类型只能是 UTF-8 文本,不能直接传二进制支持二进制、JSON、混合数据
分帧结构需要手动封装成 event: 格式,解析麻烦可以直接发送结构化 JSON/Protobuf
HTTP 版本限制基本只依赖 HTTP/1.1,HTTP/2 支持有限原生支持 HTTP/1.1、HTTP/2、HTTP/3
中间代理兼容性某些反向代理、CDN 会断开长连接分块响应在代理和缓存系统中更健壮
浏览器生态浏览器支持好,但 MCP 不局限于浏览器客户端在 CLI、SDK、嵌入式中更易实现

核心原因: MCP 协议不仅要在浏览器跑,还要在 CLI、桌面端、服务端之间通信,SSE 的单向文本流限制和代理兼容性问题在多端环境下变得明显,而 Streamable HTTP 更通用、更灵活、更高效。


MCP 社区转向 Streamable HTTP 是因为它能在 HTTP/1.1/2/3 上提供更通用、更高性能、更灵活的流式通信能力,而不受 SSE 单向文本流的限制。

4. SSE vs Streamable HTTP 在 MCP 协议中的数据流对比图

Section titled “4. SSE vs Streamable HTTP 在 MCP 协议中的数据流对比图”
┌───────────────────────────────────┐
│ 客户端 (MCP Client) │
└───────────────┬───────────────────┘
┌───────────────┴───────────────────┐
│ │
SSE(单向推送) Streamable HTTP(分块流)
───────────────────────────────────────────────────────────────────────
HTTP 请求:
GET /stream POST /inference (或 GET)
Content-Type: application/json
服务器响应:
Content-Type: text/event-stream
event: data Content-Type: application/json
data: { "token": "你" } ┌───────────── 分块1 ──────────────┐
│ { "token": "你" } │
event: data ├───────────── 分块2 ──────────────┤
data: { "token": "好" } │ { "token": "好" } │
├───────────── 分块3 ──────────────┤
... │ { "token": "啊" } │
└──────────────────────────────────┘
方向:
仅服务器 → 客户端 双向可能:客户端也可流式上传数据(HTTP/2/3)
数据类型:
UTF-8 文本 JSON / 二进制 / 混合