wso2-apim-mcp2改版分析
结论
- apim中rest实现的mcp,不需要更新2.0,它是不为2.0取决于客户端和后端服务
- apim中mcp实现的mcp-server,需要有版本控制,版本不对,会出现问题
- apim中的服务,如果中间走了聚合mcp服务,它返回的mcp版本取决于聚合服务的mcp版本
name: MCP Dual Era Support
overview: 在 carbon-apimgt 中让网关北向(客户端↔网关)与南向(网关↔MCP 后端)同时支持 MCP 1.0(2025-06-18,有会话)与 MCP 2.0(2026-07-28,无状态),并在客户端与后端协议世代不一致时由网关做转译。
todos:
- id: phase0-constants
content: 扩展 APIConstants.MCP(2026-07-28、server/discover、Mcp-Method/Name);Publisher 校验 protocolVersion;CORS 增加新头
status: pending - id: phase1-negotiate
content: 实现北向协议探测(Negotiator),写入 MessageContext;支持 Mcp-Method 与 _meta
status: pending - id: phase1-handlers
content: 改造 McpInitHandler/MCPUtils/MCPPayloadGenerator/McpMediator:dual-era initialize/discover、session 策略、GET /mcp 行为
status: pending - id: phase2-fetcher
content: MCPInitializerAndToolFetcher 按 protocolVersion 走 1.0 session 或 2.0 无状态发现,并回写 metadata
status: pending - id: phase2-proxy-translate
content: SERVER_PROXY:元数据注入后端版本 + MCPProtocolTranslator 四象限透传/转译 + legacy session 缓存
status: pending - id: phase3-crosscut
content: Throttle/Analytics/APIKeyValidator/CORS 对齐双协议 method 与版本字段
status: pending - id: phase4-tests
content: 补齐协商/转译/Fetcher/限流单测与南北向 6 类验收场景
status: pending
isProject: false
MCP 1.0 / 2.0 南北向双协议支持任务清单
背景与目标
当前实现锁定 MCP 1.0 Streamable HTTP(2025-06-18):
- 北向:强制
initialize+params.protocolVersion校验;回复版本写死;Mcp-Session-Id仅 CORS expose,不签发/校验 - 南向:
SERVER_PROXY大多透传;MCPInitializerAndToolFetcher写死 initialize→session→tools/list MCPServerDTO.protocolVersion已落AM_API_METADATA,但运行时未使用
目标:同一网关实例对 MCP 1.0 与 2.0 客户端、1.0 与 2.0 后端均可工作;南北协议可不同,由网关转译。
协议世代约定(本方案固定):
- Legacy / MCP 1.0 =
2025-06-18(initialize +Mcp-Session-Id) - Modern / MCP 2.0 =
2026-07-28(无握手/无会话;_meta;server/discover;Mcp-Method/Mcp-Name)
配置模型(固定): 每个 MCP Server 的 metadata.protocolVersion 表示 南向后端 协议;北向按请求自动探测(header / method / _meta / initialize),写入 MessageContext,再与后端版本比较决定透传或转译。
Phase 0 — 协议常量与元数据
- 扩展
APIConstants.MCP- 增加
PROTOCOL_VERSION_2026_JULY = "2026-07-28" SUPPORTED_PROTOCOL_VERSIONS=[2025-06-18, 2026-07-28]- 增加方法:
METHOD_SERVER_DISCOVER = "server/discover" - 增加头:
HEADER_MCP_METHOD = "Mcp-Method"、HEADER_MCP_NAME = "Mcp-Name" - 增加 era 辅助常量 / 判定方法名(legacy vs modern)
- 增加
- Publisher 校验:创建/更新 MCP Server 时
protocolVersion必须属于上述集合;默认仍2025-06-18(兼容现网)- 触点:
PublisherCommonUtils、APIMappingUtil、OpenAPIpublisher-api.yaml
- 触点:
- CORS:在现有
MCP-Protocol-Version/Mcp-Session-Id基础上,强制 allow/exposeMcp-Method、Mcp-Name
Phase 1 — 北向 Dual-Era(客户端 → 网关)
核心文件:McpInitHandler、MCPUtils、MCPPayloadGenerator、McpMediator
- 协议探测(新工具类,建议
MCPProtocolNegotiator)- Legacy 信号:
method=initialize或存在Mcp-Session-Id - Modern 信号:
MCP-Protocol-Version: 2026-07-28,或 body_meta.protocolVersion,或Mcp-Method,或server/discover - 结果写入
MessageContext:MCP_PROTOCOL_VERSION、MCP_PROTOCOL_ERA
- Legacy 信号:
- 方法解析:优先
Mcp-Method头,回退 JSON-RPCmethod;保证 throttle/auth/analytics 与 2.0 头驱动一致 ALLOWED_METHODS+processInternalRequest- 增加
server/discover(网关自建 MCP 时返回 capabilities / serverInfo,替代 2.0 握手) - Legacy:保持
initialize/notifications/initialized流程 - Modern:允许首包直接
tools/list/tools/call/server/discover(不要求先 initialize)
- 增加
validateInitializeRequest/getInitializeResponse- 接受 1.0 与 2.0 版本字符串;回复 echo 协商版本(不再写死)
- Modern 客户端若误发 initialize:返回明确错误或兼容降级(本方案:兼容应答并标记 era=legacy for this connection,避免硬拒)
- 鉴权例外(
isNoAuthMCPRequest)- Legacy:维持现有 ping / notification / resources / prompts
- Modern:将
server/discover纳入与initialize同级策略(本方案:需认证,与tools/list一致,避免未授权探测;若产品要求公开 discover,可再改配置开关)
- Session
- Legacy:initialize 成功时签发
Mcp-Session-Id响应头;后续 POST/GET 可选携带(本方案:不强制校验粘滞,但透传/存储到 context 供南向 1.0 使用) - Modern:不签发、不要求
Mcp-Session-Id
- Legacy:initialize 成功时签发
- Streamable GET
/mcp- Legacy:保持现有 SSE preamble(自建)/ SERVER_PROXY 透传
- Modern:自建路径返回 405 或空闲置通道说明(本方案:对 modern 请求返回 405 Method Not Allowed,因 2.0 无 server-initiated 回推依赖);SERVER_PROXY 仍透传给后端自决
- 自建 MCP(
DIRECT_BACKEND/EXISTING_API)tools/list、tools/call结果形状按北向 era 输出;2.0 列表可带ttlMs/cacheScope等字段(有则填,无则省略)- OUT 包装逻辑按 era 分支错误码映射(如 resource missing
-32002→-32602仅对 modern)
Phase 2 — 南向 Dual-Era(网关 → 后端)
2A. Publisher 发现客户端
改造 MCPInitializerAndToolFetcher:
- 构造/方法增加
protocolVersion参数(来自校验请求或已存 metadata) - 1.0 路径:保持 initialize → 读
Mcp-Session-Id→notifications/initialized→tools/list+MCP-Protocol-Version - 2.0 路径:发送
MCP-Protocol-Version: 2026-07-28+Mcp-Method;用server/discover(若后端支持)或直接tools/list;body 带_meta;不依赖 session - 校验/刷新入口(
McpServersApiServiceImpl/RestApiPublisherUtils)写入探测到的实际版本到metadata.protocolVersion
2B. SERVER_PROXY 运行时
- Synapse 透传保证不剥离:
MCP-Protocol-Version、Mcp-Session-Id(1.0)、Mcp-Method/Mcp-Name(2.0)、以及 JSON body_meta - 从订阅/API 元数据读取后端
protocolVersion注入 MessageContext(需确认 keymgtAPI实体是否带 metadata;若无,在网关 DataHolder/部署产物中补充 protocolVersion 字段) - 同世代:透传(现逻辑),
tools/list仍可由网关用已发布目录合成(保持现行为) - 跨世代转译(新模块,建议
MCPProtocolTranslator)
| 北向 | 南向 | 行为 |
|---|---|---|
| 1.0 | 1.0 | 透传 |
| 2.0 | 2.0 | 透传 + 补齐 Mcp-Method/_meta(若客户端未带) |
| 1.0 | 2.0 | 吃客户端 initialize(网关本地应答);南向去掉 session,改写为 modern 请求;响应回写为 1.0 JSON-RPC |
| 2.0 | 1.0 | 网关代持后端 session(initialize + 缓存 sessionId);对客户端隐藏 session;南向发 legacy,北向回 modern |
Session 缓存:按 apiId + clientCredential/hash 短 TTL 内存/Redis(本方案优先 本地 Guava/Caffeine 式缓存 + TTL,与现有 gateway 缓存模式对齐;多节点后续再上分布式)。
2C. 自建 MCP 南向
DIRECT_BACKEND / EXISTING_API 的 tools/call→REST 与 MCP 版本无关;仅保证北向应答符合客户端 era(Phase 1)。
Phase 3 — 横切:鉴权、限流、分析、CORS
ThrottleHandler:继续仅对tools/call限流;method 来源含Mcp-Method- Analytics:填充
MCP_PROTOCOL_VERSION/ era / sessionId(legacy)到SynapseAnalyticsDataProvidercustom props APIKeyValidator:tool→resource 映射不因 era 改变- WWW-Authenticate / well-known:保持;核对 2.0 对
iss的更严校验不破坏现有 metadata 响应
Phase 4 — 测试与验收矩阵
| 场景 | 期望 |
|---|---|
| 1.0 客户端 → 自建 MCP | initialize/list/call 成功,带回 session 头 |
| 2.0 客户端 → 自建 MCP | 无 initialize;discover/list/call 成功;无 session |
| 1.0 客户端 → SERVER_PROXY 1.0 后端 | 透传成功 |
| 2.0 客户端 → SERVER_PROXY 2.0 后端 | 透传成功 |
| 1.0 客户端 → SERVER_PROXY 2.0 后端 | 转译成功 |
| 2.0 客户端 → SERVER_PROXY 1.0 后端 | 转译成功(网关代持 session) |
| Publisher 拉 1.0 / 2.0 工具列表 | 各自路径成功并写入正确 protocolVersion |
| 不支持版本 | initialize/_meta 返回 supported 列表错误体 |
单测重点:MCPUtils 协商/校验、MCPProtocolTranslator 往返、MCPInitializerAndToolFetcher 双路径、Throttle method 头解析。
主要改动文件(按优先级)
APIConstants.java— 版本/方法/头- 新建
MCPProtocolNegotiator+MCPProtocolTranslator(gateway 包下) McpInitHandler.java/MCPUtils.java/MCPPayloadGenerator.java/McpMediator.javaMCPInitializerAndToolFetcher.java+ Publisher validate/create/refresh 调用链APIMappingUtil/ CORS / metadata 校验- Throttle + Analytics providers
- 对应 unit tests
不在本清单:Helm chart、Devportal UI 大改、完整 MCP Apps/Tasks 扩展(仅保证 core tools/list/call/discover/initialize)。
网关如何知道后端mcp是哪个版本
靠的是 MCP Server 上配置的 protocolVersion(表示南向后端协议),不是每次请求去猜后端。
数据从哪来
-
创建/更新时写入
Publisher 在 MCP Server DTO 里带protocolVersion:2025-06-18→ 后端是 MCP 1.02026-07-28→ 后端是 MCP 2.0- 不填则默认
2025-06-18
-
落库
写到AM_API_METADATA,key 为protocolVersion。 -
部署到网关
打进 Gateway 部署产物的additionalProperties,运行时挂到 keymgtAPI.protocolVersion/apiProperties。 -
请求时读取
MCPProtocolNegotiator.resolveBackendProtocolVersion(api)读这个字段,写入MCP_BACKEND_PROTOCOL_VERSION,再和北向探测到的客户端版本比较,决定透传还是转译。
和北向的区别
| 方向 | 怎么知道版本 |
|---|---|
| 北向(客户端→网关) | 自动探测:initialize / Mcp-Session-Id / MCP-Protocol-Version / _meta / Mcp-Method / server/discover |
| 南向(网关→后端) | 配置驱动:读该 MCP Server 的 metadata.protocolVersion |
运维时怎么填
- 明确后端是 1.0 / 2.0:创建 MCP Server 时设对
protocolVersion - 校验第三方 MCP:先按 1.0 拉 tools,失败再试 2.0(
validateThirdPartyMCPServer);成功后建议把对应版本写回该 Server 的protocolVersion
结论: 网关“知道”后端是几,是因为你(或校验流程)把它记在 MCP Server 配置里,并随部署带到网关;运行时只读配置,不做握手探测。
浙公网安备 33010602011771号