Merge pull request #516 from koic/counter_offer_legacy_version_on_initialize

Stop negotiating modern protocol versions through the `initialize` handshake
This commit is contained in:
Koichi ITO 2026-08-15 11:32:15 +09:00 • committed by GitHub
commit a62e56ef48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -403,8 +403,6 @@ module MCP
# is deprecated as of MCP protocol version 2026-07-28 (SEP-2577).
# Use stderr or OpenTelemetry instead.
def notify_log_message(data:, level:, logger: nil)
warn_if_deprecated_protocol_feature(:logging, uplevel: 1)
return unless @transport
return unless logging_message_notification&.should_notify?(level)
@ -425,8 +423,6 @@ module MCP
# version 2026-07-28 (SEP-2577). Use tool parameters, resource URIs,
# server configuration, or environment variables instead.
def roots_list_changed_handler(&block)
warn_if_deprecated_protocol_feature(:roots, uplevel: 1)
@handlers[Methods::NOTIFICATIONS_ROOTS_LIST_CHANGED] = block
end
@ -591,13 +587,6 @@ module MCP
return ->(params) { handle_cancelled_notification(params, session: session) }
end
case method
when Methods::NOTIFICATIONS_ROOTS_LIST_CHANGED
warn_if_deprecated_protocol_feature(:roots, session: session, uplevel: 2)
when Methods::LOGGING_SET_LEVEL
warn_if_deprecated_protocol_feature(:logging, session: session, uplevel: 2)
end
handler = @handlers[method]
unless handler
instrument_call("unsupported_method", server_context: { request: request }) do
@ -1045,10 +1034,19 @@ module MCP
end
protocol_version = params[:protocolVersion]
negotiated_version = if Configuration::SUPPORTED_STABLE_PROTOCOL_VERSIONS.include?(protocol_version)
# Per the SEP-2575 era model, `initialize` negotiates legacy protocol versions only: a modern version is
# defined by carrying its own version on every request in `_meta`, with no handshake,
# so asking `initialize` for one (or for a version this server does not know) is answered with
# a counter-offer instead of an echo, matching the TypeScript and Python SDKs. Modern versions
# stay reachable through `server/discover` and the per-request envelope. The counter-offer is
# a configured `protocol_version` pin when one is set (`Configuration` only accepts handshake versions there),
# and the latest handshake version otherwise.
negotiated_version = if Configuration.handshake_protocol_version?(protocol_version)
protocol_version
else
elsif configuration.protocol_version?
configuration.protocol_version
else
Configuration::LATEST_HANDSHAKE_PROTOCOL_VERSION
end
info = server_info.reject do |property|
@ -1160,19 +1158,6 @@ module MCP
{}
end
def warn_if_deprecated_protocol_feature(feature, session: nil, uplevel: 1)
protocol_version = effective_deprecation_protocol_version(session)
MCP::ProtocolDeprecations.warn_for(feature, protocol_version: protocol_version, uplevel: uplevel)
end
def effective_deprecation_protocol_version(session)
session&.protocol_version || @client_protocol_version || explicit_protocol_version
end
def explicit_protocol_version
configuration.protocol_version if configuration.protocol_version?
end
def list_tools(request)
page = paginate(@tools.values, cursor: cursor_from(request), page_size: @page_size, request: request, &:to_h)