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 (readonly)

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

#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.



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/vector_mcp/session.rb', line 139

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