vector_mcp 0.3.0 → 0.3.2

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,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VectorMCP
4
+ module Security
5
+ module Strategies
6
+ # Custom authentication strategy
7
+ # Allows developers to implement their own authentication logic
8
+ class Custom
9
+ attr_reader :handler
10
+
11
+ # Initialize with a custom authentication handler
12
+ # @param handler [Proc] a block that takes a request and returns user info or false
13
+ def initialize(&handler)
14
+ raise ArgumentError, "Custom authentication strategy requires a block" unless handler
15
+
16
+ @handler = handler
17
+ end
18
+
19
+ # Authenticate a request using the custom handler
20
+ # @param request [Hash] the request object
21
+ # @return [Object, false] result from custom handler or false if authentication failed
22
+ def authenticate(request)
23
+ result = @handler.call(request)
24
+
25
+ # Ensure result includes strategy info if it's successful
26
+ if result && result != false
27
+ format_successful_result(result)
28
+ else
29
+ false
30
+ end
31
+ rescue NoMemoryError, StandardError
32
+ # Log error but return false for security
33
+ false
34
+ end
35
+
36
+ # Check if handler is configured
37
+ # @return [Boolean] true if handler is present
38
+ def configured?
39
+ !@handler.nil?
40
+ end
41
+
42
+ private
43
+
44
+ # Format successful authentication result with strategy metadata
45
+ # @param result [Object] the result from the custom handler
46
+ # @return [Object] formatted result with strategy metadata
47
+ def format_successful_result(result)
48
+ case result
49
+ when Hash
50
+ # If result has a :user key, extract it and use as main user data
51
+ if result.key?(:user)
52
+ user_data = result[:user]
53
+ # For nil user, return a marker that will become nil in session context
54
+ return :authenticated_nil_user if user_data.nil?
55
+
56
+ user_data
57
+ else
58
+ result.merge(strategy: "custom", authenticated_at: Time.now)
59
+ end
60
+ else
61
+ {
62
+ user: result,
63
+ strategy: "custom",
64
+ authenticated_at: Time.now
65
+ }
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "jwt"
5
+ rescue LoadError
6
+ # JWT gem is optional - will raise error when trying to use JWT strategy
7
+ end
8
+
9
+ module VectorMCP
10
+ module Security
11
+ module Strategies
12
+ # JWT Token authentication strategy
13
+ # Provides stateless authentication using JSON Web Tokens
14
+ class JwtToken
15
+ attr_reader :secret, :algorithm, :options
16
+
17
+ # Initialize JWT strategy
18
+ # @param secret [String] the secret key for JWT verification
19
+ # @param algorithm [String] the JWT algorithm (default: HS256)
20
+ # @param options [Hash] additional JWT verification options
21
+ def initialize(secret:, algorithm: "HS256", **options)
22
+ raise LoadError, "JWT gem is required for JWT authentication strategy" unless defined?(JWT)
23
+
24
+ @secret = secret
25
+ @algorithm = algorithm
26
+ @options = {
27
+ algorithm: @algorithm,
28
+ verify_expiration: true,
29
+ verify_iat: true,
30
+ verify_iss: false,
31
+ verify_aud: false
32
+ }.merge(options)
33
+ end
34
+
35
+ # Authenticate a request using JWT token
36
+ # @param request [Hash] the request object
37
+ # @return [Hash, false] decoded JWT payload or false if authentication failed
38
+ def authenticate(request)
39
+ token = extract_token(request)
40
+ return false unless token
41
+
42
+ begin
43
+ decoded = JWT.decode(token, @secret, true, @options)
44
+ payload = decoded[0] # First element is the payload
45
+ headers = decoded[1] # Second element is the headers
46
+
47
+ # Return user info from JWT payload
48
+ {
49
+ **payload,
50
+ strategy: "jwt",
51
+ authenticated_at: Time.now,
52
+ jwt_headers: headers
53
+ }
54
+ rescue JWT::ExpiredSignature, JWT::InvalidIssuerError, JWT::InvalidAudienceError,
55
+ JWT::VerificationError, JWT::DecodeError, StandardError
56
+ false # Token validation failed
57
+ end
58
+ end
59
+
60
+ # Generate a JWT token (utility method for testing/development)
61
+ # @param payload [Hash] the payload to encode
62
+ # @param expires_in [Integer] expiration time in seconds from now
63
+ # @return [String] the generated JWT token
64
+ def generate_token(payload, expires_in: 3600)
65
+ exp_payload = payload.merge(
66
+ exp: Time.now.to_i + expires_in,
67
+ iat: Time.now.to_i
68
+ )
69
+ JWT.encode(exp_payload, @secret, @algorithm)
70
+ end
71
+
72
+ # Check if JWT gem is available
73
+ # @return [Boolean] true if JWT gem is loaded
74
+ def self.available?
75
+ defined?(JWT)
76
+ end
77
+
78
+ private
79
+
80
+ # Extract JWT token from request
81
+ # @param request [Hash] the request object
82
+ # @return [String, nil] the extracted token
83
+ def extract_token(request)
84
+ headers = request[:headers] || request["headers"] || {}
85
+ params = request[:params] || request["params"] || {}
86
+
87
+ extract_from_auth_header(headers) ||
88
+ extract_from_jwt_header(headers) ||
89
+ extract_from_params(params)
90
+ end
91
+
92
+ # Extract token from Authorization header
93
+ # @param headers [Hash] request headers
94
+ # @return [String, nil] the token if found
95
+ def extract_from_auth_header(headers)
96
+ auth_header = headers["Authorization"] || headers["authorization"]
97
+ return nil unless auth_header&.start_with?("Bearer ")
98
+
99
+ token = auth_header[7..] # Remove 'Bearer ' prefix
100
+ return nil if token.nil? || token.strip.empty?
101
+
102
+ token.strip
103
+ end
104
+
105
+ # Extract token from custom JWT header
106
+ # @param headers [Hash] request headers
107
+ # @return [String, nil] the token if found
108
+ def extract_from_jwt_header(headers)
109
+ headers["X-JWT-Token"] || headers["x-jwt-token"]
110
+ end
111
+
112
+ # Extract token from query parameters
113
+ # @param params [Hash] request parameters
114
+ # @return [String, nil] the token if found
115
+ def extract_from_params(params)
116
+ params["jwt_token"] || params["token"]
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Security namespace for VectorMCP
4
+ # Contains authentication, authorization, and security middleware components
5
+
6
+ require_relative "security/auth_manager"
7
+ require_relative "security/authorization"
8
+ require_relative "security/middleware"
9
+ require_relative "security/session_context"
10
+ require_relative "security/strategies/api_key"
11
+ require_relative "security/strategies/jwt_token"
12
+ require_relative "security/strategies/custom"
13
+
14
+ module VectorMCP
15
+ # Security components for VectorMCP servers
16
+ # Provides opt-in authentication and authorization
17
+ module Security
18
+ # Get default authentication manager
19
+ # @return [AuthManager] a new authentication manager instance
20
+ def self.auth_manager
21
+ AuthManager.new
22
+ end
23
+
24
+ # Get default authorization manager
25
+ # @return [Authorization] a new authorization manager instance
26
+ def self.authorization
27
+ Authorization.new
28
+ end
29
+
30
+ # Create security middleware with default components
31
+ # @param auth_manager [AuthManager] optional custom auth manager
32
+ # @param authorization [Authorization] optional custom authorization
33
+ # @return [Middleware] configured security middleware
34
+ def self.middleware(auth_manager: nil, authorization: nil)
35
+ auth_manager ||= self.auth_manager
36
+ authorization ||= self.authorization
37
+ Middleware.new(auth_manager, authorization)
38
+ end
39
+
40
+ # Check if JWT support is available
41
+ # @return [Boolean] true if JWT gem is loaded
42
+ def self.jwt_available?
43
+ Strategies::JwtToken.available?
44
+ end
45
+ end
46
+ end
@@ -12,6 +12,14 @@ require_relative "util" # Needed if not using Handlers::Core
12
12
  require_relative "server/registry"
