Class: ActionMCP::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/action_mcp/configuration.rb

Overview

Configuration class to hold settings for the ActionMCP server.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConfiguration

Returns a new instance of Configuration.



54
55
56
57
58
59
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
# File 'lib/action_mcp/configuration.rb', line 54

def initialize
  @logging_enabled = false
  @list_changed = true
  @logging_level = :warning
  @resources_subscribe = false
  @elicitation_enabled = false
  @verbose_logging = false
  @active_profile = :primary
  @profiles = default_profiles

  # Authentication defaults - empty means all configured identifiers will be tried
  @authentication_methods = []

  @protocol_version = "2025-06-18"  # Default to stable version for backwards compatibility

  # Tasks defaults (MCP 2025-11-25)
  @tasks_enabled = false
  @tasks_list_enabled = true
  @tasks_cancel_enabled = true

  # Schema validation - disabled by default for backward compatibility
  @validate_structured_content = false

  # Gateway - resolved lazily to account for Zeitwerk autoloading
  @gateway_class_name = nil

  # Session Store
  @session_store_type = Rails.env.production? ? :active_record : :volatile
  @client_session_store_type = nil # defaults to session_store_type
  @server_session_store_type = nil # defaults to session_store_type
end

Instance Attribute Details

#active_profileObject

Get active profile (considering thread-local override)



108
109
110
# File 'lib/action_mcp/configuration.rb', line 108

def active_profile
  @active_profile
end

#adapterObject

Returns the value of attribute adapter.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def adapter
  @adapter
end

#authentication_methodsObject

Returns the value of attribute authentication_methods.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def authentication_methods
  @authentication_methods
end

#client_session_store_typeObject

Get effective client session store type (falls back to global session_store_type)



243
244
245
# File 'lib/action_mcp/configuration.rb', line 243

def client_session_store_type
  @client_session_store_type
end

#connects_toObject

Returns the value of attribute connects_to.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def connects_to
  @connects_to
end

#elicitation_enabledObject

Returns the value of attribute elicitation_enabled.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def elicitation_enabled
  @elicitation_enabled
end

#gateway_classObject

Returns the value of attribute gateway_class.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def gateway_class
  @gateway_class
end

#list_changedBoolean

Returns Whether to send a listChanged notification for tools, prompts, and resources.

Returns:

  • (Boolean)

    Whether to send a listChanged notification for tools, prompts, and resources.



21
# File 'lib/action_mcp/configuration.rb', line 21

attr_writer :name, :version

#logging_enabledBoolean

Returns Whether logging is enabled.

Returns:

  • (Boolean)

    Whether logging is enabled.



21
# File 'lib/action_mcp/configuration.rb', line 21

attr_writer :name, :version

#logging_levelSymbol

Returns The logging level.

Returns:

  • (Symbol)

    The logging level.



21
# File 'lib/action_mcp/configuration.rb', line 21

attr_writer :name, :version

#max_queueObject

Returns the value of attribute max_queue.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def max_queue
  @max_queue
end

#max_threadsObject

Returns the value of attribute max_threads.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def max_threads
  @max_threads
end

#min_threadsObject

Returns the value of attribute min_threads.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def min_threads
  @min_threads
end

#nameString

Returns The name of the MCP Server.

Returns:

  • (String)

    The name of the MCP Server.



21
# File 'lib/action_mcp/configuration.rb', line 21

attr_writer :name, :version

#polling_intervalObject

Returns the value of attribute polling_interval.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def polling_interval
  @polling_interval
end

#profilesObject

Returns the value of attribute profiles.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def profiles
  @profiles
end

#protocol_versionObject

Returns the value of attribute protocol_version.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def protocol_version
  @protocol_version
end

#resources_subscribeBoolean

Returns Whether to subscribe to resources.

Returns:

  • (Boolean)

    Whether to subscribe to resources.



21
# File 'lib/action_mcp/configuration.rb', line 21

attr_writer :name, :version

#server_session_store_typeObject

Get effective server session store type (falls back to global session_store_type)



248
249
250
# File 'lib/action_mcp/configuration.rb', line 248

def server_session_store_type
  @server_session_store_type
end

#session_store_typeObject

Returns the value of attribute session_store_type.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def session_store_type
  @session_store_type
end

#tasks_cancel_enabledObject

Returns the value of attribute tasks_cancel_enabled.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def tasks_cancel_enabled
  @tasks_cancel_enabled
end

#tasks_enabledObject

Returns the value of attribute tasks_enabled.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def tasks_enabled
  @tasks_enabled
end

#tasks_list_enabledObject

Returns the value of attribute tasks_list_enabled.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def tasks_list_enabled
  @tasks_list_enabled
end

#validate_structured_contentObject

Returns the value of attribute validate_structured_content.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def validate_structured_content
  @validate_structured_content
end

#verbose_loggingObject

Returns the value of attribute verbose_logging.



22
23
24
# File 'lib/action_mcp/configuration.rb', line 22

def verbose_logging
  @verbose_logging
end

#versionString

Returns The version of the MCP Server.

Returns:

  • (String)

    The version of the MCP Server.



21
# File 'lib/action_mcp/configuration.rb', line 21

attr_writer :name, :version

Instance Method Details

#apply_profile_optionsObject



252
253
254
255
256
257
258
259
260
261
# File 'lib/action_mcp/configuration.rb', line 252

def apply_profile_options
  profile = @profiles[active_profile]
  return unless profile && profile[:options]

  options = profile[:options]
  @list_changed = options[:list_changed] unless options[:list_changed].nil?
  @logging_enabled = options[:logging_enabled] unless options[:logging_enabled].nil?
  @logging_level = options[:logging_level] unless options[:logging_level].nil?
  @resources_subscribe = options[:resources_subscribe] unless options[:resources_subscribe].nil?
