From 78cc487304d7a690052a4900e98ef8909a90400c Mon Sep 17 00:00:00 2001 From: lucarlig Date: Fri, 18 Sep 2026 17:19:28 +0100 Subject: [PATCH] fix: accept metadata on legacy conformance initialize Treat session-era initialize requests as legacy based on params.protocolVersion even when optional request metadata is present. This prevents MCP Python SDK 2.x initialization from being rejected as modern traffic. Signed-off-by: lucarlig --- CHANGELOG.md | 5 +++++ docker/mcp-conformance.patch | 32 +++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 653f226..b5fd689 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html) ## [Unreleased] +### Fixed + +- Accept optional request metadata on session-era `initialize` requests in the + pinned conformance fixture instead of misclassifying them as modern traffic. + ## [0.5.0] - 2026-09-16 ### Added diff --git a/docker/mcp-conformance.patch b/docker/mcp-conformance.patch index 7f7ad8b..799c17b 100644 --- a/docker/mcp-conformance.patch +++ b/docker/mcp-conformance.patch @@ -24,12 +24,32 @@ // Stateless (draft) operations whose results MUST carry the SEP-2549 caching // hints (`ttlMs`, `cacheScope`). const STATELESS_CACHEABLE_METHODS: ReadonlySet = new Set([ -@@ -1283,8 +1291,42 @@ - meta === undefined && - reqVersion !== undefined && - LEGACY_SESSION_PROTOCOL_VERSIONS.includes(reqVersion); +@@ -1276,15 +1284,57 @@ + const meta = params._meta; + const metaVersion = meta?.['io.modelcontextprotocol/protocolVersion']; - -- if (!sessionId && (reqVersion || meta) && !isLegacySessionEraRequest) { ++ +- // A request that carries no `_meta` and names a legacy session-era revision +- // in the header is legacy traffic; it is served by the session path below +- // instead of being rejected for missing per-request metadata. ++ // An initialize request negotiates its version in params and may carry the ++ // optional RequestParams `_meta` field. Route session-era versions through ++ // the stateful transport even when that metadata is present. ++ const isLegacyInitializeRequest = ++ isInitializeRequest(body) && ++ typeof params.protocolVersion === 'string' && ++ LEGACY_SESSION_PROTOCOL_VERSIONS.includes(params.protocolVersion); ++ ++ // A non-initialize request that carries no `_meta` and names a legacy ++ // session-era revision in the header is also legacy traffic. + const isLegacySessionEraRequest = +- meta === undefined && +- reqVersion !== undefined && +- LEGACY_SESSION_PROTOCOL_VERSIONS.includes(reqVersion); ++ isLegacyInitializeRequest || ++ (meta === undefined && ++ reqVersion !== undefined && ++ LEGACY_SESSION_PROTOCOL_VERSIONS.includes(reqVersion)); + const isModernEraRequest = + !sessionId && (reqVersion !== undefined || meta !== undefined) && + !isLegacySessionEraRequest; @@ -64,7 +84,9 @@ + } + }); + } +- + +- if (!sessionId && (reqVersion || meta) && !isLegacySessionEraRequest) { + if (isModernEraRequest) { // Missing Transport Header Validation Check if (!reqVersion) {