How OpenMAIC Manages LLM Provider Configuration: Server-Side Architecture Explained
OpenMAIC centralizes LLM provider configuration in a dedicated server-side module that loads YAML files, overrides settings with environment variables, and exposes secure resolver APIs to keep API keys hidden from clients while providing metadata to the UI.
Managing credentials for multiple Large Language Model providers requires a careful balance between flexibility and security. In OpenMAIC, all LLM provider settings are governed by the provider-config module located at lib/server/provider-config.ts, which implements a hierarchical configuration system supporting both file-based and environment-based credential management. This architecture ensures that sensitive API keys never leave the server while still allowing clients to query available models and capabilities.
Configuration Loading Pipeline
The LLM provider configuration follows a strict loading order that combines declarative files with runtime environment overrides.
YAML File Initialization
At server startup, the system reads an optional YAML configuration file via loadYamlFile('server-providers.yml'). This file can declare provider definitions including API keys, base URLs, allowed model lists, and proxy settings.
Environment variables then override these values using the LLM_ENV_MAP constant defined at lines 63-78. This map associates prefixes like OPENAI with provider IDs like openai, enabling the system to scan for variables following the pattern:
<PREFIX>_API_KEY– Authentication credentials<PREFIX>_BASE_URL– Custom endpoint URLs<PREFIX>_MODELS– Comma-separated list of allowed models
The loadEnvSection function (lines 37-49) processes these mappings and merges them with the YAML baseline.
Process-Level Caching
The combined configuration is stored in a process-singleton Map called _configs to ensure fast subsequent reads without re-parsing files or re-scanning environment variables. This cache is populated during the buildConfig phase (lines 99-110).
ServerProviderEntry Interface
Each provider configuration conforms to the ServerProviderEntry interface defined between lines 25-40:
interface ServerProviderEntry {
apiKey: string;
baseUrl?: string;
models?: string[];
proxy?: string;
enabled?: boolean; // operator-wide force-off switch
}
The enabled boolean allows operators to administratively disable providers without removing their configuration entirely, while the optional models array enforces an allow-list of specific model identifiers.
Secure Public API for LLMs
OpenMAIC exposes a curated set of functions that provide necessary metadata to clients while protecting secrets. According to the implementation in lib/server/provider-config.ts, these resolvers handle the distinction between server-managed and unmanaged providers.
Listing Configured Providers
The getServerProviders() function returns a sanitized view of all managed LLM providers, exposing only the allowed model lists while omitting API keys and base URLs:
import { getServerProviders } from '@/lib/server/provider-config';
// Returns { openai: { models: ['gpt-4', 'gpt-3.5-turbo'] }, anthropic: {} }
const providers = getServerProviders();
Credential Resolution
The resolveApiKey() and resolveBaseUrl() functions implement a fallback strategy. If a provider ID exists in the server configuration, the server-side values are returned; otherwise, the functions accept optional client-supplied values for unmanaged providers:
import { resolveApiKey, resolveBaseUrl } from '@/lib/server/provider-config';
// Managed provider: returns server-configured key
const openaiKey = resolveApiKey('openai');
// Unmanaged provider: uses client-provided fallback
const customKey = resolveApiKey('my-custom-llm', 'client-key-123');
Additional utilities include isServerConfiguredProvider(), which checks administrative configuration status, and resolveProxy(), which fetches server-side proxy URLs for specific providers.
Model Pinning and Defaults
When operators specify <PREFIX>_MODELS, the first entry in the array becomes the managed default for that provider. Client-supplied models are validated against this allow-list in the resolveApiKey and resolveBaseUrl functions. This mechanism prevents users from accessing models that the operator has not explicitly approved, even if the underlying API key technically supports them.
Disable-by-Operator Capability
The module implements a disabled map populated by collectDisabledProviders() that allows forced deactivation of specific providers within capability sections. Disabled providers remain visible in listings—marked with { disabled: true }—so the UI can render them appropriately, but the runtime skips them during actual LLM calls. This provides clear user feedback while enforcing operational restrictions.
Security Architecture
OpenMAIC maintains strict separation between server-side secrets and client-visible metadata. The configuration flow ensures:
- Secret containment: API keys reside only in the
_configsMap on the server - Environment flexibility: Operators can inject credentials via environment variables without modifying code
- Client safety: Public APIs expose model lists but never expose
apiKeyorbaseUrlvalues
This pattern is validated in tests/store/settings-validation.test.ts, which verifies hasUsableLLMProvider and isLLMProviderConfigured logic, and demonstrated in tests/web-search/route.test.ts, which exercises the resolver functions in route handlers.
Summary
- Centralized configuration: All LLM provider settings live in
lib/server/provider-config.tswith YAML and environment variable support - Hierarchical loading:
server-providers.ymlprovides defaults, whileLLM_ENV_MAPenables environment variable overrides - Secure APIs:
getServerProviders(),resolveApiKey(), andresolveBaseUrl()protect secrets while exposing necessary metadata - Administrative controls: Operators can disable providers globally or pin specific models using the
enabledflag and<PREFIX>_MODELSarrays - Process caching: The
_configsMap eliminates redundant file system and environment scans after initial load
Frequently Asked Questions
How does OpenMAIC keep LLM API keys secure?
OpenMAIC stores API keys exclusively in the server-side _configs Map within lib/server/provider-config.ts. The public getServerProviders() function deliberately omits the apiKey and baseUrl fields from its return type, exposing only model arrays and boolean flags. When client applications need to route requests through the server, they call resolveApiKey() and resolveBaseUrl(), which execute within the server context and never transmit credentials to the browser.
Can I configure multiple LLM providers simultaneously?
Yes. The configuration system supports multiple providers through the server-providers.yml file or by defining multiple entries in the LLM_ENV_MAP. Each provider requires a unique prefix (such as OPENAI or ANTHROPIC) mapped to its provider ID. The getServerProviders() function returns an object containing all configured providers, allowing the application to switch between them based on capability requirements or user preferences.
What happens if I specify both a YAML file and environment variables?
OpenMAIC applies a layered configuration strategy. The buildConfig process first loads values from server-providers.yml, then the loadEnvSection function overrides those values with any matching environment variables found using the LLM_ENV_MAP prefixes. This allows operators to commit non-sensitive base URLs to version control while keeping API keys in secure environment variables.
How do I restrict which models users can access?
Specify the <PREFIX>_MODELS environment variable with a comma-separated list of allowed model identifiers. The first model in this list becomes the default for that provider. The resolveApiKey and related resolver functions validate client-supplied models against this allow-list, rejecting requests for models not explicitly included in the server configuration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →