You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Legacy initialize responses drop capabilities.extensions (2025-11-25 and earlier) #3773
What happens. On connections that negotiate 2025-11-25 or earlier, a server's initialize result loses capabilities.extensions. The public ServerCapabilities model exposes extensions, but serialize_server_result("initialize", version, ...) validates against the per-version wire model, and _v2025_11_25.ServerCapabilities has no extensions field and uses extra="ignore". Client advertisements survive, so negotiation is one-sided: the client offers an extension but never sees the server accept it.
Why it matters. Extensions became official in 2026-07-28, but they are widely negotiated through initialize on older versions. MCP Apps' stable spec advertises io.modelcontextprotocol/ui this way, and the TypeScript, Go, C#, Rust, Kotlin, Ruby, PHP, and Java SDKs all carry the field on legacy connections. modelcontextprotocol/modelcontextprotocol#3364 documents this and encourages SDKs that can carry the field to do so. Today, a Python server can't advertise MCP Apps (or any extension) to a 2025-11-25 client.
Expected.capabilities.extensions survives legacy initialize serialization in both directions, as it does for 2026-07-28.
Possible fix. Add an optional extensions: dict[str, dict[str, Any]] | None field to the legacy ClientCapabilities/ServerCapabilities wire models (or carve it out of the sieve), and add an initialize round-trip test per supported legacy version.
Related: #3640, which covers unknown capability keys more broadly. This issue is narrower: extensions is a known field that the SDK already models for 2026-07-28.
Activity