Merge pull request #440 from koic/mcp_2026_07_28_spec_associate_server_requests
Associate server-to-client requests with the originating client request per SEP-2260
This commit is contained in:
commit
a793dde6cd
2 changed files with 323 additions and 16 deletions
|
|
@ -54,6 +54,9 @@ module MCP
|
|||
end
|
||||
|
||||
# Delegates to the session so the request is scoped to the originating client.
|
||||
# The originating request id is stamped as `related_request_id`, satisfying
|
||||
# SEP-2260's requirement that server-to-client requests be associated with
|
||||
# the client request being processed.
|
||||
# @deprecated MCP Roots (`roots/list` and
|
||||
# `notifications/roots/list_changed`) is deprecated as of MCP protocol
|
||||
# version 2026-07-28 (SEP-2577). Use tool parameters, resource URIs,
|
||||
|
|
@ -91,6 +94,11 @@ module MCP
|
|||
# Delegates to the session so the request is scoped to the originating client.
|
||||
# Falls back to `@context` (via `method_missing`) when `@notification_target`
|
||||
# does not support sampling.
|
||||
#
|
||||
# The originating request id is stamped as `related_request_id` and cannot be
|
||||
# overridden by callers (the literal keyword after `**kwargs` wins),
|
||||
# satisfying SEP-2260's requirement that server-to-client requests be
|
||||
# associated with the client request being processed.
|
||||
# @deprecated MCP Sampling (`sampling/createMessage`) is deprecated as of
|
||||
# MCP protocol version 2026-07-28 (SEP-2577). Use direct LLM provider
|
||||
# APIs instead.
|
||||
|
|
@ -107,6 +115,8 @@ module MCP
|
|||
# Delegates to the session so the request is scoped to the originating client.
|
||||
# Falls back to `@context` (via `method_missing`) when `@notification_target`
|
||||
# does not support elicitation.
|
||||
# The originating request id is stamped as a non-overridable
|
||||
# `related_request_id`, as with `create_sampling_message` (SEP-2260).
|
||||
def create_form_elicitation(**kwargs)
|
||||
if @notification_target.respond_to?(:create_form_elicitation)
|
||||
@notification_target.create_form_elicitation(**kwargs, related_request_id: @related_request_id)
|
||||
|
|
@ -119,6 +129,8 @@ module MCP
|
|||
|
||||
# Delegates to the session so the request is scoped to the originating client.
|
||||
# Falls back to `@context` when `@notification_target` does not support URL mode elicitation.
|
||||
# The originating request id is stamped as a non-overridable `related_request_id`,
|
||||
# as with `create_sampling_message` (SEP-2260).
|
||||
def create_url_elicitation(**kwargs)
|
||||
if @notification_target.respond_to?(:create_url_elicitation)
|
||||
@notification_target.create_url_elicitation(**kwargs, related_request_id: @related_request_id)
|
||||
|
|
|
|||
|
|
@ -98,11 +98,17 @@ module MCP
|
|||
end
|
||||
|
||||
# Sends a `roots/list` request scoped to this session.
|
||||
#
|
||||
# Per SEP-2260, the request must be associated with an originating client
|
||||
# request; prefer `server_context.list_roots` inside a handler, which stamps
|
||||
# the association automatically.
|
||||
# @deprecated MCP Roots (`roots/list` and
|
||||
# `notifications/roots/list_changed`) is deprecated as of MCP protocol
|
||||
# version 2026-07-28 (SEP-2577). Use tool parameters, resource URIs,
|
||||
# server configuration, or environment variables instead.
|
||||
def list_roots(related_request_id: nil)
|
||||
warn_unassociated_request(__method__, related_request_id)
|
||||
|
||||
unless client_capabilities&.dig(:roots)
|
||||
raise "Client does not support roots."
|
||||
end
|
||||
|
|
@ -119,16 +125,28 @@ module MCP
|
|||
end
|
||||
|
||||
# Sends a `sampling/createMessage` request scoped to this session.
|
||||
#
|
||||
# Per SEP-2260, the request must be associated with an originating client
|
||||
# request; prefer `server_context.create_sampling_message` inside a handler,
|
||||
# which stamps the association automatically.
|
||||
# @deprecated MCP Sampling (`sampling/createMessage`) is deprecated as of
|
||||
# MCP protocol version 2026-07-28 (SEP-2577). Use direct LLM provider
|
||||
# APIs instead.
|
||||
def create_sampling_message(related_request_id: nil, **kwargs)
|
||||
warn_unassociated_request(__method__, related_request_id)
|
||||
|
||||
params = @server.build_sampling_params(client_capabilities, **kwargs)
|
||||
send_to_transport_request(Methods::SAMPLING_CREATE_MESSAGE, params, related_request_id: related_request_id)
|
||||
end
|
||||
|
||||
# Sends an `elicitation/create` request (form mode) scoped to this session.
|
||||
#
|
||||
# Per SEP-2260, the request must be associated with an originating client
|
||||
# request; prefer `server_context.create_form_elicitation` inside a handler,
|
||||
# which stamps the association automatically.
|
||||
def create_form_elicitation(message:, requested_schema:, related_request_id: nil)
|
||||
warn_unassociated_request(__method__, related_request_id)
|
||||
|
||||
unless client_capabilities&.dig(:elicitation)
|
||||
raise "Client does not support elicitation. " \
|
||||
"The client must declare the `elicitation` capability during initialization."
|
||||
|
|
@ -139,7 +157,13 @@ module MCP
|
|||
end
|
||||
|
||||
# Sends an `elicitation/create` request (URL mode) scoped to this session.
|
||||
#
|
||||
# Per SEP-2260, the request must be associated with an originating client
|
||||
# request; prefer `server_context.create_url_elicitation` inside a handler,
|
||||
# which stamps the association automatically.
|
||||
def create_url_elicitation(message:, url:, elicitation_id:, related_request_id: nil)
|
||||
warn_unassociated_request(__method__, related_request_id)
|
||||
|
||||
unless client_capabilities&.dig(:elicitation, :url)
|
||||
raise "Client does not support URL mode elicitation. " \
|
||||
"The client must declare the `elicitation.url` capability during initialization."
|
||||
|
|
@ -264,5 +288,21 @@ module MCP
|
|||
# The explicit splat suppresses that conversion and is a no-op when `supported` is empty.
|
||||
transport_method.call(method, params, **supported)
|
||||
end
|
||||
|
||||
# Per SEP-2260, servers MUST send `roots/list`, `sampling/createMessage`, and `elicitation/create` only
|
||||
# in association with an originating client request (`ping` is exempt). A request without `related_request_id:` is
|
||||
# delivered on the standalone GET stream by the Streamable HTTP transport, which the 2026-07-28 spec forbids;
|
||||
# warn so callers migrate to the `server_context` helpers before this becomes an error.
|
||||
# https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2260
|
||||
def warn_unassociated_request(method_name, related_request_id)
|
||||
return if related_request_id
|
||||
|
||||
warn(
|
||||
"Calling `ServerSession##{method_name}` without `related_request_id:` is deprecated (SEP-2260): " \
|
||||
"server-to-client #{method_name} requests must be associated with an originating client request. " \
|
||||
"Use `server_context.#{method_name}` inside a handler, or pass `related_request_id:` explicitly.",
|
||||
uplevel: 2,
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue