Module: Woods::MCP::ConfigResolver

Defined in:
lib/woods/mcp/config_resolver.rb

Overview

Resolves the embedding configuration that the MCP server should use.

Reads woods.json (the resolved config snapshot written at embed time), applies environment-variable overrides, validates, and returns either a populated Configuration or raises a typed BootstrapError subclass that the caller can present to an operator.

This class is extracted from Bootstrapper to isolate the config-resolution concern from network probing and store construction. Bootstrapper delegates to ConfigResolver.resolve as its first step.

Resolution order (highest priority first):

  1. Host Rails initializer (Woods.configuration already has embedding_provider). When woods.json is also present the stored config is loaded and asserted compatible via ResolvedConfig#assert_compatible!.

  2. woods.json snapshot alone (MCP server running without a host initializer). The stored config is used to populate config in place.

  3. Environment-variable auto-detect (the default when woods.json is absent and no host provider is set). Wires semantic search if OPENAI_API_KEY or a reachable Ollama is found; otherwise leaves the provider nil so the server boots in pattern/structural-only mode.

  4. WOODS_REQUIRE_INDEX=1 overrides (3) to fail closed, raising MissingArtifact when woods.json is absent.

Examples:

Typical Bootstrapper usage

config, source = ConfigResolver.resolve(Woods.configuration, artifact: artifact)
# config.embedding_provider is now guaranteed to be non-nil (or :none was returned)

Class Method Summary collapse

Class Method Details

.resolve(config, artifact:, env: ENV, ollama_probe: nil) ⇒ Array(Woods::Configuration, Symbol)

Resolve and validate the embedding configuration.

When woods.json is present in the artifact directory it is parsed into a ResolvedConfig and, if the host already has a provider configured, validated for compatibility (dimension + provider class/model must agree). If the host has no provider configured the stored config is applied to config so Builder can construct the correct provider.

When woods.json is absent and the host already has a provider configured, the host config is trusted and used as-is.

When woods.json is absent and the host has no provider configured, auto-detect runs by default: pattern/structural tools always work, and semantic search wires up only if OPENAI_API_KEY or a reachable Ollama is found. Set WOODS_REQUIRE_INDEX=1 to fail closed and raise MissingArtifact instead.

Parameters:

  • config (Woods::Configuration)

    the live host configuration object. May be mutated in the auto-detect path.

  • artifact (Woods::IndexArtifact, nil)

    the on-disk artifact wrapper.

  • env (Hash) (defaults to: ENV)

    environment variable source (default ENV, overridable in specs without stubbing the global ENV).

  • ollama_probe (#call, nil) (defaults to: nil)

    callable used to check Ollama reachability in the deprecated auto-detect path. Defaults to ollama_reachable? on this module. Callers may pass a different probe to facilitate testing without touching global state.

Returns:

  • (Array(Woods::Configuration, Symbol))

    tuple of [config, source] where source is one of :snapshot, :host_config, :autodetect, or :none. The config is the same object passed in, possibly mutated.

Raises:



75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/woods/mcp/config_resolver.rb', line 75

def self.resolve(config, artifact:, env: ENV, ollama_probe: nil)
  stored = read_stored_config(artifact)

  if stored
    [apply_stored_config(config, stored, artifact: artifact, env: env), :snapshot]
  elsif config.embedding_provider
    # Host initializer configured a provider; no woods.json to validate
    # against. Trust the host config and proceed.
    [config, :host_config]
  else
    resolve_without_artifact(config, artifact: artifact, env: env, ollama_probe: ollama_probe)
  end
end