Loads configuration and credentials from various sources into environment variables. Uses per-variable precedence - each variable is loaded from the highest priority source. Priority order (highest to lowest): 1. Runtime environment variables (shell/CI) 2. Local `.env` in projec
()
| 285 | # ============================================================================ |
| 286 | |
| 287 | def _load_credentials(): |
| 288 | """ |
| 289 | Loads configuration and credentials from various sources into environment variables. |
| 290 | Uses per-variable precedence - each variable is loaded from the highest priority source. |
| 291 | Priority order (highest to lowest): |
| 292 | 1. Runtime environment variables (shell/CI) |
| 293 | 2. Local `.env` in project directory (project-specific overrides) |
| 294 | 3. Global `~/.codegraphcontext/.env` (user defaults, including `cgc config set`) |
| 295 | 4. Local `mcp.json` env vars (project defaults) |
| 296 | 1. Local `mcp.json` env vars (highest - explicit MCP server config) |
| 297 | 2. ``<cwd>/.codegraphcontext/.env`` only (no parent-directory walk) |
| 298 | 3. Global `~/.codegraphcontext/.env` (lowest - user defaults) |
| 299 | |
| 300 | Step 2 skips duplicate loading when that file is the same path as the global file. |
| 301 | Arbitrary repo-root `.env` files are not loaded—only CodeGraphContext config paths. |
| 302 | """ |
| 303 | from dotenv import dotenv_values |
| 304 | from codegraphcontext.cli.config_manager import ( |
| 305 | ensure_config_dir, |
| 306 | codegraphcontext_dotenv_at_cwd, |
| 307 | ) |
| 308 | |
| 309 | # Ensure config directory exists (lazy initialization) |
| 310 | ensure_config_dir() |
| 311 | |
| 312 | # Snapshot runtime environment BEFORE merging config files. |
| 313 | # These values must remain highest priority. |
| 314 | runtime_env = dict(os.environ) |
| 315 | |
| 316 | # Collect all config sources in precedence order (lowest to highest) |
| 317 | config_sources = [] |
| 318 | config_source_names = [] |
| 319 | key_source_map = {} |
| 320 | key_defined_in = {} |
| 321 | |
| 322 | def _append_source(source_name: str, source_values: dict): |
| 323 | if not source_values: |
| 324 | return |
| 325 | config_sources.append(source_values) |
| 326 | config_source_names.append(source_name) |
| 327 | for k, v in source_values.items(): |
| 328 | if v is None: |
| 329 | continue |
| 330 | key_source_map[k] = source_name |
| 331 | key_defined_in.setdefault(k, []).append(source_name) |
| 332 | |
| 333 | # 4. Local mcp.json (lowest priority - project defaults) |
| 334 | mcp_file_path = Path.cwd() / "mcp.json" |
| 335 | if mcp_file_path.exists(): |
| 336 | try: |
| 337 | with open(mcp_file_path, "r") as f: |
| 338 | mcp_config = json.load(f) |
| 339 | server_env = mcp_config.get("mcpServers", {}).get("CodeGraphContext", {}).get("env", {}) |
| 340 | _append_source("mcp.json", server_env) |
| 341 | except Exception as e: |
| 342 | console.print(f"[yellow]Warning: Could not load mcp.json: {e}[/yellow]") |
| 343 | |
| 344 | # 3. Global .env file (user defaults) |