13
13
  require_relative "server/capabilities"
14
14
  require_relative "server/message_handling"
15
+ require_relative "security/auth_manager"
16
+ require_relative "security/authorization"
17
+ require_relative "security/middleware"
18
+ require_relative "security/session_context"
19
+ require_relative "security/strategies/api_key"
20
+ require_relative "security/strategies/jwt_token"
21
+ require_relative "security/strategies/custom"
22
+ require_relative "middleware"
15
23
 
16
24
  module VectorMCP
17
25
  # The `Server` class is the central component for an MCP server implementation.
@@ -62,7 +70,8 @@ module VectorMCP
62
70
  # The specific version of the Model Context Protocol this server implements.
63
71
  PROTOCOL_VERSION = "2024-11-05"
64
72
 
65
- attr_reader :logger, :name, :version, :protocol_version, :tools, :resources, :prompts, :roots, :in_flight_requests
73
+ attr_reader :logger, :name, :version, :protocol_version, :tools, :resources, :prompts, :roots, :in_flight_requests,
74
+ :auth_manager, :authorization, :security_middleware, :middleware_manager
66
75
  attr_accessor :transport
67
76
 
68
77
  # Initializes a new VectorMCP server.
@@ -90,8 +99,8 @@ module VectorMCP
90
99
  @name = name_pos || name || "UnnamedServer"
