十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Envoy MCP Router 过滤器详解:多 MCP 后端聚合、扇出路由与请求/响应转发机制

Envoy MCP Router 过滤器详解:多 MCP 后端聚合、扇出路由与请求/响应转发机制 Envoy MCP Router 过滤器详解多 MCP 后端聚合、扇出路由与请求/响应转发机制【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy导读Envoy 的 MCP Router 过滤器envoy.filters.http.mcp_router将多个远端 Model Context ProtocolMCP服务器聚合为单个逻辑 MCP 服务器向客户端统一呈现其 capabilities、tools 与 resources。本文基于仓库中的 mcp_router_filter.rst 文档结合 mcp_router.proto 与 mcp_router.cc 源码完整讲解其配置方法、单后端/多后端路由语义、惰性初始化、server-to-client 请求的 JSON-RPC ID 重写、会话身份绑定与统计指标帮助你在一处网关内对多个 MCP 后端实施统一策略与聚合接入。MCP Router 在 Envoy 中的定位MCP Router 是一个 HTTP 流过滤器负责聚合多个 MCP 服务器的 capabilities、tools 和 resources并以单一 MCP 服务器的形式呈现给客户端proto 注释将其定义为 MCP Multiplexer/Demultiplexer。它带来两个直接收益客户端只需连接一个 Envoy 端点即可访问多个后端 MCP 服务Envoy 成为统一策略执行点可对多个远端服务器施加一致的路由、鉴权与观测策略。从 mcp_router.proto 的注释可以确认两个重要约束该过滤器必须是过滤器链中的最后一个过滤器terminal filter并取代 HTTP router 过滤器并非所有路由级策略都适用以下策略会被忽略route、redirect、direct_response。此外该过滤器不能独立工作必须与 MCP 过滤器 配合使用MCP 过滤器负责解析入站 MCP 请求并填充动态元数据dynamic metadata而 MCP Router 消费这些元数据来做路由决策。这一点在过滤器文档开篇即有明确说明也被 mcp_router.cc 中的readMetadataFromMcpFilter()实现所印证——它会从 stream 的动态元数据中读取method、id、params等字段。基础配置示例原文档给出的最小配置如下两条过滤器必须同时配置MCP 过滤器在前MCP Router 在后http_filters: - name: envoy.filters.http.mcp typed_config: type: type.googleapis.com/envoy.extensions.filters.http.mcp.v3.Mcp - name: envoy.filters.http.mcp_router typed_config: type: type.googleapis.com/envoy.extensions.filters.http.mcp_router.v3.McpRouter lazy_initialization: true servers: - name: backend1 mcp_cluster: cluster: backend1_cluster path: /mcp配置中两个关键点envoy.filters.http.mcp解析 MCP JSON-RPC 消息并把请求要素写入动态元数据envoy.filters.http.mcp_router读取元数据将请求路由/扇出到配置的一个或多个 MCP 后端。McpRouter 配置字段详解McpRouter消息的完整字段定义见 mcp_router.proto下表汇总了全部配置项字段类型说明serversrepeated McpBackend远端 MCP 服务器列表。所有远端服务器都会收到客户端向 Envoy 呈现的同一份 capabilitiessession_identitySessionIdentity若设置则从请求中提取 subject用户/主体并绑定到 MCP 会话不设置则创建无身份绑定的会话lazy_initializationbool若为 true后端初始化延迟到首个请求路由到该后端时进行默认 false在initialize期间急切初始化所有后端McpBackend单后端定义message McpBackend { string name 1; // 唯一名称用于工具名前缀、会话 ID 组成、日志与错误信息 McpCluster mcp_cluster 2; // 后端目标规格 }name的用途非常具体工具名前缀例如time__get_current_time、会话 ID 组成以及日志与错误消息。若不指定默认取 cluster 名称。McpCluster后端目标规格message McpCluster { string cluster 1; // 路由请求所用的 cluster 名称必填min_len: 1 string path 2; // MCP 请求使用的路径默认 /mcp google.protobuf.Duration timeout 3; // 请求超时未设置时使用 cluster 的超时配置 string host_rewrite_literal 4; // 转发时用该值替换 host 头 }在实现侧filter_config.h 的McpBackendConfig给出默认超时值为5000mstimeout{5000}。这个超时在 mcp_router.cc 中通过backend_options.setTimeout(backend-timeout)应用到每个后端的异步请求流。过滤器链装配与工厂注册MCP Router 以标准 HTTP 过滤器工厂方式注册见 config.ccMcpRouterFilterConfigFactory::createFilterFactory接收McpRouterproto 配置构造McpRouterConfigImpl并通过callbacks.addStreamDecoderFilter(...)注册为StreamDecoderFilter过滤器通过REGISTER_FACTORY(McpRouterFilterConfigFactory, Server::Configuration::NamedHttpFilterConfigFactory)静态注册扩展名即envoy.filters.http.mcp_router。值得注意的实现细节来自 mcp_router.cc 的getClusterConfig()如果目标 cluster 携带envoy.clusters.mcp_multicluster类型的 typed filter metadataClusterConfig路由器会用McpRouterClusterConfigImpl覆盖过滤器配置中的服务器列表即后端列表也可以来自 cluster 配置而非过滤器配置源码注释表明该机制是过渡方案未来将完全改用 cluster 配置。此外decodeHeaders 会直接拒绝 GET 请求返回 405 Method Not Allowed并校验 session ID 头mcp-session-id无请求体则返回 400。单后端与多后端Multiplexing两种模式从 filter_config.h 可以看到isMultiplexing()的判断标准是后端数量大于 1backends_.size() 1。两种模式在路由语义上有本质区别维度单后端模式多后端Multiplexing模式后端解析一律路由到默认后端根据名称前缀/URI scheme 解析目标后端名称改写不做改写需要剥离/添加前缀server-to-client 响应路由无需 ID 重写只有一个目标需要 JSON-RPCid前缀重写工具名tools/call的路由与改写在多后端模式下聚合后的工具名采用backend__tool格式。客户端发起tools/call时携带前缀名网关在 parseToolName() 中按__分隔符解析出后端名与真实工具名再通过 rewriteToolCallBody() 在请求体中把前缀名替换为后端可识别的原名。原文档示例中的42 → time__42正是这种 ID 前缀机制的体现。资源 URI 的编码方式资源 URI 采用特殊格式backendscheme://path如timefile://current→ 后端time、改写后 URIfile://current解析逻辑见 parseResourceUri()。这种分隔的设计是为了避免后端名与 URI scheme 名冲突。resources/read、resources/subscribe、resources/unsubscribe等单后端资源方法共用 handleSingleBackendResourceMethod() 完成按 URI 路由。扇出Fanout与聚合对于tools/list、resources/list、prompts/list等需要汇总所有后端结果的请求网关通过 initializeFanout() 向所有或指定子集后端发起多路复用请求Http::MuxDemux::multicast收集全部响应后调用聚合回调合并结果如aggregateToolsList、aggregatePromptsList、aggregateResourceItems。这也就是统计指标中rq_fanout的计数场景。惰性初始化Lazy Initialization默认lazy_initialization: false情况下MCP Router 在客户端initialize请求期间急切初始化所有后端阻塞直到每个后端都响应或超时。这在某个后端慢速或不稳定时会拖慢整个客户端初始化流程。当lazy_initialization: true时initialize响应立即返回携带网关自身 capabilities 和空的 backend session 映射每个后端在首个请求首次路由到它时才按需初始化。该行为在原文档中有明确描述并可在实现中找到对应支撑proto 字段定义mcp_router.proto、配置类lazyInitialization()filter_config.h以及 mcp_router.h 中的lazyInitSingleBackend/lazyInitFanout/buildSyntheticInitBody辅助函数。实现层面decodeData() 在惰性初始化进行中会缓冲请求数据lazy_init_request_body_待后端初始化完成后由回调重放replay请求。测试侧mcp_router_test.cc 中有大量用例第 859 行起验证了lazy_initialization字段默认 false、可开启以及开启后的行为。Server-to-Client 请求的透明转发与 ID 重写MCP 协议允许后端服务器在流进行中向客户端发送请求主要包括elicitation/create向用户请求额外输入sampling/createMessage请求 LLM 补全roots/list查询可用 roots。原文档明确了网关的透明处理机制结合源码可以还原完整流程后端发起 SSE server-to-client 请求网关将请求转发给客户端。在多后端multiplexing模式下JSON-RPC 的id字段会被重写为带后端名前缀的形式如42变为time__42见 pushSseEvent() 中对ServerRequest类型事件的 ID 前缀处理数字 ID 与字符串 ID 均被处理。客户端回传 JSON-RPC 响应网关解析带前缀的id确定应送达的后端还原原始id值若为纯数字则恢复为不带引号的数字类型见 rewriteServerResponseId()再将该响应转发给对应后端。单后端模式不做任何 ID 重写因为只有一个可能的目标。整个处理无需额外配置网关自动向客户端通告elicitation能力并根据客户端声明的 capabilities 处理请求/响应路由。SSE 相关的测试见 mcp_router_sse_test.cc如第 108、114、290 行分别验证roots/list、sampling/createMessage、elicitation/create的分类集成场景见 mcp_router_integration_test.cc第 2404、2470 行附近验证 SSE 中的 server-to-client 请求转发。请求转发中的头部处理copyRequestHeaders() 显示网关转发到后端时会跳过:method、:path、:authority、host、content-type、accept以及mcp-session-id头其余请求头原样复制同时pushSseHeaders()会把后端的mcp-session-id移除并替换为客户端请求的会话 IDmcp_router.cc。会话身份Session Identity与校验MCP Router 支持将请求主体subject绑定到 MCP 会话用于多用户场景下的会话隔离与鉴权IdentityExtractor二选一从请求中提取身份——HeaderSource从指定请求头提取如x-user-identityheader 名需符合 HTTP header 命名规则DynamicMetadataSource从动态元数据提取例如由 JWT 或 ext_authz 过滤器填充的MetadataKey。ValidationPolicyMODE_UNSPECIFIED/DISABLED默认若初始化时存在身份则绑定但不校验后续请求提取失败时会话以匿名进行ENFORCE身份提取失败或会话身份与请求身份不匹配时拒绝请求403。实现侧getAuthenticatedSubject() 分别处理 header 源与动态元数据源通过Config::Metadata::metadataValue按 filter 名 路径键取值validateSubjectIfRequired() 在 ENFORCE 模式下比对会话主体与当前请求主体失败时计数rq_auth_failure并返回 403Unable to verify session identity 或 Session identity mismatch。支持的方法分发MCP Router 识别并分发以下 MCP 方法请求类initialize、tools/list、tools/call、resources/list、resources/read、resources/subscribe、resources/unsubscribe、resources/templates/list、prompts/list、prompts/get、completion/complete、logging/setLevel、ping通知类client → server扇出到所有后端notifications/initialized、notifications/cancelled、notifications/roots/list_changed特殊类型__jsonrpc_response客户端对 server-to-client 请求的响应。ping与通知类请求由网关本地直接处理对应rq_direct_response统计未知方法返回 400 并计数rq_invalid。另外从 mcp_router.cc 可以看到网关自身以envoy-mcp-gateway版本1.0.0的身份通告能力协商使用的 MCP 协议版本为2025-06-18。统计指标StatisticsMCP Router 在stat_prefix.mcp_router.命名空间下输出以下计数器原文档统计表完整继承如下其定义可在 filter_config.h 的MCP_ROUTER_STATS宏中逐一对应名称类型描述rq_totalCounter处理的 MCP 请求总数rq_fanoutCounter扇出到多个后端的请求数rq_direct_responseCounter本地直接处理的请求数如 ping、通知rq_body_rewriteCounter发生请求体重写的请求数工具/提示/URI 前缀剥离rq_invalidCounter因元数据无效/缺失或方法不受支持而被拒绝的请求数rq_unknown_backendCounter无法解析目标后端的请求数rq_backend_failureCounter单个后端返回错误的请求数rq_fanout_failureCounter扇出请求中所有后端均失败的请求数rq_session_invalidCounter会话 ID 无效或不可解析的请求数rq_auth_failureCounter因会话身份校验失败而被拒绝的请求数这些指标在实现中的埋点与文档描述完全一致例如rq_invalid在元数据缺失mcp_router.cc与未知方法mcp_router.cc两处递增rq_session_invalid在会话解码失败时递增mcp_router.ccrq_auth_failure在身份校验失败时递增。总结与适用场景MCP Router 过滤器让 Envoy 承担起MCP 聚合网关的角色对外是单一 MCP 服务器对内则完成多后端的会话管理、请求扇出、名称/URI 改写与结果聚合。其典型使用场景包括统一入口聚合将多个后端 MCP 服务工具、资源、提示词暴露为单个端点统一策略执行与 MCP 过滤器 联动基于 MCP 元数据实施 RBAC 或外部授权ext_authz并对出站 AI Agent 流量进行管控慢后端隔离通过lazy_initialization避免不可靠后端阻塞客户端初始化。需要注意的是根据 proto 中的work_in_progress true标注mcp_router.proto该扩展仍处于积极开发中配置与行为可能随版本演进。作为终端过滤器使用时应规划好过滤器链顺序并利用stat_prefix.mcp_router.下的指标持续观测路由与聚合健康状况。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表