end

#capabilitiesObject

Returns capabilities based on active profile



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/action_mcp/configuration.rb', line 207

def capabilities
  capabilities = {}
  profile = @profiles[active_profile]

  # Check profile configuration instead of registry contents
  # If profile includes tools (either "all" or specific tools), advertise tools capability
  capabilities[:tools] = { listChanged: @list_changed } if profile && profile[:tools]&.any?

  # If profile includes prompts, advertise prompts capability
  capabilities[:prompts] = { listChanged: @list_changed } if profile && profile[:prompts]&.any?

  capabilities[:logging] = {} if @logging_enabled

  # If profile includes resources, advertise resources capability
  if profile && profile[:resources]&.any?
    capabilities[:resources] = { subscribe: @resources_subscribe, listChanged: @list_changed }
  end

  capabilities[:elicitation] = {} if @elicitation_enabled

  # Tasks capability (MCP 2025-11-25)
  if @tasks_enabled
    tasks_cap = {
      requests: {
        tools: { call: {} }
      }
    }
    tasks_cap[:list] = {} if @tasks_list_enabled
    tasks_cap[:cancel] = {} if @tasks_cancel_enabled
    capabilities[:tasks] = tasks_cap
  end

  capabilities
end

#eager_load_if_neededObject



263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/action_mcp/configuration.rb', line 263

def eager_load_if_needed
  profile = @profiles[active_profile]
  return unless profile

  # Check if any component type includes "all"
  needs_eager_load = profile[:tools]&.include?("all") ||
                     profile[:prompts]&.include?("all") ||
                     profile[:resources]&.include?("all")

  return unless needs_eager_load

  ensure_mcp_components_loaded
end

#filtered_promptsObject

Filter prompts based on active profile



191
192
193
194
195
196
# File 'lib/action_mcp/configuration.rb', line 191

def filtered_prompts
  return PromptsRegistry.non_abstract if should_include_all?(:prompts)

  prompt_names = @profiles[active_profile][:prompts] || []
  PromptsRegistry.non_abstract.select { |prompt| prompt_names.include?(prompt.name) }
end

#filtered_resourcesObject

Filter resources based on active profile



199
200
201
202
203
204
# File 'lib/action_mcp/configuration.rb', line 199

def filtered_resources
  return ResourceTemplatesRegistry.non_abstract if should_include_all?(:resources)

  resource_names = @profiles[active_profile][:resources] || []
  ResourceTemplatesRegistry.non_abstract.select { |resource| resource_names.include?(resource.name) }
end

#filtered_toolsObject

Filter tools based on active profile



181
182
183
184
185
186
187
188
# File 'lib/action_mcp/configuration.rb', line 181

def filtered_tools
  return ToolsRegistry.non_abstract if should_include_all?(:tools)

  tool_names = @profiles[active_profile][:tools] || []
  # Convert tool names to underscored format
  tool_names = tool_names.map { |name| name.to_s.underscore }
  ToolsRegistry.non_abstract.select { |tool| tool_names.include?(tool.name.underscore) }
end

#load_profilesObject

Load custom configuration from Rails configuration



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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
# File 'lib/action_mcp/configuration.rb', line 113

def load_profiles
  # First load defaults from the gem
  @profiles = default_profiles

  # Preserve any settings that were already set via Rails config
  preserved_name = @name

  # Try to load from config/mcp.yml in the Rails app using Rails.config_for
  begin
    app_config = Rails.application.config_for(:mcp)

    raise "Invalid MCP config file" unless app_config.is_a?(Hash)

    # Extract authentication configuration if present
    # Handle both symbol and string keys
    @authentication_methods = Array(app_config[:authentication] || app_config["authentication"]) if app_config[:authentication] || app_config["authentication"]

    # Extract other top-level configuration settings
    extract_top_level_settings(app_config)

    # Extract profiles configuration - merge with defaults instead of replacing
    # Rails.config_for returns OrderedOptions which uses symbol keys
    if app_config[:profiles] || app_config["profiles"]
      # Get profiles with either symbol or string key
      app_profiles = app_config[:profiles] || app_config["profiles"]

      # Convert to regular hash and deep symbolize keys
      if app_profiles.is_a?(ActiveSupport::OrderedOptions)
        app_profiles = app_profiles.to_h.deep_symbolize_keys
      elsif app_profiles.respond_to?(:deep_symbolize_keys)
        app_profiles = app_profiles.deep_symbolize_keys
      end

      Rails.logger.debug "[Configuration] Merging profiles: #{app_profiles.inspect}" if @verbose_logging
      @profiles = @profiles.deep_merge(app_profiles)
    end
  rescue StandardError => e
    # If the config file doesn't exist in the Rails app, just use the defaults
    Rails.logger.warn "[Configuration] Failed to load MCP config: #{e.class} - #{e.message}"
    # No MCP config found in Rails app, using defaults from gem
  end

  # Apply the active profile
  Rails.logger.info "[ActionMCP] Loaded profiles: #{@profiles.keys.join(', ')}" if @verbose_logging
  Rails.logger.info "[ActionMCP] Using profile: #{@active_profile}" if @verbose_logging
  use_profile(@active_profile)

  # Restore preserved settings
  @name = preserved_name if preserved_name

  self
end

#use_profile(profile_name) ⇒ Object

Switch to a specific profile



167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/action_mcp/configuration.rb', line 167

def use_profile(profile_name)
  profile_name = profile_name.to_sym
  unless @profiles.key?(profile_name)
    Rails.logger.warn "Profile '#{profile_name}' not found, using primary"
    profile_name = :primary
  end

  @active_profile = profile_name
  apply_profile_options

  self
end