91
100
  @version = version
92
101
  @protocol_version = options[:protocol_version] || PROTOCOL_VERSION
93
- @logger = VectorMCP.logger
94
- @logger.level = options[:log_level] if options[:log_level]
102
+ @logger = VectorMCP.logger_for("server")
103
+ # NOTE: log level should be configured via VectorMCP.configure_logging instead
95
104
 
96
105
  @transport = nil
97
106
  @tools = {}
@@ -108,6 +117,14 @@ module VectorMCP
108
117
  # Configure sampling capabilities
109
118
  @sampling_config = configure_sampling_capabilities(options[:sampling_config] || {})
110
119
 
120
+ # Initialize security components
121
+ @auth_manager = Security::AuthManager.new
122
+ @authorization = Security::Authorization.new
123
+ @security_middleware = Security::Middleware.new(@auth_manager, @authorization)
124
+
125
+ # Initialize middleware manager
126
+ @middleware_manager = Middleware::Manager.new
127
+
111
128
  setup_default_handlers
112
129
 
113
130
  @logger.info("Server instance '#{@name}' v#{@version} (MCP Protocol: #{@protocol_version}, Gem: v#{VectorMCP::VERSION}) initialized.")
@@ -120,7 +137,7 @@ module VectorMCP
120
137
  # @param transport [:stdio, :sse, VectorMCP::Transport::Base] The transport to use.
121
138
  # Can be a symbol (`:stdio`, `:sse`) or an initialized transport instance.
122
139
  # If a symbol is provided, the method will instantiate the corresponding transport class.
123
- # If `:sse` is chosen, ensure `async` and `falcon` gems are available.
140
+ # If `:sse` is chosen, it uses Puma as the HTTP server.
124
141
  # @param options [Hash] Transport-specific options (e.g., `:host`, `:port` for SSE).
125
142
  # These are passed to the transport's constructor if a symbol is provided for `transport`.
126
143
  # @return [void]
@@ -135,7 +152,7 @@ module VectorMCP
135
152
  require_relative "transport/sse"
136
153
  VectorMCP::Transport::SSE.new(self, **options)
137
154
  rescue LoadError => e
138
- logger.fatal("SSE transport requires additional dependencies. Install the 'async' and 'falcon' gems.")
155
+ logger.fatal("SSE transport requires additional dependencies.")
139
156
  raise NotImplementedError, "SSE transport dependencies not available: #{e.message}"
140
157
  end
141
158
  when VectorMCP::Transport::Base # Allow passing an initialized transport instance
@@ -148,6 +165,173 @@ module VectorMCP
148
165
  self.transport = active_transport
149
166
  active_transport.run
150
167
  end
