Class: MCP::ServerContext
- Inherits:
-
Object
- Object
- MCP::ServerContext
- Defined in:
- lib/mcp/server_context.rb
Instance Attribute Summary collapse
-
#cancellation ⇒ Object
readonly
Returns the value of attribute cancellation.
-
#envelope ⇒ Object
readonly
The SEP-2575 per-request envelope (
MCP::RequestEnvelope) when the request was classified as modern;nilon legacy requests. -
#input_responses ⇒ Object
readonly
SEP-2322 multi round-trip retry fields, present when the client re-issued the request after an
input_requiredresult:input_responsesmaps the keys of the earlierinputRequeststo the client's answers, andrequest_stateis the opaque continuation string echoed back byte-exactly. -
#request_state ⇒ Object
readonly
SEP-2322 multi round-trip retry fields, present when the client re-issued the request after an
input_requiredresult:input_responsesmaps the keys of the earlierinputRequeststo the client's answers, andrequest_stateis the opaque continuation string echoed back byte-exactly.
Instance Method Summary collapse
- #cancelled? ⇒ Boolean
-
#client_capabilities ⇒ Object
Client capabilities for the current request, with the same envelope-first resolution as #client_info.
-
#client_info ⇒ Object
Client identity for the current request.
-
#create_form_elicitation(**kwargs) ⇒ Object
Delegates to the session so the request is scoped to the originating client.
-
#create_sampling_message(**kwargs) ⇒ Object
deprecated
Deprecated.
MCP Sampling (
sampling/createMessage) is deprecated as of MCP protocol version 2026-07-28 (SEP-2577). Use direct LLM provider APIs instead. -
#create_url_elicitation(**kwargs) ⇒ Object
Delegates to the session so the request is scoped to the originating client.
-
#initialize(context, progress:, notification_target:, related_request_id: nil, cancellation: nil, envelope: nil, input_responses: nil, request_state: nil) ⇒ ServerContext
constructor
A new instance of ServerContext.
-
#input_response(key) ⇒ Object
Reads one entry of #input_responses by its
inputRequestskey, tolerating symbol or string keys. -
#list_roots(timeout: nil) ⇒ Object
deprecated
Deprecated.
MCP Roots (
roots/listandnotifications/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. -
#method_missing(name, *args, **kwargs, &block) ⇒ Object
Forward arguments explicitly with
*args, **kwargs, &blockrather than the...forwarding syntax. -
#modern? ⇒ Boolean
Whether the current request follows the stateless modern lifecycle (SEP-2575).
-
#notify_elicitation_complete(**kwargs) ⇒ Object
Delegates to the session so the notification is scoped to the originating client.
-
#notify_log_message(data:, level:, logger: nil) ⇒ Object
deprecated
Deprecated.
MCP Logging (
logging/setLevelandnotifications/message) is deprecated as of MCP protocol version 2026-07-28 (SEP-2577). Use stderr or OpenTelemetry instead. -
#notify_resources_updated(uri:) ⇒ Object
Sends a resource updated notification scoped to the originating session.
-
#ping(timeout: nil) ⇒ Hash
Sends a
pingrequest to the originating client to verify it is still responsive. -
#protocol_version ⇒ Object
The protocol version the current request was made with.
- #raise_if_cancelled! ⇒ Object
-
#report_progress(progress, total: nil, message: nil) ⇒ Object
Reports progress for the current tool operation.
-
#require_client_capability!(*path) ⇒ Object
Guards the current request on a declared client capability (SEP-2575).
- #respond_to_missing?(name, include_private = false) ⇒ Boolean
Constructor Details
#initialize(context, progress:, notification_target:, related_request_id: nil, cancellation: nil, envelope: nil, input_responses: nil, request_state: nil) ⇒ ServerContext
Returns a new instance of ServerContext.
18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/mcp/server_context.rb', line 18 def initialize(context, progress:, notification_target:, related_request_id: nil, cancellation: nil, envelope: nil, input_responses: nil, request_state: nil) @context = context @progress = progress @notification_target = notification_target @related_request_id = @cancellation = cancellation @envelope = envelope @input_responses = input_responses @request_state = request_state end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, **kwargs, &block) ⇒ Object
Forward arguments explicitly with *args, **kwargs, &block rather than the ... forwarding syntax.
The gem supports Ruby 2.7.0 (see required_ruby_version), but RuboCop's Parser backend only runs on Ruby 2.7.8,
so leading-argument forwarding like def method_missing(name, ...) is allowed by the linter even though it
raises a SyntaxError on Ruby 2.7.0 through 2.7.2 (it was added in Ruby 2.7.3). Explicit forwarding keeps
this method loadable on Ruby 2.7.0.
237 238 239 240 241 242 243 |
# File 'lib/mcp/server_context.rb', line 237 def method_missing(name, *args, **kwargs, &block) if @context.respond_to?(name) @context.public_send(name, *args, **kwargs, &block) else super end end |
Instance Attribute Details
#cancellation ⇒ Object (readonly)
Returns the value of attribute cancellation.
5 6 7 |
# File 'lib/mcp/server_context.rb', line 5 def cancellation @cancellation end |
#envelope ⇒ Object (readonly)
The SEP-2575 per-request envelope (MCP::RequestEnvelope) when the request was classified as modern;
nil on legacy requests.
9 10 11 |
# File 'lib/mcp/server_context.rb', line 9 def envelope @envelope end |
#input_responses ⇒ Object (readonly)
SEP-2322 multi round-trip retry fields, present when the client re-issued the request after
an input_required result: input_responses maps the keys of the earlier inputRequests to
the client's answers, and request_state is the opaque continuation string echoed back byte-exactly.
Both are nil on a first-round request. Only handlers that opt in to server_context: can read them
(the same access model as the envelope readers).
16 17 18 |
# File 'lib/mcp/server_context.rb', line 16 def input_responses @input_responses end |
#request_state ⇒ Object (readonly)
SEP-2322 multi round-trip retry fields, present when the client re-issued the request after
an input_required result: input_responses maps the keys of the earlier inputRequests to
the client's answers, and request_state is the opaque continuation string echoed back byte-exactly.
Both are nil on a first-round request. Only handlers that opt in to server_context: can read them
(the same access model as the envelope readers).
16 17 18 |
# File 'lib/mcp/server_context.rb', line 16 def request_state @request_state end |
Instance Method Details
#cancelled? ⇒ Boolean
38 39 40 |
# File 'lib/mcp/server_context.rb', line 38 def cancelled? !!@cancellation&.cancelled? end |
#client_capabilities ⇒ Object
Client capabilities for the current request, with the same envelope-first resolution as #client_info.
61 62 63 64 65 |
# File 'lib/mcp/server_context.rb', line 61 def client_capabilities return @envelope.client_capabilities if @envelope @notification_target.client_capabilities if @notification_target.respond_to?(:client_capabilities) end |
#client_info ⇒ Object
Client identity for the current request. Modern requests carry it in the _meta envelope;
legacy sessions fall back to the state stored by initialize. The envelope always wins
because servers MUST NOT infer identity from prior requests.
54 55 56 57 58 |
# File 'lib/mcp/server_context.rb', line 54 def client_info return @envelope.client_info if @envelope @notification_target.client if @notification_target.respond_to?(:client) end |
#create_form_elicitation(**kwargs) ⇒ Object
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).
197 198 199 200 201 202 203 204 205 |
# File 'lib/mcp/server_context.rb', line 197 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) elsif @context.respond_to?(:create_form_elicitation) @context.create_form_elicitation(**kwargs, related_request_id: @related_request_id) else raise NoMethodError, "undefined method 'create_form_elicitation' for #{self}" end end |
#create_sampling_message(**kwargs) ⇒ Object
MCP Sampling (sampling/createMessage) is deprecated as of
MCP protocol version 2026-07-28 (SEP-2577). Use direct LLM provider
APIs instead.
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.
182 183 184 185 186 187 188 189 190 |
# File 'lib/mcp/server_context.rb', line 182 def (**kwargs) if @notification_target.respond_to?(:create_sampling_message) @notification_target.(**kwargs, related_request_id: @related_request_id) elsif @context.respond_to?(:create_sampling_message) @context.(**kwargs, related_request_id: @related_request_id) else raise NoMethodError, "undefined method 'create_sampling_message' for #{self}" end end |
#create_url_elicitation(**kwargs) ⇒ Object
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).
211 212 213 214 215 216 217 218 219 |
# File 'lib/mcp/server_context.rb', line 211 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) elsif @context.respond_to?(:create_url_elicitation) @context.create_url_elicitation(**kwargs, related_request_id: @related_request_id) else raise NoMethodError, "undefined method 'create_url_elicitation' for #{self}" end end |
#input_response(key) ⇒ Object
Reads one entry of #input_responses by its inputRequests key, tolerating symbol or string keys.
31 32 33 34 35 36 |
# File 'lib/mcp/server_context.rb', line 31 def input_response(key) return unless @input_responses.is_a?(Hash) value = @input_responses[key.to_sym] value.nil? ? @input_responses[key.to_s] : value end |
#list_roots(timeout: nil) ⇒ Object
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.
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.
141 142 143 144 145 146 147 |
# File 'lib/mcp/server_context.rb', line 141 def list_roots(timeout: nil) if @notification_target.respond_to?(:list_roots) @notification_target.list_roots(related_request_id: @related_request_id, **timeout_kwarg(timeout)) else raise NoMethodError, "undefined method 'list_roots' for #{self}" end end |
#modern? ⇒ Boolean
Whether the current request follows the stateless modern lifecycle (SEP-2575).
47 48 49 |
# File 'lib/mcp/server_context.rb', line 47 def modern? !@envelope.nil? end |
#notify_elicitation_complete(**kwargs) ⇒ Object
Delegates to the session so the notification is scoped to the originating client.
222 223 224 225 226 227 228 229 230 |
# File 'lib/mcp/server_context.rb', line 222 def notify_elicitation_complete(**kwargs) if @notification_target.respond_to?(:notify_elicitation_complete) @notification_target.notify_elicitation_complete(**kwargs) elsif @context.respond_to?(:notify_elicitation_complete) @context.notify_elicitation_complete(**kwargs) else raise NoMethodError, "undefined method 'notify_elicitation_complete' for #{self}" end end |
#notify_log_message(data:, level:, logger: nil) ⇒ Object
MCP Logging (logging/setLevel and notifications/message)
is deprecated as of MCP protocol version 2026-07-28 (SEP-2577).
Use stderr or OpenTelemetry instead.
Sends a log message notification scoped to the originating session.
110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/mcp/server_context.rb', line 110 def (data:, level:, logger: nil) return unless @notification_target # Modern requests opt in to logging per request (SEP-2575): without `io.modelcontextprotocol/logLevel` in `_meta`, # the server MUST NOT send any `notifications/message` for the request, and an insufficient level drops # the message the same way. Session- or server-level gating still applies downstream on delegation. if @envelope threshold = @envelope.log_level && LoggingMessageNotification.new(level: @envelope.log_level) return unless threshold&.valid_level? && threshold.should_notify?(level) end @notification_target.(data: data, level: level, logger: logger, related_request_id: @related_request_id) end |
#notify_resources_updated(uri:) ⇒ Object
Sends a resource updated notification scoped to the originating session.
127 128 129 130 131 |
# File 'lib/mcp/server_context.rb', line 127 def notify_resources_updated(uri:) return unless @notification_target @notification_target.notify_resources_updated(uri: uri) end |
#ping(timeout: nil) ⇒ Hash
Sends a ping request to the originating client to verify it is still responsive.
Per the MCP spec, the client MUST respond promptly with an empty result.
163 164 165 166 167 168 169 |
# File 'lib/mcp/server_context.rb', line 163 def ping(timeout: nil) if @notification_target.respond_to?(:ping) @notification_target.ping(related_request_id: @related_request_id, **timeout_kwarg(timeout)) else raise NoMethodError, "undefined method 'ping' for #{self}" end end |
#protocol_version ⇒ Object
The protocol version the current request was made with. nil on legacy requests,
where the version is a session-level negotiation result rather than per-request data.
69 70 71 |
# File 'lib/mcp/server_context.rb', line 69 def protocol_version @envelope&.protocol_version end |
#raise_if_cancelled! ⇒ Object
42 43 44 |
# File 'lib/mcp/server_context.rb', line 42 def raise_if_cancelled! @cancellation&.raise_if_cancelled! end |
#report_progress(progress, total: nil, message: nil) ⇒ Object
Reports progress for the current tool operation. The notification is automatically scoped to the originating session.
98 99 100 |
# File 'lib/mcp/server_context.rb', line 98 def report_progress(progress, total: nil, message: nil) @progress.report(progress, total: total, message: ) end |
#require_client_capability!(*path) ⇒ Object
Guards the current request on a declared client capability (SEP-2575). path names nested capability keys,
e.g. require_client_capability!(:elicitation, :form). Raises Server::MissingRequiredClientCapabilityError
(JSON-RPC error -32021 with data: { requiredCapabilities: ... }) when the capability was not declared.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/mcp/server_context.rb', line 76 def require_client_capability!(*path) raise ArgumentError, "at least one capability key is required" if path.empty? declared = client_capabilities value = path.reduce(declared) do |acc, key| break unless acc.is_a?(Hash) symbol_value = acc[key.to_sym] symbol_value.nil? ? acc[key.to_s] : symbol_value end return unless value.nil? required = path.reverse.inject({}) { |acc, key| { key.to_sym => acc } } raise Server::MissingRequiredClientCapabilityError, required end |
#respond_to_missing?(name, include_private = false) ⇒ Boolean
245 246 247 |
# File 'lib/mcp/server_context.rb', line 245 def respond_to_missing?(name, include_private = false) @context.respond_to?(name) || super end |