Class: VectorMCP::Session
- Inherits:
-
Object
- Object
- VectorMCP::Session
- Defined in:
- lib/vector_mcp/session.rb
Overview
Represents the state of a single client-server connection session in MCP. It tracks initialization status, and negotiated capabilities between the client and server.
Instance Attribute Summary collapse
-
#client_capabilities ⇒ Hash?
readonly
Capabilities supported by the client, received during initialization.
-
#client_info ⇒ Hash?
readonly
Information about the client, received during initialization.
-
#data ⇒ Object
For user-defined session-specific storage and resolved auth context.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#protocol_version ⇒ String
readonly
The MCP protocol version used by the server.
-
#request_context ⇒ RequestContext
The request context for this session.
-
#security_context ⇒ Object
For user-defined session-specific storage and resolved auth context.
-
#server ⇒ Object
readonly
Returns the value of attribute server.
-
#server_capabilities ⇒ Hash
readonly
Capabilities supported by the server.
-
#server_info ⇒ Hash
readonly
Information about the server.
-
#transport ⇒ Object
readonly
Returns the value of attribute transport.
Instance Method Summary collapse
-
#initialize(server, transport = nil, id: SecureRandom.uuid, request_context: nil) ⇒ Session
constructor
Initializes a new session.
-
#initialize!(params) ⇒ Hash
Marks the session as initialized using parameters from the client’s ‘initialize` request.
-
#initialized? ⇒ Boolean
Checks if the session has been successfully initialized.
-
#request_header(name) ⇒ String?
Convenience method to get a request header value.
-
#request_headers? ⇒ Boolean
Convenience method to check if the session has request headers.
-
#request_param(name) ⇒ String?
Convenience method to get a request parameter value.
-
#request_params? ⇒ Boolean
Convenience method to check if the session has request parameters.
-
#sample(request_params, timeout: nil) ⇒ VectorMCP::Sampling::Result
Initiates an MCP sampling request to the client associated with this session.
-
#update_request_context(**attributes) ⇒ RequestContext
Updates the request context with new data.
Constructor Details
#initialize(server, transport = nil, id: SecureRandom.uuid, request_context: nil) ⇒ Session
Initializes a new session.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/vector_mcp/session.rb', line 29 def initialize(server, transport = nil, id: SecureRandom.uuid, request_context: nil) @server = server @transport = transport # Store the transport for sending requests @id = id @initialized_state = :pending # :pending, :succeeded, :failed @client_info = nil @client_capabilities = nil @data = {} # Initialize user data hash @security_context = Security::SessionContext.anonymous @logger = server.logger # Initialize request context @request_context = case request_context when RequestContext request_context when Hash RequestContext.new(**request_context) else RequestContext.new end end |
Instance Attribute Details
#client_capabilities ⇒ Hash? (readonly)
Capabilities supported by the client, received during initialization.
19 20 21 |
# File 'lib/vector_mcp/session.rb', line 19 def client_capabilities @client_capabilities end |
#client_info ⇒ Hash? (readonly)
Information about the client, received during initialization.
19 20 21 |
# File 'lib/vector_mcp/session.rb', line 19 def client_info @client_info end |
#data ⇒ Object
For user-defined session-specific storage and resolved auth context
21 22 23 |
# File 'lib/vector_mcp/session.rb', line 21 def data @data end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
20 21 22 |
# File 'lib/vector_mcp/session.rb', line 20 def id @id end |
#protocol_version ⇒ String (readonly)
The MCP protocol version used by the server.
19 20 21 |
# File 'lib/vector_mcp/session.rb', line 19 def protocol_version @protocol_version end |
#request_context ⇒ RequestContext
The request context for this session.
19 20 21 |
# File 'lib/vector_mcp/session.rb', line 19 def request_context @request_context end |
#security_context ⇒ Object
For user-defined session-specific storage and resolved auth context
21 22 23 |
# File 'lib/vector_mcp/session.rb', line 21 def security_context @security_context end |
#server ⇒ Object (readonly)
Returns the value of attribute server.
20 21 22 |
# File 'lib/vector_mcp/session.rb', line 20 def server @server end |
#server_capabilities ⇒ Hash (readonly)
Capabilities supported by the server.
19 20 21 |
# File 'lib/vector_mcp/session.rb', line 19 def server_capabilities @server_capabilities end |
#server_info ⇒ Hash (readonly)
Information about the server.
19 20 21 |
# File 'lib/vector_mcp/session.rb', line 19 def server_info @server_info end |
#transport ⇒ Object (readonly)
Returns the value of attribute transport.
20 21 22 |
# File 'lib/vector_mcp/session.rb', line 20 def transport @transport end |
Instance Method Details
#initialize!(params) ⇒ Hash
Marks the session as initialized using parameters from the client’s ‘initialize` request.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/vector_mcp/session.rb', line 56 def initialize!(params) raise InitializationError, "Session already initialized or initialization attempt in progress." unless @initialized_state == :pending # TODO: More robust validation of params against MCP spec for initialize request params["protocolVersion"] client_capabilities_raw = params["capabilities"] client_info_raw = params["clientInfo"] # For now, we mostly care about clientInfo and capabilities for the session object. # Protocol version matching is more of a server/transport concern at a lower level if strict checks are needed. @client_info = client_info_raw.transform_keys(&:to_sym) if client_info_raw.is_a?(Hash) @client_capabilities = client_capabilities_raw.transform_keys(&:to_sym) if client_capabilities_raw.is_a?(Hash) @initialized_state = :succeeded @logger.info("[Session #{@id}] Initialized successfully. Client: #{@client_info&.dig(:name)}") { protocolVersion: @server.protocol_version, serverInfo: @server.server_info, capabilities: @server.server_capabilities } rescue StandardError => e @initialized_state = :failed @logger.error("[Session #{@id}] Initialization failed: #{e.}") # Re-raise as an InitializationError if it's not already one of our ProtocolErrors raise e if e.is_a?(ProtocolError) raise InitializationError, "Initialization processing error: #{e.}", details: { original_error: e.to_s } end |
#initialized? ⇒ Boolean
Checks if the session has been successfully initialized.
89 90 91 |
# File 'lib/vector_mcp/session.rb', line 89 def initialized? @initialized_state == :succeeded end |
#request_header(name) ⇒ String?
Convenience method to get a request header value.
150 151 152 |
# File 'lib/vector_mcp/session.rb', line 150 def request_header(name) @request_context.header(name) end |
#request_headers? ⇒ Boolean
Convenience method to check if the session has request headers.
135 136 137 |
# File 'lib/vector_mcp/session.rb', line 135 def request_headers? @request_context.headers? end |
#request_param(name) ⇒ String?
Convenience method to get a request parameter value.
158 159 160 |
# File 'lib/vector_mcp/session.rb', line 158 def request_param(name) @request_context.param(name) end |
#request_params? ⇒ Boolean
Convenience method to check if the session has request parameters.
142 143 144 |
# File 'lib/vector_mcp/session.rb', line 142 def request_params? @request_context.params? end |
#sample(request_params, timeout: nil) ⇒ VectorMCP::Sampling::Result
Initiates an MCP sampling request to the client associated with this session. This is a blocking call that waits for the client’s response.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/vector_mcp/session.rb', line 179 def sample(request_params, timeout: nil) validate_sampling_preconditions # Create middleware context for sampling context = VectorMCP::Middleware::Context.new( operation_type: :sampling, operation_name: "createMessage", params: request_params, session: self, server: @server, metadata: { start_time: Time.now, timeout: timeout } ) # Execute before_sampling_request hooks context = @server.middleware_manager.execute_hooks(:before_sampling_request, context) raise context.error if context.error? begin sampling_req_obj = VectorMCP::Sampling::Request.new(request_params) @logger.debug("[Session #{@id}] Sending sampling/createMessage request to client.") result = send_sampling_request(sampling_req_obj, timeout) # Set result in context context.result = result # Execute after_sampling_response hooks context = @server.middleware_manager.execute_hooks(:after_sampling_response, context) context.result rescue StandardError => e # Set error in context and execute error hooks context.error = e context = @server.middleware_manager.execute_hooks(:on_sampling_error, context) # Re-raise unless middleware handled the error raise e unless context.result context.result end end |
#update_request_context(**attributes) ⇒ RequestContext
Updates the request context with new data. This merges the provided attributes with the existing context.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/vector_mcp/session.rb', line 116 def update_request_context(**attributes) current_attrs = @request_context.to_h # Deep merge nested hashes like headers and params merged_attrs = current_attrs.dup attributes.each do |key, value| merged_attrs[key] = if value.is_a?(Hash) && current_attrs[key].is_a?(Hash) current_attrs[key].merge(value) else value end end @request_context = RequestContext.new(**merged_attrs) end |