168
+
169
+ # --- Security Configuration ---
170
+
171
+ # Enable authentication with specified strategy and configuration
172
+ # @param strategy [Symbol] the authentication strategy (:api_key, :jwt, :custom)
173
+ # @param options [Hash] strategy-specific configuration options
174
+ # @return [void]
175
+ def enable_authentication!(strategy: :api_key, **options, &block)
176
+ # Clear existing strategies when switching to a new configuration
177
+ clear_auth_strategies unless @auth_manager.strategies.empty?
178
+
179
+ @auth_manager.enable!(default_strategy: strategy)
180
+
181
+ case strategy
182
+ when :api_key
183
+ add_api_key_auth(options[:keys] || [])
184
+ when :jwt
185
+ add_jwt_auth(options)
186
+ when :custom
187
+ handler = block || options[:handler]
188
+ raise ArgumentError, "Custom authentication strategy requires a handler block" unless handler
189
+
190
+ add_custom_auth(&handler)
191
+
192
+ else
193
+ raise ArgumentError, "Unknown authentication strategy: #{strategy}"
194
+ end
195
+
196
+ @logger.info("Authentication enabled with strategy: #{strategy}")
197
+ end
198
+
199
+ # Disable authentication (return to pass-through mode)
200
+ # @return [void]
201
+ def disable_authentication!
202
+ @auth_manager.disable!
203
+ @logger.info("Authentication disabled")
204
+ end
205
+
206
+ # Enable authorization with optional policy configuration block
207
+ # @param block [Proc] optional block for configuring authorization policies
208
+ # @return [void]
209
+ def enable_authorization!(&block)
210
+ @authorization.enable!
211
+ instance_eval(&block) if block_given?
212
+ @logger.info("Authorization enabled")
213
+ end
214
+
215
+ # Disable authorization (return to pass-through mode)
216
+ # @return [void]
217
+ def disable_authorization!
218
+ @authorization.disable!
219
+ @logger.info("Authorization disabled")
220
+ end
221
+
222
+ # Add authorization policy for tools
223
+ # @param block [Proc] policy block that receives (user, action, tool)
224
+ # @return [void]
225
+ def authorize_tools(&block)
226
+ @authorization.add_policy(:tool, &block)
227
+ end
228
+
229
+ # Add authorization policy for resources
230
+ # @param block [Proc] policy block that receives (user, action, resource)
231
+ # @return [void]
232
+ def authorize_resources(&block)
233
+ @authorization.add_policy(:resource, &block)
234
+ end
235
+
236
+ # Add authorization policy for prompts
237
+ # @param block [Proc] policy block that receives (user, action, prompt)
238
+ # @return [void]
239
+ def authorize_prompts(&block)
240
+ @authorization.add_policy(:prompt, &block)
241
+ end
242
+
243
+ # Add authorization policy for roots
244
+ # @param block [Proc] policy block that receives (user, action, root)
245
+ # @return [void]
246
+ def authorize_roots(&block)
247
+ @authorization.add_policy(:root, &block)
248
+ end
249
+
250
+ # Check if security features are enabled
251
+ # @return [Boolean] true if authentication or authorization is enabled
252
+ def security_enabled?
253
+ @security_middleware.security_enabled?
254
+ end
255
+
256
+ # Get current security status for debugging/monitoring
257
+ # @return [Hash] security configuration status
258
+ def security_status
259
+ @security_middleware.security_status
260
+ end
261
+
262
+ # --- Middleware Management ---
263
+
264
+ # Register middleware for specific hook types
265
+ # @param middleware_class [Class] Middleware class inheriting from VectorMCP::Middleware::Base
266
+ # @param hooks [Symbol, Array<Symbol>] Hook types to register for (e.g., :before_tool_call, [:before_tool_call, :after_tool_call])
267
+ # @param priority [Integer] Execution priority (lower numbers execute first, default: 100)
268
+ # @param conditions [Hash] Conditions for when middleware should run
269
+ # @option conditions [Array<String>] :only_operations Only run for these operations
270
+ # @option conditions [Array<String>] :except_operations Don't run for these operations
271
+ # @option conditions [Array<String>] :only_users Only run for these user IDs
272
+ # @option conditions [Array<String>] :except_users Don't run for these user IDs
273
+ # @option conditions [Boolean] :critical If true, errors in this middleware stop execution
274
+ # @example
275
+ # server.use_middleware(MyMiddleware, :before_tool_call)
276
+ # server.use_middleware(AuthMiddleware, [:before_request, :after_response], priority: 10)
277
+ # server.use_middleware(LoggingMiddleware, :after_tool_call, conditions: { only_operations: ['important_tool'] })
278
+ def use_middleware(middleware_class, hooks, priority: Middleware::Hook::DEFAULT_PRIORITY, conditions: {})
279
+ @middleware_manager.register(middleware_class, hooks, priority: priority, conditions: conditions)
280
+ @logger.info("Registered middleware: #{middleware_class.name}")
281
+ end
282
+
283
+ # Remove all middleware hooks for a specific class
284
+ # @param middleware_class [Class] Middleware class to remove
285
+ def remove_middleware(middleware_class)
286
+ @middleware_manager.unregister(middleware_class)
287
+ @logger.info("Removed middleware: #{middleware_class.name}")
288
+ end
289
+
290
+ # Get middleware statistics
291
+ # @return [Hash] Statistics about registered middleware
292
+ def middleware_stats
293
+ @middleware_manager.stats
294
+ end
295
+
296
+ # Clear all middleware (useful for testing)
297
+ def clear_middleware!
298
+ @middleware_manager.clear!
299
+ @logger.info("Cleared all middleware")
300
+ end
301
+
302
+ private
303
+
304
+ # Add API key authentication strategy
305
+ # @param keys [Array<String>] array of valid API keys
306
+ # @return [void]
307
+ def add_api_key_auth(keys)
308
+ strategy = Security::Strategies::ApiKey.new(keys: keys)
309
+ @auth_manager.add_strategy(:api_key, strategy)
310
+ end
311
+
312
+ # Add JWT authentication strategy
313
+ # @param options [Hash] JWT configuration options
314
+ # @return [void]
315
+ def add_jwt_auth(options)
316
+ strategy = Security::Strategies::JwtToken.new(**options)
317
+ @auth_manager.add_strategy(:jwt, strategy)
318
+ end
319
+
320
+ # Add custom authentication strategy
321
+ # @param handler [Proc] custom authentication handler block
322
+ # @return [void]
323
+ def add_custom_auth(&block)
324
+ strategy = Security::Strategies::Custom.new(&block)
325
+ @auth_manager.add_strategy(:custom, strategy)
326
+ end
327
+
328
+ # Clear all authentication strategies
329
+ # @return [void]
330
+ def clear_auth_strategies
331
+ @auth_manager.strategies.each_key do |strategy_name|
332
+ @auth_manager.remove_strategy(strategy_name)
333
+ end
334
+ end
151
335
  end
