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.
-
#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.
-
#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.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/vector_mcp/session.rb', line 28 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 @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.
18 19 20 |
# File 'lib/vector_mcp/session.rb', line 18 def client_capabilities @client_capabilities end |
#client_info ⇒ Hash? (readonly)
Information about the client, received during initialization.
18 19 20 |
# File 'lib/vector_mcp/session.rb', line 18 def client_info @client_info end |
#data ⇒ Object
For user-defined session-specific storage
20 21 22 |
# File 'lib/vector_mcp/session.rb', line 20 def data @data end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
19 20 21 |
# File 'lib/vector_mcp/session.rb', line 19 def id @id end |
#protocol_version ⇒ String (readonly)
The MCP protocol version used by the server.
18 19 20 |
# File 'lib/vector_mcp/session.rb', line 18 def protocol_version @protocol_version end |
#request_context ⇒ RequestContext
The request context for this session.
18 19 20 |
# File 'lib/vector_mcp/session.rb', line 18 def request_context @request_context end |
#server ⇒ Object (readonly)
Returns the value of attribute server.
19 20 21 |
# File 'lib/vector_mcp/session.rb', line 19 def server @server end |
#server_capabilities ⇒ Hash (readonly)
Capabilities supported by the server.
18 19 20 |
# File 'lib/vector_mcp/session.rb', line 18 def server_capabilities @server_capabilities end |
#server_info ⇒ Hash (readonly)
Information about the server.
18 19 20 |
# File 'lib/vector_mcp/session.rb', line 18 def server_info @server_info end |
#transport ⇒ Object (readonly)
Returns the value of attribute transport.
19 20 21 |
# File 'lib/vector_mcp/session.rb', line 19 def transport @transport end |
Instance Method Details
#initialize!(params) ⇒ Hash
Marks the session as initialized using parameters from the client’s ‘initialize` request.
54 55 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 |
# File 'lib/vector_mcp/session.rb', line 54 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.
87 88 89 |
# File 'lib/vector_mcp/session.rb', line 87 def initialized? @initialized_state == :succeeded end |
#request_header(name) ⇒ String?
Convenience method to get a request header value.
148 149 150 |
# File 'lib/vector_mcp/session.rb', line 148 def request_header(name) @request_context.header(name) end |
#request_headers? ⇒ Boolean
Convenience method to check if the session has request headers.
133 134 135 |
# File 'lib/vector_mcp/session.rb', line 133 def request_headers? @request_context.headers? end |
#request_param(name) ⇒ String?
Convenience method to get a request parameter value.
156 157 158 |
# File 'lib/vector_mcp/session.rb', line 156 def request_param(name) @request_context.param(name) end |
#request_params? ⇒ Boolean
Convenience method to check if the session has request parameters.
140 141 142 |
# File 'lib/vector_mcp/session.rb', line 140 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.
177 178 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 |
# File 'lib/vector_mcp/session.rb', line 177 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.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/vector_mcp/session.rb', line 114 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 |