
DeerFlow MCP 集成深度指南多服务器接入、分层凭证模型与持久化长任务运行时解析【免费下载链接】deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of tasks that could take minutes to hours.项目地址: https://gitcode.com/GitHub_Trending/de/deer-flowDeerFlow 后端通过packages/harness/deerflow/mcp/封装 Model Context ProtocolMCP实现多 MCP 服务器的统一接入、凭证注入、工具名前缀、缓存失效与长期任务durable long-running task调度。本文以 mcp/AGENTS.md 为骨架结合 cache.py、tasks/models.py 等源码与 extensions_config.example.json 配置样例展开。读完本文你将掌握MCP 服务器的注册字段与工具暴露规则、四层凭证的优先级与安全边界、工具缓存为何用「内容签名」而非 mtime 判断失效以及「提交后即退出 Agent 循环」的持久化任务运行时McpTaskService如何保证状态不丢失、结果不串写、故障可恢复。适用前提文中配置路径与行为均以当前仓库GitHub_Trending/de/deer-flow为准涉及 Gateway API、extensions_config.json、SQL 持久化等能力时以对应部署形态为前提。一、模块全景从MultiServerMCPClient到 Agent 可见工具deerflow/mcp/模块的公开入口见init.py核心 API 为initialize_mcp_tools()/get_cached_mcp_tools()初始化与「首次使用才加载」的惰性获取reset_mcp_tools_cache()手动重置缓存并关闭持久会话get_mcp_tools()真正从配置装载 LangChain 工具build_servers_config()/build_server_params()将extensions_config.json的服务器描述转换为适配器参数。目录内各文件职责均与下文章节对应文件职责cache.py工具缓存、并发初始化、基于配置签名的失效检测client.py服务器参数构建、静态headers校验tools.py工具装载、路由提示注入、任务工具包装隐藏 status/cancel、包装 submitheaders.py非法头值检测illegal_header_value_reason与大小写归一化apply_header_overridesoauth.pyHTTP/SSE 的 token endpoint 流程client_credentials/refresh_token与自动刷新user_scoped_auth.py按用户凭证拦截器build_user_scoped_auth_interceptorcontext_headers.py按请求凭证拦截器build_context_headers_interceptorinterceptors.py拦截器注册顺序OAuth → user_auth → headers_from_contextsession_pool.pystdio 持久会话池与重置reset_session_pooltask_tool_caller.py任务型工具调用、stdio 会话作用域恢复、请求级 header 传递tasks/models.py协议中立的任务快照/状态机/驱动请求模型tasks/driver.pyMcpTaskDriver驱动协议tasks/ordinary.py普通 MCP 长任务驱动解析structuredContenttasks/runtime.py任务运行时启动期装配传输层支持三种stdio基于 command、SSE、HTTP。工具名称默认带server_name_前缀tool_name_prefix默认true以避免多服务器工具重名冲突仅当某服务器自带稳定命名空间时可设为false此时发现阶段会以该标志调用langchain_mcp_adapters.tools.load_mcp_tools。注意源路由source routing与 stdio 会话池包装始终以「产出来自哪个服务器、哪种传输」为准绝不依据可见工具名是否带服务器前缀——前缀只负责显示与避撞不参与路由判定。二、配置文件的注册字段与完整示例所有 MCP 服务器、拦截器与技能都写在进程本地的extensions_config.json或DEER_FLOW_EXTENSIONS_CONFIG_PATH指向的路径。根目录 extensions_config.example.json 给出了可复制的最小完整形态{ middlewares: [], mcpInterceptors: [ my_package.mcp.auth:build_auth_interceptor ], mcpServers: { github: { enabled: false, type: stdio, command: npx, args: [-y, modelcontextprotocol/server-github], env: { GITHUB_TOKEN: $GITHUB_TOKEN }, tool_name_prefix: true, session_init_timeout: 60, tool_call_timeout: 60, description: GitHub MCP server for repository operations }, openviking: { enabled: false, type: http, url: http://127.0.0.1:1933/mcp, headers: { X-API-Key: $OPENVIKING_API_KEY }, description: Official OpenViking tools for explicit memory and resource operations }, postgres: { enabled: false, type: stdio, command: npx, args: [-y, modelcontextprotocol/server-postgres, postgresql://localhost/mydb], env: {}, description: PostgreSQL database access, routing: { mode: prefer, priority: 50, keywords: [database, SQL, table, 订单, 用户] }, tools: { query: { routing: { mode: prefer, priority: 100, keywords: [查库, 订单表, 指标] } } } }, long-running-reports: { enabled: false, type: http, url: https://reports.example.com/mcp, description: Example ordinary MCP background-task contract, session_init_timeout: 60, tool_call_timeout: 60, task_toolsets: [ { name: report-generation, submit_tool: submit_report, status_tool: get_report_status, cancel_tool: cancel_report } ] } }, skills: {} }要点速览type为stdio/http运行期配置模型同样归一化type与 MCP 规范transport别名stdio配command/args/envhttp/sse配url与headers。静态headers与env中的$ENV_VAR引用会被替换为环境变量值。session_init_timeout/tool_call_timeoutHTTP/SSE 下会话初始化与任务调用的超时秒。routing服务器级与tools.original_tool_name.routing工具级是软性偏好元数据仅影响工具搜索提示不做硬路由详见第七节。task_toolsets声明「普通 MCP 背景任务契约」把裸的 submit/status/cancel 原始工具名绑定成一组业务语义详见第八、九节。mcpInterceptors为自定义拦截器导入串module:attr来自扩展包例如在 extension-api 契约 生态中编写。三、惰性初始化与「内容签名」式缓存失效3.1 加载时机与可用性边界DeerFlow 对 MCP 工具采取首次使用才加载策略get_cached_mcp_tools()在工具未初始化时会自动执行initialize_mcp_tools()保证同一套代码在 FastAPI 与 LangGraph Studio 两种启动上下文里都能工作。相关实现在 cache.py进程内以模块级单例_mcp_tools_cache持有工具列表_init_lock可重入与_init_condition保护状态迁移并发初始化通过「generation」令牌协调若某次初始化期间缓存被重置则丢弃其产物并让等待方重试工具包装wrapper闭包会引用模块级会话池单例因此任何使缓存失效的路径都必须先替换/退役会话池单例、再重置缓存状态_reset_mcp_tools_cache_state_and_retire_pool_locked否则被放弃的连接上的(server_name, scope_key)会话可能残留给下一次 wrapper 构建使用。一个容易被忽略的约束是运行时可用性边界MCP 相关的服务器运行时与绑定配置、mcpInterceptors都被冻结在Gateway 启动快照中磁盘上改动extensions_config.json不会实时改变已装载的工具集必须等 Gateway 重启才生效。文档明确「mcp_tasksis startup-only; changing it on disk does not alter the live toolset until the Gateway restarts.」下文第八节的task_toolsets、第十节的 stdio 启动策略都受这一边界约束。3.2 失效判定为什么不是「mtime 」cache.py在每次get_cached_mcp_tools()都做失效检查_is_cache_stale()cache.py判定标准是已解析的配置路径 (mtime, size, sha256)内容签名用「内容相等性!」而非严格的 mtime比较。原因在于后者会漏掉四类真实场景同一秒内的连续编辑mtime 粒度不足mtime 保持不动或倒退git checkout、cp -p/备份还原、保留时间戳的tar/rsync、对象存储/网络挂载切换到 mtime 相等或更旧的新配置文件仅记路径可发现「换了文件」进程运行期间配置被删除或暂不可读。签名辅助函数是共享的config/file_signature.py::get_config_signature同时服务config/app_config.py::get_app_config()所读的兄弟运行时配置文件而不是各维护一份拷贝——签名逻辑全局唯一。配套的「响 vs 静」策略非常讲究ExtensionsConfig.resolve_config_path()对显式config_path/DEER_FLOW_EXTENSIONS_CONFIG_PATH指向缺失文件时抛FileNotFoundError——操作者显式声明的路径消失是真实配置错误对真正要加载配置使用的调用方例如经get_mcp_tools()的from_file()故意要响而缓存自身的路径解析cache.py::_resolve_config_pathL35-L68更窄它局部捕获该FileNotFoundError并当作「未配置」处理于是此前合法、运行中途消失的显式/env-var 配置只会让陈旧性检查降级为「不陈旧」而不会在每个热路径请求上抛异常。两个行为各归其位互不污染。3.3 初始化中途变动的竞态处理initialize_mcp_tools()在装载前与装载后各取一次配置状态(path, signature)并比对cache.py若装载期间签名变化说明本次装载基于过期配置丢弃结果并把缓存复位走与正常失效相同的「会话池退役」路径等待者随后重试。此外用 generation 校验避免「缓存已被 reset 却仍写入旧结果」。四、凭证体系四层来源、一条优先级与「fail-closed」HTTP/SSE 服务器的请求头可来自四个层级注册顺序与覆盖优先级在mcp/interceptors.py中固定静态 headers oauth自动刷新注入 user_auth按用户 headers_from_context按请求其中headers_from_context的拦截器注册在user_auth之后所以声明了多个来源的服务器按请求的凭证在最终请求头中获胜静态headers只服务启动时的工具发现阶段。4.1 OAuthHTTP/SSEoauth.py支持 token endpoint 流程client_credentials与refresh_token含自动刷新与 Authorization 头注入。关键安全点渲染后的token_type access_token必须先通过mcp/headers.py::illegal_header_value_reason的校验位置在OAuthTokenManager.get_authorization_header——工具拦截器、初始发现头、持久任务路径三方读取的同一个边界值。若 token endpoint 返回的内容传输层会拒绝如换行、首尾空白、非 ASCII则直接 fail-closed绝不把值回显进模型可见的工具错误h11 会在换行/空白场景把完整值渲染进异常消息而 httpx 虽更早拦截非 ASCII 但也只点名非法字符。校验的是渲染后的完整值而非两个字段分开看因为那才是传输层所见。4.2 按用户凭证user_authmcpServers.server.user_auth把 DeerFlow 用户 id 映射到凭证头值支持$ENV_VAR引用。user_scoped_auth.py::build_user_scoped_auth_interceptor在每次工具调用时依据已认证的运行时用户改写对应头该拦截器注册于 OAuth 之后因此对同时声明 OAuth 与 user_auth 的服务器按用户值获胜。fail-closed未映射的用户或解析后为空的凭证抛ToolException除非配置on_missing: passthrough解析出的值若传输层会拒绝换行/首尾空白/非 ASCII仍走headers.py::illegal_header_value_reason无论on_missing与否一律拒绝且不回显值Gateway 的 GET 会掩码user_auth.users的值PUT 往返时保留已存储的凭证以支持掩码值回写。4.3 按请求凭证headers_from_contextmcpServers.server.headers_from_context把 HTTP 头名映射到本次运行请求config.context.secrets载体的 key适用于调用方逐请求选择凭证的场景多租户网关、每次运行的 API key。context_headers.py::build_context_headers_interceptor每次工具调用解析映射并改写请求头。fail-closed请求 secrets 中缺失映射 key或解析为空抛ToolException只点名缺失 key除非on_missing: passthrough——静默回退等于让某租户的调用借「发现凭证」的权限发送非法头值换行/首尾空白/非 ASCII无论on_missing一律拒绝且不回显h11 会把完整值渲染进异常消息而ToolErrorHandlingMiddleware会把工具错误复制进模型可见消息未加校验的坏凭证最终会进入 prompt、checkpoint 与 traces仅sse/http生效stdio服务器会警告并跳过与user_auth一致——stdio 会话按用户/线程隔离本身就承载了身份该块只存名字永不存凭证因此 Gateway 返回时不掩码PUT 原样替换声明的映射仅其中extraallow的 key 参与敏感掩码并在往返时从存储块还原。值得单独强调的边界持久化task_toolsets调用在此拆分——submit 在 Agent 运行内被 await 并携带映射后的请求头McpTaskToolCaller.call_tool(request_scoped_headersTrue)仅由OrdinaryMcpTaskDriver.submit设置而 status/cancel 在该次运行结束后执行、保留服务器级凭证。于是on_missing: deny覆盖 submit 却不覆盖后续轮询——这正是启动警告要说明的语义缺口。4.4 头名大小写不敏感headers.py所有凭证拦截器都通过apply_header_overrides写头它会丢弃仅大小写不同的键改用连接已使用的拼写。没有这层归一化静态authorization与注入的Authorization会同时到达 httpx——适配器用{**static, **override}合并连接头与覆盖头而服务器若用单值访问器读取该字段只会得到静态条目优先级被静默反转。此外headers_from_context.headers在配置加载期就拒绝同一头的两种拼写。4.5 在拦截器里读取运行上下文用runtime别用config拦截器需要拿当前用户/线程时应读取request.runtimeLangGraph 的 tool node 会把ToolRuntime注入任何名为runtime的工具参数——这对池化 stdio wrapper 与langchain-mcp-adapters自带的 HTTP/SSE 工具都成立——兜底再退到langgraph.runtime.get_runtime()。严禁使用langgraph.config.get_config()[context]运行上下文搭在 runtime 上并不随RunnableConfig传播到子 runnable因此该 key 在工具调用内是None。测试 tests/test_mcp_context_headers.py 中test_adapter_tool_receives_the_runtime_langgraph_injects通过禁用环境兜底、在真实 graph 里驱动真实适配器工具把这个注入规则钉死在上游改名风险之上。五、工具名前缀、会话作用域与 stdio 文件语义5.1 路由提示routing hintsrouting是软性偏好元数据不构成硬路由。有效路由在mcp/tools.py::get_mcp_tools()仍同时持有source_name与原始 MCP 工具名时解析随后存进tool.metadata的deerflow_mcp_routing。提示渲染由tools/builtins/tool_search.py::get_mcp_routing_hints_prompt_section完成当某个被提示的 MCP 工具当前处于 deferred延迟状态时会提示模型可经tool_search获取。文档提醒不要再为 PR1 风格的偏好提示另加并行路由中间件。5.2 stdio 会话的文件输出与临时目录持久 stdio 会话以user_id:thread_id为作用域。对 stdio 传输DeerFlow 会把子进程默认cwd钉到线程工作区并把TMPDIR/TMP/TEMP钉到workspace/.mcp/tmp/除非操作者显式配置了cwd或 temp 环境值。.mcp是 DeerFlow 私有的内部命名空间工具返回其中的临时/调试文件时仍可寻址但会从运行工作区变更摘要中排除——按目录名在任何深度生效与EXCLUDED_DIR_NAMES中其它保留名.git、node_modules…一致即使某服务器从别的 cwd 创建相对.mcp目录也依然稳健。两条启动路径当前都把它钉在工作区根。SSE/HTTP 传输完全跳过这套文件系统准备。5.3 stdio 断连恢复只逐出「同一会话」普通 Agent 工具调用与持久任务 submit/status/cancel 调用若收到 MCP SDK 显式Connection closed错误或 AnyIO closed-stream 错误只有当已注册条目仍是失败的那个ClientSession时才逐出对应的(server_name, user_id:thread_id)会话。这样旧并发调用的迟到错误不可能逐出它的替代会话或正在创建的新会话。失败调用照常暴露原始错误且从不自动重放后续重试会创建全新子进程/会话。协议超时、正常的isErrortrue工具结果、拦截器失败都不逐出健康的有状态会话。5.4 stdio 路径翻译MCP 返回的本地文件引用不会被复制。若ResourceLink或保守的自由文本路径解析到线程挂载的用户数据树内的现存文件则被确定性地翻译为/mnt/user-data/...树外路径保持原样。六、长期任务持久化运行时durable MCP task runtime这是本模块的技术重心长时 MCP 工作走独立的持久化任务运行时而不是把远端任务 ID 与状态轮询留在 Agent 循环里。对应代码为mcp/tasks/驱动协议与persistence/mcp_tasks/持久化app/mcp_tasks/McpTaskServiceAgent/LLM 循环之外的状态、取消与通知工作。6.1 归一化状态机与驱动协议tasks/models.py定义了协议中立的McpTaskDriver契约与归一化的TaskSnapshot。TaskStatus只有六个状态models.pySUBMITTEDsubmitted; WORKINGworking; INPUT_REQUIREDinput_required COMPLETEDcompleted; FAILEDfailed; CANCELLEDcancelled状态集含派生分类POLLABLE_TASK_STATUSES {submitted, working, input_required}TERMINAL_TASK_STATUSES {completed, failed, cancelled}ATTENTION_TASK_STATUSES {input_required, *terminal}。TaskSnapshot.__post_init__L67-L84强制执行两条跨驱动不变量poll_after_seconds必须是有限正数。校验放在TaskSnapshot边界而非每个驱动各自守卫因为消费方会把该间隔转成timedeltaNaN/Inf 能穿过裸 0检查却会炸掉消费者——把不变量收拢到唯一边界让所有驱动受同一规则约束input_required状态必须携带input_required载荷否则构造即失败。另有TaskReference驱动在 Agent 运行结束后仍需要的稳定数据本地任务 id、user/thread、server、远端任务 id、driver_data、TaskSubmitRequest含 server_name/task_name 的长度校验与TaskSubmission持久化的远端句柄 初始归一化快照。6.2McpTaskService认领、租约与防过期回写后台循环中McpTaskService用租约lease认领到期行依据记录解析出协议特定的McpTaskDriver把驱动返回的归一化快照写回mcp_tasks表租约过期即重启恢复机制——结果返回时若 worker 已不再持有未过期租约则该结果必须丢弃即便 owner token 仍匹配即过期后、甚至在别的 worker 认领该行之前过期结果都无法被写回。persistence/mcp_tasks/拥有可持续化的远端句柄映射、轮询计划、通知状态、租约属主以及独立的连续轮询/投递错误计数器普通轮询错误与投递错误计数分开统计。轮询时间戳与重试计划都基于远端调用完成时刻而非扫描开始时刻。6.3 提交流程的补偿语义若提交成功但持久化失败或调用方在持久化进行中被取消服务会尽力取消远端任务若补偿取消本身也失败则保留原始错误或取消信号。uq_mcp_tasks_user_server_remote唯一约束冲突则不同已存在持久化行已占有该远端句柄冲突浮现时不会取消那条被追踪任务。6.4 失败隔离与进程退出意外的单任务轮询失败与兄弟认领相互隔离并可通过租约过期恢复Gateway 关闭会取消轮询器因此挂起的外部状态调用不能阻塞进程退出。input_required与终态会停止轮询并置notification_statuspending等待后续 Agent/UI 投递。6.5 持久化前提与默认关闭持久化恢复要求 SQL 数据库后端sqlite或postgres内存后端会让该仓库/服务不可用。运行时由mcp_tasks在启动期装配默认关闭直到注册了具体驱动才启用该基础本身不改变普通 MCP 工具行为。6.6 任务载荷上界payload bounds持久化的任务错误截断至 4000 字符input_required与result_artifact必须各自序列化为64 KiB 内的合法 JSON非法或超大载荷直接成为永久协议失败不做截断改变其语义远端任务 id/任务名限制 255 字符、任务启用的服务器名限制 128 字符与 SQL schema 一致常量定义于 tasks/models.py 所引用的constantsMCP_TASK_NAME_MAX_LENGTH/MCP_TASK_SERVER_NAME_MAX_LENGTH超大的提交型远端 id 只在 Service 已握有句柄之后才被拒绝——这样补偿取消仍能执行超大的结果保留既有的有界预览/截断/artifact 行为而不是协议失败。6.7 取消cancellation的租约栅栏首个取消请求给在途轮询租约设栅栏fence重复取消请求保持活跃的取消租约从而不可能发出并发的远端 cancel取消退避从远端尝试结束才开始因此慢超时不会吞掉重试延迟取消、轮询、通知各批次均隔离单任务异常意外的取消/轮询失败让该记录租约到期即可通知失败只释放受影响租约供重试HTTP 与 Agent 取消请求在持久化取消栅栏后即返回——慢速远端调用与重试计划完全归后台循环所有。HTTP 取消端点在循环未运行时mcp_tasks_availablefalse例如mcp_tasks.enabledfalse但配了 SQL 持久化对请求回 503取消绝不在没有 worker 执行时被确认。6.8 通知notification语义通知失败使用与幂等键dispatch_attempt分离的连续计数器、有上限的指数退避、运行启动前重建最新事件五连败后进入dead_letter目标线程永久缺失/不匹配时立即 dead-letter而非重建或重新认领input_required与终态事件快照由幂等 Agent 运行投递仅当运行成功才标记 delivered可信的通知指令留在输入边界之外序列化的远端事件被框定为不可信数据忙线程冲突被归一化回服务边界使排队快照收敛到最新任务事件派发运行缺失算一次失败投递而瞬时 run-store 水合错误保持可区分并重试同一查找数据库是事实源ThreadState只收到有界的当前线程投影显示名在该模型状态边界被中性化。七、普通 MCP 长任务驱动ordinary driver与运行期细则7.1 绑定、包装与可见性extensions_config.json - mcpServers.server.task_toolsets把精确的原始submit/status/cancel 工具名绑定成工具集一个原始工具在该服务器各 group 中只能占据一个角色。mcp/tools.py会把 status/cancel 隐藏起来并把 submit 替换成包装器——包装器只在持久化完成后返回本地任务 id。Agent 侧只见 submitstatus/cancel 由后台McpTaskService驱动。7.2 远端语义映射与错误分类ordinary.py只读 MCP 的structuredContent把远端running映射为workingerror_codetask_not_found或结构化输出畸形 →永久失败isErrortrue的状态调用是可重试的调用失败首个文本内容块被保留为有界诊断而「远端任务永久失败」必须以正常结果 结构化statusfailed到达——两者在通道语义上被严格区分。7.3 会话作用域与超时task_tool_caller.pytask_tool_caller.py恢复相同的(server_name, user_id:thread_id)stdio 会话作用域HTTP/SSE 调用保持短暂ephemeralsession_init_timeout施加于初始化、tool_call_timeout施加于任务调用并支持在 Agent 运行之外做服务器级 OAuth 刷新。7.4 退避、降级与轮询节奏McpTaskService瞬时 status/cancel 错误指数退避且无最大尝试次数上限API 的tracking_degraded派生自连续错误阈值input_required走更慢的轮询节奏有限正数的远端轮询提示poll_after_seconds被封顶为 24 小时。7.5 冻结快照与热漂移任务启用的服务器运行时/绑定配置与mcpInterceptors冻结在 Gateway 启动快照上热漂移会在工具发现偏离后台调用之前就清晰失败而纯展示字段与非任务服务器保持可热重载。配置了任务工具集却在「运行时关闭或持久化为内存」时启动将直接启动失败。7.6 已知限制用户仍不能向input_required状态的远端任务回传答案。八、Gateway 运行期更新与原子写Gateway API 的保存动作写入extensions_config.jsonGateway 内嵌运行时通过上文「已解析路径 内容签名」检测到变化因此多 worker/陈旧 mtime 部署下新增/移除某 MCP 服务器无需重启即可生效PUT /api/mcp/config全载荷校验后重置缓存PATCH /api/mcp/config只改某服务器的enabled字段归一化与运行时配置模型一致的type/MCP 规范transport别名且只在启用目标时校验之任一端点重置都只清自己 worker的缓存。并发写安全MCP、skill 与内嵌客户端写者在整个「读-改-写/重载」周期持有进程本地extensions_config_write_lock与 sidecar 咨询锁extensions_config_file_lock随后共用atomic_write_extensions_config()先在同目录写临时文件并fsync再os.replace()并保留既有文件的 mode 与 symlink 目标序列化或替换失败时保留旧配置并清理临时文件。九、HTTP 边界上的 stdio 启动策略分层防御而非信任边界routers/mcp.py::_validate_mcp_update_requestPUT与PATCH的启用分支共用处理一个关键差异配置文件可以表达任何内容但 API 是不可信输入因此经 API 注册的 stdio 服务器必须满足command是白名单内的裸可执行名——_DEFAULT_MCP_STDIO_COMMAND_ALLOWLIST {npx, uvx}可由DEER_FLOW_MCP_STDIO_COMMAND_ALLOWLIST扩展command中拒绝路径分隔符、空白与 shell 元字符args不含_ARBITRARY_EXEC_ARGS中的标志env不含_CODE_INJECTING_ENV_VARS中的名字。规则 2、3 之所以存在是因为仅查命令名只限定「跑哪个二进制」却不管「这个二进制跑什么」。env黑名单对所有白名单命令生效两条黑名单同时匹配--flagvalue与--flag value两种拼写。args黑名单的作用域取决于命令——因为「启动器在哪里停止解析自身标志」决定了某个 token 算不算 exec 标志包启动器_PACKAGE_LAUNCHERS {npx, uvx}只筛其自身选项区npx/uvx在包名处停止解析并把手后每个 token 交给被启动的服务器 argv——那里-c常是「config」、-e是「env」整段筛查反而会误伤普通第三方服务器。裸--也结束选项区其后首个 token 才是包名。要找该边界需要每个启动器的选项元数arity因为值是参数而非位置参数npx -p pkg -c command会执行命令-p是npm exec的--packagepkg是其值且 npm 继续解析若把选项区结束在首个非标志 token 处就会直接越过它。_NPX_BOOLEAN_ARGS由npmcli/confignpm 10.9.4定义生成并去掉-pexec 覆盖_UVX_VALUE_ARGS来自uvx --helpuv 0.11.1。升级启动器后应重新生成而非手改。未知选项的默认处理按启动器故意相反npx 拥有真实 exec 标志-c/--call故未知选项消费一个值并保持选项区开放npm 会报它没定义的选项因此不会误拒有效调用uvx 没有任何字符串求值标志其筛子是绊线未知选项不消费值uv 巨大的布尔面也不会过度拦截。uvx 的 exec 集还去掉短拼写因为-c是 uv 的--constraints、-p是--python。其它所有命令整段筛查另加两条规则因为它是解释器而非包运行器-p在此算 exec 标志node 的--print单杠短选项簇逐字母拆解以免node -pe蒙混过只按拆分的检查。判定被真实启动器钉死对 npx校验器拒绝的每个参数向量都是 npx 真正会执行的放行的每个向量都是 npx 原样透传给服务器的。env筛查覆盖进程启动时无条件执行代码的名字如PYTHONPATH/PYTHONHOME在纯uvx下会在解释器启动时运行调用方可控的sitecustomize.py。调用方可控的搜索路径是较弱、有条件的类别属接受残留LD_LIBRARY_PATH/DYLD_LIBRARY_PATH依赖进程加载可遮蔽库且本地依赖服务器合理设置与NODE_PATH在本地node_modules链之后查找遮蔽不了已装依赖且 ESMimport完全忽略只能供给本会解析失败的 CJS 模块。不要把搜索路径移入集合——那会让「无条件」规则失真这正是纵深防御清单开始被误当成边界的方式。远端传输全跳过三条检查——它们不派生任何进程。这是纵深防御不是信任边界。npx/uvx的存在意义就是拉取并执行远端包管理员仍可指向自己发布的包真正的边界是管理员认证 网络可达性。不要假设增加此处的检查就能让 MCP 注册对不受信管理员安全——不能解法不是更大的黑名单。十、跨章节一致性要点与可验证依据工具暴露的事实源是进程本地已安装的 submittermcp_tasks只在启动期生效磁盘热改不改变运行中工具集活跃技能必须显式声明 list/cancel 业务工具。从源码结构可以推断initialize_mcp_tools()对「装载前后签名变化」的丢弃分支必须与常规失效走同一会话池退役路径cache.py这是(server_name, scope_key)会话不被泄漏给新 wrapper 的前提。状态机、长度上限与poll_after_seconds校验均为可直接单测的纯逻辑tasks/models.py上下文注入规则由 test_mcp_context_headers.py 固化。持久化层位于 persistence/mcp_tasks服务编排位于 backend/app/mcp_tasks模块级汇总可见 backend/AGENTS.md。进一步阅读MCP 服务器集成说明面向运营的服务器接入手册缓存失效实现 与 任务状态模型完整配置骨架extensions_config.example.json端到端行为约定见 mcp/AGENTS.md 与相关test_mcp_*测试。操作提示本文涉及的行为均以「Gateway 重启后生效」「SQL 持久化sqlite/postgres」「进程本地 extensions 配置」为适用前提内存持久化下持久任务仓库/服务不可用任务工具集在运行时关闭或内存持久化时配置会直接启动失败。把 .mcp、user_auth 凭证掩码、headers_from_context名字存储等安全语义纳入你的网关二次开发可避免凭证泄漏到模型可见错误与检查点中。【免费下载链接】deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of tasks that could take minutes to hours.项目地址: https://gitcode.com/GitHub_Trending/de/deer-flow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考