152
336
 
153
337
  module Transport
@@ -95,10 +95,43 @@ module VectorMCP
95
95
  def sample(request_params, timeout: nil)
96
96
  validate_sampling_preconditions
97
97
 
98
- sampling_req_obj = VectorMCP::Sampling::Request.new(request_params)
99
- @logger.info("[Session #{@id}] Sending sampling/createMessage request to client.")
100
-
101
- send_sampling_request(sampling_req_obj, timeout)
98
+ # Create middleware context for sampling
99
+ context = VectorMCP::Middleware::Context.new(
100
+ operation_type: :sampling,
101
+ operation_name: "createMessage",
102
+ params: request_params,
103
+ session: self,
104
+ server: @server,
105
+ metadata: { start_time: Time.now, timeout: timeout }
106
+ )
107
+
108
+ # Execute before_sampling_request hooks
109
+ context = @server.middleware_manager.execute_hooks(:before_sampling_request, context)
110
+ raise context.error if context.error?
111
+
112
+ begin
113
+ sampling_req_obj = VectorMCP::Sampling::Request.new(request_params)
114
+ @logger.info("[Session #{@id}] Sending sampling/createMessage request to client.")
115
+
116
+ result = send_sampling_request(sampling_req_obj, timeout)
117
+
118
+ # Set result in context
119
+ context.result = result
120
+
121
+ # Execute after_sampling_response hooks
122
+ context = @server.middleware_manager.execute_hooks(:after_sampling_response, context)
123
+
124
+ context.result
125
+ rescue StandardError => e
126
+ # Set error in context and execute error hooks
127
+ context.error = e
128
+ context = @server.middleware_manager.execute_hooks(:on_sampling_error, context)
129
+
130
+ # Re-raise unless middleware handled the error
131
+ raise e unless context.result
132
+
133
+ context.result
134
+ end
102
135
  end
103
136
 
104
137
  private
@@ -2,5 +2,5 @@
2
2
 
3
3
  module VectorMCP
4
4
  # The current version of the VectorMCP gem.
5
- VERSION = "0.3.0"
5
+ VERSION = "0.3.2"
6
6
  end
data/lib/vector_mcp.rb CHANGED
@@ -11,14 +11,16 @@ require_relative "vector_mcp/util"
11
11
  require_relative "vector_mcp/image_util"
12
12
  require_relative "vector_mcp/handlers/core"
13
13
  require_relative "vector_mcp/transport/stdio"
14
- # require_relative "vector_mcp/transport/sse" # Load on demand to avoid async dependencies
14
+ # require_relative "vector_mcp/transport/sse" # Load on demand
15
+ require_relative "vector_mcp/logger"
16
+ require_relative "vector_mcp/middleware"
15
17
  require_relative "vector_mcp/server"
16
18
 
17
19
  # The VectorMCP module provides a full-featured, opinionated Ruby implementation
18
20
  # of the **Model Context Protocol (MCP)**. It gives developers everything needed
19
21
  # to spin up an MCP-compatible server—including:
20
22
  #
