vector_mcp 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_session_manager"
4
+
5
+ module VectorMCP
6
+ module Transport
7
+ # Session manager for Stdio transport with single global session.
8
+ # Extends BaseSessionManager with stdio-specific functionality.
9
+ #
10
+ # The Stdio transport uses a single global session for the entire transport lifetime.
11
+ class StdioSessionManager < BaseSessionManager
12
+ GLOBAL_SESSION_ID = "stdio_global_session"
13
+
14
+ # Initializes a new Stdio session manager.
15
+ #
16
+ # @param transport [Stdio] The parent transport instance
17
+ # @param session_timeout [Integer] Session timeout in seconds (ignored for stdio)
18
+ def initialize(transport, session_timeout = 300)
19
+ super
20
+
21
+ # Create the single global session for stdio transport
22
+ @global_session = create_global_session
23
+ end
24
+
25
+ # Gets the global session for stdio transport.
26
+ # Stdio uses a single global session for the entire transport lifetime.
27
+ #
28
+ # @return [Session] The global session
29
+ def global_session
30
+ @global_session&.touch!
31
+ @global_session
32
+ end
33
+
34
+ # Gets or creates the global session for stdio transport.
35
+ # This is an alias for global_session for stdio transport.
36
+ #
37
+ # @return [Session] The global session
38
+ def global_session_or_create
39
+ global_session
40
+ end
41
+
42
+ # Override: Gets session by ID, but always returns the global session for stdio.
43
+ #
44
+ # @param session_id [String] The session ID (ignored for stdio)
45
+ # @return [Session] The global session
46
+ def session(_session_id = nil)
47
+ global_session
48
+ end
49
+
50
+ # Override: Always returns the global session for stdio.
51
+ #
52
+ # @param session_id [String, nil] The session ID (ignored)
53
+ # @return [Session] The global session
54
+ def session_or_create(_session_id = nil)
55
+ global_session
56
+ end
57
+
58
+ # Override: Cannot create additional sessions in stdio transport.
59
+ #
60
+ # @param session_id [String, nil] The session ID (ignored)
61
+ # @return [Session] The global session
62
+ def create_session(_session_id = nil)
63
+ # For stdio, always return the existing global session
64
+ global_session
65
+ end
66
+
67
+ # Override: Cannot terminate the global session while transport is running.
68
+ #
69
+ # @param session_id [String] The session ID (ignored)
70
+ # @return [Boolean] Always false (session cannot be terminated individually)
71
+ def session_terminated?(_session_id)
72
+ # For stdio, the session is only terminated when the transport shuts down
73
+ false
74
+ end
75
+
76
+ # Override: Always returns 1 for the single global session.
77
+ #
78
+ # @return [Integer] Always 1
79
+ def session_count
80
+ 1
81
+ end
82
+
83
+ # Override: Always returns the global session ID.
84
+ #
85
+ # @return [Array<String>] Array containing the global session ID
86
+ def active_session_ids
87
+ [GLOBAL_SESSION_ID]
88
+ end
89
+
90
+ # Override: Always returns true for the single session.
91
+ #
92
+ # @return [Boolean] Always true
93
+ def sessions?
94
+ true
95
+ end
96
+
97
+ # Gets all sessions for stdio transport (just the one global session).
98
+ #
99
+ # @return [Array<Session>] Array containing the global session
100
+ def all_sessions
101
+ [@global_session].compact
102
+ end
103
+
104
+ # Alias for global_session for compatibility with tests.
105
+ #
106
+ # @return [Session] The global session
107
+ def current_global_session
108
+ global_session
109
+ end
110
+
111
+ # Alias for global_session_or_create for compatibility with tests.
112
+ #
113
+ # @return [Session] The global session
114
+ def global_session_or_create_current
115
+ global_session_or_create
116
+ end
117
+
118
+ # Alias for all_sessions for compatibility with tests.
119
+ #
120
+ # @return [Array<Session>] Array containing the global session
121
+ def current_all_sessions
122
+ all_sessions
123
+ end
124
+
125
+ protected
126
+
127
+ # Override: Stdio doesn't need automatic cleanup since it has a single persistent session.
128
+ def auto_cleanup_enabled?
129
+ false
130
+ end
131
+
132
+ # Override: Returns metadata for stdio sessions.
133
+ def create_session_metadata
134
+ { session_type: :stdio_global, created_via: :transport_startup }
135
+ end
136
+
137
+ # Override: Stdio can always send messages (single session assumption).
138
+ def can_send_message_to_session?(_session)
139
+ true
140
+ end
141
+
142
+ # Override: Sends messages via the transport's notification mechanism.
143
+ def message_sent_to_session?(_session, message)
144
+ # For stdio, we send notifications directly via the transport
145
+ @transport.send_notification(message["method"], message["params"])
146
+ true
147
+ end
148
+
149
+ # Override: Stdio broadcasts to the single session (same as regular send).
150
+ def broadcast_message(message)
151
+ message_sent_to_session?(@global_session, message) ? 1 : 0
152
+ end
153
+
154
+ private
155
+
156
+ # Creates the single global session for stdio transport.
157
+ #
158
+ # @return [BaseSessionManager::Session] The global session
159
+ def create_global_session
160
+ now = Time.now
161
+
162
+ # Create VectorMCP session context with minimal request context
163
+ request_context = VectorMCP::RequestContext.minimal("stdio")
164
+ session_context = VectorMCP::Session.new(@transport.server, @transport, id: GLOBAL_SESSION_ID, request_context: request_context)
165
+
166
+ # Create internal session record using base session manager struct
167
+ session = BaseSessionManager::Session.new(
168
+ GLOBAL_SESSION_ID,
169
+ session_context,
170
+ now,
171
+ now,
172
+ create_session_metadata
173
+ )
174
+
175
+ @sessions[GLOBAL_SESSION_ID] = session
176
+ logger.info { "Global stdio session created: #{GLOBAL_SESSION_ID}" }
177
+ session
178
+ end
179
+ end
180
+ end
181
+ end
@@ -231,8 +231,46 @@ module VectorMCP
231
231
  content
