Class: VectorMCP::Session

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

Constructor Details

#initialize(server, transport = nil, id: SecureRandom.uuid, request_context: nil) ⇒ Session

Initializes a new session.

Parameters:

  • server (VectorMCP::Server)

    The server instance managing this session.

  • transport (VectorMCP::Transport::Base, nil) (defaults to: nil)

    The transport handling this session. Required for sampling.

  • id (String) (defaults to: SecureRandom.uuid)

    A unique identifier for this session (e.g., from transport layer).

  • request_context (RequestContext, Hash, nil) (defaults to: nil)

    The request context for this session.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/vector_mcp/session.rb', line 30

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
  @created_at = Time.now
  @last_accessed_at = @created_at
  @metadata = {} # Transport-owned lifecycle/connection state
  @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_capabilitiesHash? (readonly)

Capabilities supported by the client, received during initialization.

Returns:

  • (Hash, nil)

    the current value of client_capabilities



19
20
21
# File 'lib/vector_mcp/session.rb', line 19

def client_capabilities
  @client_capabilities
end

#client_infoHash? (readonly)

Information about the client, received during initialization.

Returns:

  • (Hash, nil)

    the current value of client_info



19
20
21
# File 'lib/vector_mcp/session.rb', line 19

def client_info
  @client_info
end

#created_atObject (readonly)

Returns the value of attribute created_at.



20
21
22
# File 'lib/vector_mcp/session.rb', line 20

def created_at
  @created_at
end

#dataObject

For user-defined session-specific storage and resolved auth context



22
23
24
# File 'lib/vector_mcp/session.rb', line 22

def data
  @data
end

#idObject (readonly)

Returns the value of attribute id.



20
21
22
# File 'lib/vector_mcp/session.rb', line 20

def id
  @id
end

#last_accessed_atObject (readonly)

Returns the value of attribute last_accessed_at.



20
21
22
# File 'lib/vector_mcp/session.rb', line 20

def last_accessed_at
  @last_accessed_at
end

#metadataObject (readonly)

Returns the value of attribute metadata.



20
21
22
# File 'lib/vector_mcp/session.rb', line 20

def 
  @metadata
end

#protocol_versionString (readonly)

The MCP protocol version used by the server.

Returns:

  • (String)

    the current value of protocol_version



19
20
21
# File 'lib/vector_mcp/session.rb', line 19

def protocol_version
  @protocol_version
end

#request_contextRequestContext

The request context for this session.

Returns:



19
20
21
# File 'lib/vector_mcp/session.rb', line 19

def request_context
  @request_context
end

#security_contextObject

For user-defined session-specific storage and resolved auth context



22
23
24
# File 'lib/vector_mcp/session.rb', line 22

def security_context
  @security_context
end

#serverObject (readonly)

Returns the value of attribute server.



20
21
22
# File 'lib/vector_mcp/session.rb', line 20

def server
  @server
end

#server_capabilitiesHash (readonly)

Capabilities supported by the server.

Returns:

  • (Hash)

    the current value of server_capabilities



19
20
21
# File 'lib/vector_mcp/session.rb', line 19

def server_capabilities
  @server_capabilities
end

#server_infoHash (readonly)

Information about the server.

Returns:

  • (Hash)

    the current value of server_info



19
20
21
# File 'lib/vector_mcp/session.rb', line 19

def server_info
  @server_info
end

#transportObject (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

#ageFloat

Returns Seconds since the session was created.

Returns:

  • (Float)

    Seconds since the session was created.



112
113
114
# File 'lib/vector_mcp/session.rb', line 112

def age
  Time.now - @created_at
end

#expired?(timeout) ⇒ Boolean

Returns True when the session has been idle longer than the timeout.

Parameters:

  • timeout (Numeric)

    Idle timeout in seconds.

Returns:

  • (Boolean)

    True when the session has been idle longer than the timeout.



107
108
109
# File 'lib/vector_mcp/session.rb', line 107

def expired?(timeout)
  Time.now - @last_accessed_at > timeout
end

#initialize!(params) ⇒ Hash

Marks the session as initialized using parameters from the client's initialize request.

Parameters:

  • params (Hash)

    The parameters from the client's initialize request. Expected keys include "protocolVersion", "clientInfo", and "capabilities".

Returns:

  • (Hash)

    A hash suitable for the server's initialize response result.



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
85
86
87
88
# File 'lib/vector_mcp/session.rb', line 60

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.message}")
  # 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.message}", details: { original_error: e.to_s }
end

#initialized?Boolean

Checks if the session has been successfully initialized.

Returns:

  • (Boolean)

    True if the session is initialized, false otherwise.



93
94
95
# File 'lib/vector_mcp/session.rb', line 93

def initialized?
  @initialized_state == :succeeded
end

#request_header(name) ⇒ String?

Deprecated.

Will be removed in 0.7. Use the per-request invocation's Invocation#request_header instead.

Returns The header value or nil if not found.

Parameters:

  • name (String)

    The header name.

Returns:

  • (String, nil)

    The header value or nil if not found.



166
167
168
169
# File 'lib/vector_mcp/session.rb', line 166

def request_header(name)
  deprecated_request_api(:request_header)
  @request_context.header(name)
end

#request_headers?Boolean

Deprecated.

Will be removed in 0.7. Use the per-request invocation's Invocation#request_headers? instead.

Returns True if the request context has headers.

Returns:

  • (Boolean)

    True if the request context has headers.



149
150
151
152
# File 'lib/vector_mcp/session.rb', line 149

def request_headers?
  deprecated_request_api(:request_headers?)
  @request_context.headers?
end

#request_param(name) ⇒ String?

Deprecated.

Will be removed in 0.7. Use the per-request invocation's Invocation#request_param instead.

Returns The parameter value or nil if not found.

Parameters:

  • name (String)

    The parameter name.

Returns:

  • (String, nil)

    The parameter value or nil if not found.



175
176
177
178
# File 'lib/vector_mcp/session.rb', line 175

def request_param(name)
  deprecated_request_api(:request_param)
  @request_context.param(name)
end

#request_params?Boolean

Deprecated.

Will be removed in 0.7. Use the per-request invocation's Invocation#request_params? instead.

Returns True if the request context has parameters.

Returns:

  • (Boolean)

    True if the request context has parameters.



157
158
159
160
# File 'lib/vector_mcp/session.rb', line 157

def request_params?
  deprecated_request_api(: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.

Parameters:

  • request_params (Hash)

    Parameters for the sampling/createMessage request. See VectorMCP::Sampling::Request for expected structure (e.g., :messages, :max_tokens).

  • timeout (Numeric, nil) (defaults to: nil)

    Optional timeout in seconds for this specific request. Defaults to the transport's default request timeout.

Returns:

Raises:

  • (VectorMCP::SamplingError)

    if the sampling request fails, is rejected, or times out.

  • (StandardError)

    if the session's transport does not support send_request.



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/vector_mcp/session.rb', line 197

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

#touch!void

This method returns an undefined value.

Records activity on this session, deferring expiry.



101
102
103
# File 'lib/vector_mcp/session.rb', line 101

def touch!
  @last_accessed_at = Time.now
end

#update_request_context(**attributes) ⇒ RequestContext

Deprecated.

Will be removed in 0.7. Use the per-request invocation's Invocation#update_request_context instead.

Updates the request context with new data.

Parameters:

  • attributes (Hash)

    The attributes to merge into the request context.

Returns:



141
142
143
144
# File 'lib/vector_mcp/session.rb', line 141

def update_request_context(**attributes)
  deprecated_request_api(:update_request_context)
  @request_context = @request_context.merge(attributes)
end