21
- # * **Transport adapters** (synchronous `stdio` or asynchronous HTTP + SSE)
23
+ # * **Transport adapters** (synchronous `stdio` or HTTP + SSE)
22
24
  # * **High-level abstractions** for *tools*, *resources*, and *prompts*
23
25
  # * **JSON-RPC 2.0** message handling with sensible defaults and detailed
24
26
  # error reporting helpers
@@ -44,13 +46,19 @@ require_relative "vector_mcp/server"
44
46
  # order to serve multiple concurrent clients over HTTP.
45
47
  #
46
48
  module VectorMCP
47
- # @return [Logger] the shared logger instance for the library.
48
- @logger = Logger.new($stderr, level: Logger::INFO, progname: "VectorMCP")
49
-
50
49
  class << self
51
- # @!attribute [r] logger
52
- # @return [Logger] the shared logger instance for the library.
53
- attr_reader :logger
50
+ # Get a component-specific logger
51
+ # @param component [String, Symbol] the component name
52
+ # @return [VectorMCP::Logger] component logger
53
+ def logger_for(component)
54
+ Logger.for(component)
55
+ end
56
+
57
+ # Get the default logger
58
+ # @return [VectorMCP::Logger] default logger
59
+ def logger
60
+ @logger ||= Logger.for("vectormcp")
61
+ end
54
62
 
55
63
  # Creates a new {VectorMCP::Server} instance. This is a **thin wrapper** around
56
64
  # `VectorMCP::Server.new`; it exists purely for syntactic sugar so you can write
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.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergio Bayona
@@ -65,6 +65,20 @@ dependencies:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
67
  version: '3.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: jwt
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '2.7'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '2.7'
68
82
  - !ruby/object:Gem::Dependency
69
83
  name: puma
70
84
  requirement: !ruby/object:Gem::Requirement
@@ -79,8 +93,24 @@ dependencies:
79
93
  - - "~>"
80
94
  - !ruby/object:Gem::Version
81
95
  version: '6.4'
82
- description: Server-side tools for implementing the Model Context Protocol in Ruby
83
- applications
96
+ - !ruby/object:Gem::Dependency
97
+ name: rack
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.0'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '3.0'
110
+ description: A Ruby gem implementing the Model Context Protocol (MCP) server-side
111
+ specification. Provides a framework for creating MCP servers that expose tools,
112
+ resources, prompts, and roots to LLM clients with comprehensive security features,
113
+ structured logging, and production-ready capabilities.
84
114
  email:
85
115
  - bayona.sergio@gmail.com
86
116
  executables:
@@ -89,6 +119,7 @@ executables:
89
119
  extensions: []
90
120
  extra_rdoc_files: []
91
121
  files:
122
+ - CHANGELOG.md
92
123
  - LICENSE.txt
93
124
  - README.md
94
125
  - bin/console
@@ -98,8 +129,22 @@ files:
98
129
  - lib/vector_mcp/errors.rb
99
130
  - lib/vector_mcp/handlers/core.rb
100
131
  - lib/vector_mcp/image_util.rb
132
+ - lib/vector_mcp/logger.rb
133
+ - lib/vector_mcp/middleware.rb
134
+ - lib/vector_mcp/middleware/base.rb
135
+ - lib/vector_mcp/middleware/context.rb
136
+ - lib/vector_mcp/middleware/hook.rb
137
+ - lib/vector_mcp/middleware/manager.rb
101
138
  - lib/vector_mcp/sampling/request.rb
102
139
  - lib/vector_mcp/sampling/result.rb
140
+ - lib/vector_mcp/security.rb
141
+ - lib/vector_mcp/security/auth_manager.rb
142
+ - lib/vector_mcp/security/authorization.rb
143
+ - lib/vector_mcp/security/middleware.rb
144
+ - lib/vector_mcp/security/session_context.rb
145
+ - lib/vector_mcp/security/strategies/api_key.rb
146
+ - lib/vector_mcp/security/strategies/custom.rb
147
+ - lib/vector_mcp/security/strategies/jwt_token.rb
103
148
  - lib/vector_mcp/server.rb
104
149
  - lib/vector_mcp/server/capabilities.rb
105
150
  - lib/vector_mcp/server/message_handling.rb
@@ -128,7 +173,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
128
173
  requirements:
129
174
  - - ">="
130
175
  - !ruby/object:Gem::Version
131
- version: 3.1.0
176
+ version: 3.0.6
132
177
  required_rubygems_version: !ruby/object:Gem::Requirement
133
178
  requirements:
134
179
  - - ">="