232
232
  end
233
233
 
234
+ # Extracts HTTP headers from a Rack environment hash.
235
+ # Converts Rack's HTTP_* environment variables to proper HTTP header names.
236
+ # @param env [Hash] The Rack environment hash.
237
+ # @return [Hash] Normalized headers with proper casing.
238
+ def extract_headers_from_rack_env(env)
239
+ headers = {}
240
+ return headers if env.nil?
241
+
242
+ env.each do |key, value|
243
+ next unless key.start_with?("HTTP_")
244
+
245
+ # Convert HTTP_X_API_KEY to X-API-Key format
246
+ header_name = key[5..].split("_").map do |part|
247
+ case part.upcase
248
+ when "API" then "API" # Keep API in all caps
249
+ else part.capitalize
250
+ end
251
+ end.join("-")
252
+ headers[header_name] = value
253
+ end
254
+
255
+ # Add special headers
256
+ headers["Authorization"] = env["HTTP_AUTHORIZATION"] if env["HTTP_AUTHORIZATION"]
257
+ headers["Content-Type"] = env["CONTENT_TYPE"] if env["CONTENT_TYPE"]
258
+ headers
259
+ end
260
+
261
+ # Extracts query parameters from a Rack environment hash.
262
+ # Parses the QUERY_STRING into a hash of parameters.
263
+ # @param env [Hash] The Rack environment hash.
264
+ # @return [Hash] Normalized parameters as key-value pairs.
265
+ def extract_params_from_rack_env(env)
266
+ params = {}
267
+ params = URI.decode_www_form(env["QUERY_STRING"]).to_h if env && env["QUERY_STRING"]
268
+ params
269
+ end
270
+
234
271
  module_function :looks_like_image_file_path?, :binary_image_data?,
235
272
  :file_path_to_image_content, :binary_image_to_content,
236
- :validate_and_enhance_image_content
273
+ :validate_and_enhance_image_content, :extract_headers_from_rack_env,
274
+ :extract_params_from_rack_env
237
275
  end
238
276
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module VectorMCP
4
4
  # The current version of the VectorMCP gem.
5
- VERSION = "0.3.2"
5
+ VERSION = "0.3.3"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vector_mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergio Bayona
@@ -135,6 +135,7 @@ files:
135
135
  - lib/vector_mcp/middleware/context.rb
136
136
  - lib/vector_mcp/middleware/hook.rb
137
137
  - lib/vector_mcp/middleware/manager.rb
138
+ - lib/vector_mcp/request_context.rb
138
139
  - lib/vector_mcp/sampling/request.rb
139
140
  - lib/vector_mcp/sampling/result.rb
140
141
  - lib/vector_mcp/security.rb
@@ -150,12 +151,19 @@ files:
150
151
  - lib/vector_mcp/server/message_handling.rb
151
152
  - lib/vector_mcp/server/registry.rb
152
153
  - lib/vector_mcp/session.rb
154
+ - lib/vector_mcp/transport/base_session_manager.rb
155
+ - lib/vector_mcp/transport/http_stream.rb
156
+ - lib/vector_mcp/transport/http_stream/event_store.rb
157
+ - lib/vector_mcp/transport/http_stream/session_manager.rb
158
+ - lib/vector_mcp/transport/http_stream/stream_handler.rb
153
159
  - lib/vector_mcp/transport/sse.rb
154
160
  - lib/vector_mcp/transport/sse/client_connection.rb
155
161
  - lib/vector_mcp/transport/sse/message_handler.rb
156
162
  - lib/vector_mcp/transport/sse/puma_config.rb
157
163
  - lib/vector_mcp/transport/sse/stream_manager.rb
164
+ - lib/vector_mcp/transport/sse_session_manager.rb
158
165
  - lib/vector_mcp/transport/stdio.rb
166
+ - lib/vector_mcp/transport/stdio_session_manager.rb
159
167
  - lib/vector_mcp/util.rb
160
168
  - lib/vector_mcp/version.rb
161
169
  homepage: https://github.com/sergiobayona/vector_mcp