vector_mcp 0.3.1 → 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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +122 -0
  3. data/lib/vector_mcp/definitions.rb +25 -9
  4. data/lib/vector_mcp/errors.rb +2 -3
  5. data/lib/vector_mcp/handlers/core.rb +206 -50
  6. data/lib/vector_mcp/logger.rb +148 -0
  7. data/lib/vector_mcp/middleware/base.rb +171 -0
  8. data/lib/vector_mcp/middleware/context.rb +76 -0
  9. data/lib/vector_mcp/middleware/hook.rb +169 -0
  10. data/lib/vector_mcp/middleware/manager.rb +179 -0
  11. data/lib/vector_mcp/middleware.rb +43 -0
  12. data/lib/vector_mcp/request_context.rb +182 -0
  13. data/lib/vector_mcp/sampling/result.rb +11 -1
  14. data/lib/vector_mcp/security/middleware.rb +2 -28
  15. data/lib/vector_mcp/security/strategies/api_key.rb +2 -24
  16. data/lib/vector_mcp/security/strategies/jwt_token.rb +6 -3
  17. data/lib/vector_mcp/server/capabilities.rb +5 -7
  18. data/lib/vector_mcp/server/message_handling.rb +11 -5
  19. data/lib/vector_mcp/server.rb +74 -20
  20. data/lib/vector_mcp/session.rb +131 -8
  21. data/lib/vector_mcp/transport/base_session_manager.rb +320 -0
  22. data/lib/vector_mcp/transport/http_stream/event_store.rb +151 -0
  23. data/lib/vector_mcp/transport/http_stream/session_manager.rb +189 -0
  24. data/lib/vector_mcp/transport/http_stream/stream_handler.rb +269 -0
  25. data/lib/vector_mcp/transport/http_stream.rb +779 -0
  26. data/lib/vector_mcp/transport/sse.rb +74 -19
  27. data/lib/vector_mcp/transport/sse_session_manager.rb +188 -0
  28. data/lib/vector_mcp/transport/stdio.rb +70 -13
  29. data/lib/vector_mcp/transport/stdio_session_manager.rb +181 -0
  30. data/lib/vector_mcp/util.rb +39 -1
  31. data/lib/vector_mcp/version.rb +1 -1
  32. data/lib/vector_mcp.rb +10 -35
  33. metadata +25 -24
  34. data/lib/vector_mcp/logging/component.rb +0 -131
  35. data/lib/vector_mcp/logging/configuration.rb +0 -156
  36. data/lib/vector_mcp/logging/constants.rb +0 -21
  37. data/lib/vector_mcp/logging/core.rb +0 -175
  38. data/lib/vector_mcp/logging/filters/component.rb +0 -69
  39. data/lib/vector_mcp/logging/filters/level.rb +0 -23
  40. data/lib/vector_mcp/logging/formatters/base.rb +0 -52
  41. data/lib/vector_mcp/logging/formatters/json.rb +0 -83
  42. data/lib/vector_mcp/logging/formatters/text.rb +0 -72
  43. data/lib/vector_mcp/logging/outputs/base.rb +0 -64
  44. data/lib/vector_mcp/logging/outputs/console.rb +0 -35
  45. data/lib/vector_mcp/logging/outputs/file.rb +0 -157
  46. data/lib/vector_mcp/logging.rb +0 -71
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VectorMCP
4
+ module Middleware
5
+ # Base class for all middleware implementations
6
+ # Provides common functionality and hook method templates
7
+ class Base
8
+ # Initialize middleware with optional configuration
9
+ # @param config [Hash] Configuration options
10
+ def initialize(config = {})
11
+ @config = config
12
+ @logger = VectorMCP.logger_for("middleware.#{self.class.name.split("::").last.downcase}")
13
+ end
14
+
15
+ # Generic hook dispatcher - override specific hook methods instead
16
+ # @param hook_type [String] Type of hook being executed
17
+ # @param context [VectorMCP::Middleware::Context] Execution context
18
+ def call(hook_type, context)
19
+ # Generic middleware hook execution
20
+ end
21
+
22
+ # Tool operation hooks
23
+
24
+ # Called before tool execution
25
+ # @param context [VectorMCP::Middleware::Context] Execution context
26
+ def before_tool_call(context)
27
+ # Override in subclasses
28
+ end
29
+
30
+ # Called after successful tool execution
31
+ # @param context [VectorMCP::Middleware::Context] Execution context with result
32
+ def after_tool_call(context)
33
+ # Override in subclasses
34
+ end
35
+
36
+ # Called when tool execution fails
37
+ # @param context [VectorMCP::Middleware::Context] Execution context with error
38
+ def on_tool_error(context)
39
+ # Override in subclasses
40
+ end
41
+
42
+ # Resource operation hooks
43
+
44
+ # Called before resource read
45
+ # @param context [VectorMCP::Middleware::Context] Execution context
46
+ def before_resource_read(context)
47
+ # Override in subclasses
48
+ end
49
+
50
+ # Called after successful resource read
51
+ # @param context [VectorMCP::Middleware::Context] Execution context with result
52
+ def after_resource_read(context)
53
+ # Override in subclasses
54
+ end
55
+
56
+ # Called when resource read fails
57
+ # @param context [VectorMCP::Middleware::Context] Execution context with error
58
+ def on_resource_error(context)
59
+ # Override in subclasses
60
+ end
61
+
62
+ # Prompt operation hooks
63
+
64
+ # Called before prompt get
65
+ # @param context [VectorMCP::Middleware::Context] Execution context
66
+ def before_prompt_get(context)
67
+ # Override in subclasses
68
+ end
69
+
70
+ # Called after successful prompt get
71
+ # @param context [VectorMCP::Middleware::Context] Execution context with result
72
+ def after_prompt_get(context)
73
+ # Override in subclasses
74
+ end
75
+
76
+ # Called when prompt get fails
77
+ # @param context [VectorMCP::Middleware::Context] Execution context with error
78
+ def on_prompt_error(context)
79
+ # Override in subclasses
80
+ end
81
+
82
+ # Sampling operation hooks
83
+
84
+ # Called before sampling request
85
+ # @param context [VectorMCP::Middleware::Context] Execution context
86
+ def before_sampling_request(context)
87
+ # Override in subclasses
88
+ end
89
+
90
+ # Called after successful sampling response
91
+ # @param context [VectorMCP::Middleware::Context] Execution context with result
92
+ def after_sampling_response(context)
93
+ # Override in subclasses
94
+ end
95
+
96
+ # Called when sampling fails
97
+ # @param context [VectorMCP::Middleware::Context] Execution context with error
98
+ def on_sampling_error(context)
99
+ # Override in subclasses
100
+ end
101
+
102
+ # Transport operation hooks
103
+
104
+ # Called before any request processing
105
+ # @param context [VectorMCP::Middleware::Context] Execution context
106
+ def before_request(context)
107
+ # Override in subclasses
108
+ end
109
+
110
+ # Called after successful response
111
+ # @param context [VectorMCP::Middleware::Context] Execution context with result
112
+ def after_response(context)
113
+ # Override in subclasses
114
+ end
115
+
116
+ # Called when transport error occurs
117
+ # @param context [VectorMCP::Middleware::Context] Execution context with error
118
+ def on_transport_error(context)
119
+ # Override in subclasses
120
+ end
121
+
122
+ # Authentication hooks
123
+
124
+ # Called before authentication
125
+ # @param context [VectorMCP::Middleware::Context] Execution context
126
+ def before_auth(context)
127
+ # Override in subclasses
128
+ end
129
+
130
+ # Called after successful authentication
131
+ # @param context [VectorMCP::Middleware::Context] Execution context with result
132
+ def after_auth(context)
133
+ # Override in subclasses
134
+ end
135
+
136
+ # Called when authentication fails
137
+ # @param context [VectorMCP::Middleware::Context] Execution context with error
138
+ def on_auth_error(context)
139
+ # Override in subclasses
140
+ end
141
+
142
+ protected
143
+
144
+ attr_reader :config, :logger
145
+
146
+ # Helper method to modify request parameters (if mutable)
147
+ # @param context [VectorMCP::Middleware::Context] Execution context
148
+ # @param new_params [Hash] New parameters to set
149
+ def modify_params(context, new_params)
150
+ if context.respond_to?(:params=)
151
+ context.params = new_params
152
+ else
153
+ @logger.warn("Cannot modify immutable params in context")
154
+ end
155
+ end
156
+
157
+ # Helper method to modify response result
158
+ # @param context [VectorMCP::Middleware::Context] Execution context
159
+ # @param new_result [Object] New result to set
160
+ def modify_result(context, new_result)
161
+ context.result = new_result
162
+ end
163
+
164
+ # Helper method to skip remaining hooks in the chain
165
+ # @param context [VectorMCP::Middleware::Context] Execution context
166
+ def skip_remaining_hooks(context)
167
+ context.skip_remaining_hooks = true
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VectorMCP
4
+ module Middleware
5
+ # Context object passed to middleware hooks containing operation metadata
6
+ # Provides access to request data, session info, and mutable response data
7
+ class Context
8
+ attr_reader :operation_type, :operation_name, :params, :session, :server, :metadata
9
+ attr_accessor :result, :error, :skip_remaining_hooks
10
+
11
+ # @param options [Hash] Context initialization options
12
+ # @option options [Symbol] :operation_type Type of operation (:tool_call, :resource_read, etc.)
13
+ # @option options [String] :operation_name Name of the specific operation being performed
14
+ # @option options [Hash] :params Request parameters
15
+ # @option options [VectorMCP::Session] :session Current session
16
+ # @option options [VectorMCP::Server] :server Server instance
17
+ # @option options [Hash] :metadata Additional metadata about the operation
18
+ def initialize(options = {})
19
+ @operation_type = options[:operation_type]
20
+ @operation_name = options[:operation_name]
21
+ @params = (options[:params] || {}).dup.freeze # Immutable copy
22
+ @session = options[:session]
23
+ @server = options[:server]
24
+ @metadata = (options[:metadata] || {}).dup
25
+ @result = nil
26
+ @error = nil
27
+ @skip_remaining_hooks = false
28
+ end
29
+
30
+ # Check if operation completed successfully
31
+ # @return [Boolean] true if no error occurred
32
+ def success?
33
+ @error.nil?
34
+ end
35
+
36
+ # Check if operation failed
37
+ # @return [Boolean] true if error occurred
38
+ def error?
39
+ !@error.nil?
40
+ end
41
+
42
+ # Get user context from session if available
43
+ # @return [Hash, nil] User context or nil if not authenticated
44
+ def user
45
+ @session&.security_context&.user
46
+ end
47
+
48
+ # Get operation timing information
49
+ # @return [Hash] Timing metadata
50
+ def timing
51
+ @metadata[:timing] || {}
52
+ end
53
+
54
+ # Add custom metadata
55
+ # @param key [Symbol, String] Metadata key
56
+ # @param value [Object] Metadata value
57
+ def add_metadata(key, value)
58
+ @metadata[key] = value
59
+ end
60
+
61
+ # Get all available data as hash for logging/debugging
62
+ # @return [Hash] Context summary
63
+ def to_h
64
+ {
65
+ operation_type: @operation_type,
66
+ operation_name: @operation_name,
67
+ params: @params,
68
+ session_id: @session&.id,
69
+ metadata: @metadata,
70
+ success: success?,
71
+ error: @error&.class&.name
72
+ }
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VectorMCP
4
+ module Middleware
5
+ # Represents a single middleware hook with priority and execution logic
6
+ class Hook
7
+ attr_reader :middleware_class, :hook_type, :priority, :conditions
8
+
9
+ # Default priority for middleware (lower numbers execute first)
10
+ DEFAULT_PRIORITY = 100
11
+
12
+ # @param middleware_class [Class] The middleware class to execute
13
+ # @param hook_type [String, Symbol] Type of hook (before_tool_call, etc.)
14
+ # @param priority [Integer] Execution priority (lower numbers execute first)
15
+ # @param conditions [Hash] Conditions for when this hook should run
16
+ def initialize(middleware_class, hook_type, priority: DEFAULT_PRIORITY, conditions: {})
17
+ @middleware_class = middleware_class
18
+ @hook_type = hook_type.to_s
19
+ @priority = priority
20
+ @conditions = conditions
21
+
22
+ validate_hook_type!
23
+ validate_middleware_class!
24
+ end
25
+
26
+ # Execute this hook with the given context
27
+ # @param context [VectorMCP::Middleware::Context] Execution context
28
+ # @return [void]
29
+ def execute(context)
30
+ return unless should_execute?(context)
31
+
32
+ # Create middleware instance and execute hook
33
+ middleware_instance = create_middleware_instance(context)
34
+ execute_hook_method(middleware_instance, context)
35
+ rescue StandardError => e
36
+ handle_hook_error(e, context)
37
+ end
38
+
39
+ # Check if this hook should execute for the given context
40
+ # @param context [VectorMCP::Middleware::Context] Execution context
41
+ # @return [Boolean] true if hook should execute
42
+ def should_execute?(context)
43
+ return false if context.skip_remaining_hooks
44
+
45
+ # Check operation type match
46
+ return false unless matches_operation_type?(context)
47
+
48
+ # Check custom conditions
49
+ @conditions.all? { |key, value| condition_matches?(key, value, context) }
50
+ end
51
+
52
+ # Compare hooks for sorting by priority
53
+ # @param other [Hook] Other hook to compare
54
+ # @return [Integer] Comparison result
55
+ def <=>(other)
56
+ @priority <=> other.priority
57
+ end
58
+
59
+ private
60
+
61
+ def validate_hook_type!
62
+ return if HOOK_TYPES.include?(@hook_type)
63
+
64
+ raise InvalidHookTypeError, @hook_type
65
+ end
66
+
67
+ def validate_middleware_class!
68
+ raise ArgumentError, "middleware_class must be a Class, got #{@middleware_class.class}" unless @middleware_class.is_a?(Class)
69
+
70
+ return if @middleware_class < VectorMCP::Middleware::Base
71
+
72
+ raise ArgumentError, "middleware_class must inherit from VectorMCP::Middleware::Base"
73
+ end
74
+
75
+ def matches_operation_type?(context)
76
+ operation_prefix = @hook_type.split("_")[1..].join("_")
77
+
78
+ return true if transport_or_auth_hook?(operation_prefix)
79
+
80
+ operation_matches?(operation_prefix, context.operation_type)
81
+ end
82
+
83
+ def condition_matches?(key, value, context)
84
+ case key
85
+ when :only_operations, :except_operations
86
+ operation_condition_matches?(key, value, context)
87
+ when :only_users, :except_users
88
+ user_condition_matches?(key, value, context)
89
+ else
90
+ true # Unknown conditions are ignored
91
+ end
92
+ end
93
+
94
+ def transport_or_auth_hook?(operation_prefix)
95
+ %w[request response transport_error auth auth_error].include?(operation_prefix)
96
+ end
97
+
98
+ def operation_matches?(operation_prefix, operation_type)
99
+ case operation_prefix
100
+ when "tool_call", "tool_error"
101
+ operation_type == :tool_call
102
+ when "resource_read", "resource_error"
103
+ operation_type == :resource_read
104
+ when "prompt_get", "prompt_error"
105
+ operation_type == :prompt_get
106
+ when "sampling_request", "sampling_response", "sampling_error"
107
+ operation_type == :sampling
108
+ else
109
+ true
110
+ end
111
+ end
112
+
113
+ def operation_condition_matches?(key, value, context)
114
+ included = Array(value).include?(context.operation_name)
115
+ key == :only_operations ? included : !included
116
+ end
117
+
118
+ def user_condition_matches?(key, value, context)
119
+ user_id = context.user&.[](:user_id) || context.user&.[]("user_id")
120
+ included = Array(value).include?(user_id)
121
+ key == :only_users ? included : !included
122
+ end
123
+
124
+ def create_middleware_instance(_context)
125
+ if @middleware_class.respond_to?(:new)
126
+ @middleware_class.new
127
+ else
128
+ @middleware_class
129
+ end
130
+ end
131
+
132
+ def execute_hook_method(middleware_instance, context)
133
+ method_name = @hook_type
134
+
135
+ if middleware_instance.respond_to?(method_name)
136
+ middleware_instance.public_send(method_name, context)
137
+ elsif middleware_instance.respond_to?(:call)
138
+ # Fallback to generic call method
139
+ middleware_instance.call(@hook_type, context)
140
+ else
141
+ raise MiddlewareError,
142
+ "Middleware #{@middleware_class} does not respond to #{method_name} or call",
143
+ middleware_class: @middleware_class
144
+ end
145
+ end
146
+
147
+ def handle_hook_error(error, context)
148
+ # Log the error but don't break the chain unless it's critical
149
+ logger = VectorMCP.logger_for("middleware")
150
+ logger.error("Middleware hook failed") do
151
+ {
152
+ middleware: @middleware_class.name,
153
+ hook_type: @hook_type,
154
+ operation: context.operation_name,
155
+ error: error.message
156
+ }
157
+ end
158
+
159
+ # Re-raise if it's a critical error that should stop execution
160
+ return unless error.is_a?(VectorMCP::Error) || @conditions[:critical] == true
161
+
162
+ raise MiddlewareError,
163
+ "Critical middleware failure in #{@middleware_class}",
164
+ original_error: error,
165
+ middleware_class: @middleware_class
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent-ruby"
4
+
5
+ module VectorMCP
6
+ module Middleware
7
+ # Central manager for middleware hooks and execution
8
+ # Thread-safe registry and execution engine for all middleware
9
+ class Manager
10
+ def initialize
11
+ @hooks = Concurrent::Map.new { |h, k| h[k] = Concurrent::Array.new }
12
+ @logger = VectorMCP.logger_for("middleware.manager")
13
+ end
14
+
15
+ # Register a middleware for specific hook types
16
+ # @param middleware_class [Class] Middleware class inheriting from Base
17
+ # @param hooks [Array<String, Symbol>] Hook types to register for
18
+ # @param priority [Integer] Execution priority (lower numbers execute first)
19
+ # @param conditions [Hash] Conditions for when middleware should run
20
+ # @example
21
+ # manager.register(MyMiddleware, [:before_tool_call, :after_tool_call])
22
+ # manager.register(AuthMiddleware, :before_request, priority: 10)
23
+ def register(middleware_class, hooks, priority: Hook::DEFAULT_PRIORITY, conditions: {})
24
+ Array(hooks).each do |hook_type|
25
+ hook = Hook.new(middleware_class, hook_type, priority: priority, conditions: conditions)
26
+ add_hook(hook)
27
+ end
28
+
29
+ @logger.debug("Registered middleware") do
30
+ {
31
+ middleware: middleware_class.name,
32
+ hooks: Array(hooks),
33
+ priority: priority
34
+ }
35
+ end
36
+ end
37
+
38
+ # Remove all hooks for a specific middleware class
39
+ # @param middleware_class [Class] Middleware class to remove
40
+ def unregister(middleware_class)
41
+ removed_count = 0
42
+
43
+ @hooks.each_value do |hook_array|
44
+ removed_count += hook_array.delete_if { |hook| hook.middleware_class == middleware_class }.size
45
+ end
46
+
47
+ @logger.debug("Unregistered middleware") do
48
+ {
49
+ middleware: middleware_class.name,
50
+ hooks_removed: removed_count
51
+ }
52
+ end
53
+ end
54
+
55
+ # Execute all hooks for a specific hook type with timing
56
+ # @param hook_type [String, Symbol] Type of hook to execute
57
+ # @param context [VectorMCP::Middleware::Context] Execution context
58
+ # @return [VectorMCP::Middleware::Context] Modified context
59
+ def execute_hooks(hook_type, context)
60
+ hook_type_str = hook_type.to_s
61
+ hooks = get_sorted_hooks(hook_type_str)
62
+
63
+ return context if hooks.empty?
64
+
65
+ execution_state = initialize_execution_state(hook_type_str, hooks, context)
66
+ execute_hook_chain(hooks, context, execution_state)
67
+ finalize_execution(context, execution_state)
68
+
69
+ context
70
+ end
71
+
72
+ # Get statistics about registered middleware
73
+ # @return [Hash] Statistics summary
74
+ def stats
75
+ hook_counts = {}
76
+ total_hooks = 0
77
+
78
+ @hooks.each do |hook_type, hook_array|
79
+ count = hook_array.size
80
+ hook_counts[hook_type] = count
81
+ total_hooks += count
82
+ end
83
+
84
+ {
85
+ total_hooks: total_hooks,
86
+ hook_types: hook_counts.keys.sort,
87
+ hooks_by_type: hook_counts
88
+ }
89
+ end
90
+
91
+ # Clear all registered hooks (useful for testing)
92
+ def clear!
93
+ @hooks.clear
94
+ @logger.debug("Cleared all middleware hooks")
95
+ end
96
+
97
+ private
98
+
99
+ def add_hook(hook)
100
+ hook_type = hook.hook_type
101
+ hook_array = @hooks[hook_type]
102
+
103
+ # Insert hook in sorted position by priority
104
+ insertion_index = hook_array.find_index { |existing_hook| existing_hook.priority > hook.priority }
105
+ if insertion_index
106
+ hook_array.insert(insertion_index, hook)
107
+ else
108
+ hook_array << hook
109
+ end
110
+ end
111
+
112
+ def get_sorted_hooks(hook_type)
113
+ @hooks[hook_type].to_a
114
+ end
115
+
116
+ def initialize_execution_state(hook_type_str, hooks, _context)
117
+ start_time = Time.now
118
+
119
+ # Executing middleware hooks
120
+
121
+ {
122
+ hook_type: hook_type_str,
123
+ start_time: start_time,
124
+ executed_count: 0,
125
+ total_hooks: hooks.size
126
+ }
127
+ end
128
+
129
+ def execute_hook_chain(hooks, context, execution_state)
130
+ hooks.each do |hook|
131
+ break if context.skip_remaining_hooks
132
+
133
+ hook.execute(context)
134
+ execution_state[:executed_count] += 1
135
+ rescue MiddlewareError => e
136
+ handle_critical_error(e, execution_state[:hook_type], context)
137
+ break
138
+ rescue StandardError => e
139
+ handle_standard_error(e, execution_state[:hook_type])
140
+ # Continue with other hooks for non-critical errors
141
+ end
142
+ end
143
+
144
+ def finalize_execution(context, execution_state)
145
+ execution_time = Time.now - execution_state[:start_time]
146
+
147
+ context.add_metadata(:middleware_timing, {
148
+ hook_type: execution_state[:hook_type],
149
+ execution_time: execution_time,
150
+ hooks_executed: execution_state[:executed_count],
151
+ hooks_total: execution_state[:total_hooks]
152
+ })
153
+
154
+ # Completed middleware execution
155
+ end
156
+
157
+ def handle_critical_error(error, hook_type, context)
158
+ @logger.error("Critical middleware error") do
159
+ {
160
+ middleware: error.middleware_class&.name,
161
+ hook_type: hook_type,
162
+ error: error.message
163
+ }
164
+ end
165
+
166
+ context.error = error
167
+ end
168
+
169
+ def handle_standard_error(error, hook_type)
170
+ @logger.error("Unexpected middleware error") do
171
+ {
172
+ hook_type: hook_type,
173
+ error: error.message
174
+ }
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Middleware framework for VectorMCP
4
+ # Provides pluggable hooks around MCP operations
5
+ require_relative "errors"
6
+ require_relative "middleware/context"
7
+ require_relative "middleware/hook"
8
+ require_relative "middleware/manager"
9
+ require_relative "middleware/base"
10
+
11
+ module VectorMCP
12
+ # Middleware system for pluggable hooks around MCP operations
13
+ # Allows developers to add custom behavior without modifying core code
14
+ module Middleware
15
+ # Hook types available in the system
16
+ HOOK_TYPES = %w[
17
+ before_tool_call after_tool_call on_tool_error
18
+ before_resource_read after_resource_read on_resource_error
19
+ before_prompt_get after_prompt_get on_prompt_error
20
+ before_sampling_request after_sampling_response on_sampling_error
21
+ before_request after_response on_transport_error
22
+ before_auth after_auth on_auth_error
23
+ ].freeze
24
+
25
+ # Error raised when invalid hook type is specified
26
+ class InvalidHookTypeError < VectorMCP::Error
27
+ def initialize(hook_type)
28
+ super("Invalid hook type: #{hook_type}. Valid types: #{HOOK_TYPES.join(", ")}")
29
+ end
30
+ end
31
+
32
+ # Error raised when middleware execution fails
33
+ class MiddlewareError < VectorMCP::Error
34
+ attr_reader :original_error, :middleware_class
35
+
36
+ def initialize(message, original_error: nil, middleware_class: nil)
37
+ super(message)
38
+ @original_error = original_error
39
+ @middleware_class = middleware_class
40
+ end
41
+ end
42
+ end
43
+ end