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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +54 -0
- data/lib/vector_mcp/definitions.rb +25 -9
- data/lib/vector_mcp/errors.rb +2 -6
- data/lib/vector_mcp/handlers/core.rb +12 -10
- data/lib/vector_mcp/middleware/base.rb +1 -7
- data/lib/vector_mcp/middleware/manager.rb +3 -15
- data/lib/vector_mcp/request_context.rb +182 -0
- data/lib/vector_mcp/sampling/result.rb +11 -1
- data/lib/vector_mcp/security/middleware.rb +2 -28
- data/lib/vector_mcp/security/strategies/api_key.rb +2 -24
- data/lib/vector_mcp/server/capabilities.rb +5 -7
- data/lib/vector_mcp/server/message_handling.rb +11 -5
- data/lib/vector_mcp/server.rb +17 -7
- data/lib/vector_mcp/session.rb +96 -6
- data/lib/vector_mcp/transport/base_session_manager.rb +320 -0
- data/lib/vector_mcp/transport/http_stream/event_store.rb +151 -0
- data/lib/vector_mcp/transport/http_stream/session_manager.rb +189 -0
- data/lib/vector_mcp/transport/http_stream/stream_handler.rb +269 -0
- data/lib/vector_mcp/transport/http_stream.rb +779 -0
- data/lib/vector_mcp/transport/sse.rb +74 -19
- data/lib/vector_mcp/transport/sse_session_manager.rb +188 -0
- data/lib/vector_mcp/transport/stdio.rb +70 -13
- data/lib/vector_mcp/transport/stdio_session_manager.rb +181 -0
- data/lib/vector_mcp/util.rb +39 -1
- data/lib/vector_mcp/version.rb +1 -1
- metadata +9 -1
@@ -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
|
data/lib/vector_mcp/util.rb
CHANGED
@@ -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
|
data/lib/vector_mcp/version.rb
CHANGED
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.
|
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
|