fix: ensure API key detection properly reads .env in MCP context
Problem: - Task Master model configuration wasn't properly checking for API keys in the project's .env file when running through MCP - The isApiKeySet function was only checking session.env and process.env but not inspecting the .env file directly - This caused incorrect API key status reporting in MCP tools even when keys were properly set in .env Solution: - Modified resolveEnvVariable function in utils.js to properly read from .env file at projectRoot - Updated isApiKeySet to correctly pass projectRoot to resolveEnvVariable - Enhanced the key detection logic to have consistent behavior between CLI and MCP contexts - Maintains the correct precedence: session.env → .env file → process.env Testing: - Verified working correctly with both MCP and CLI tools - API keys properly detected in .env file in both contexts - Deleted .cursor/mcp.json to confirm introspection of .env as fallback works
This commit is contained in:
@@ -424,12 +424,13 @@ function getParametersForRole(role, explicitRoot = null) {
|
||||
|
||||
/**
|
||||
* Checks if the API key for a given provider is set in the environment.
|
||||
* Checks process.env first, then session.env if session is provided.
|
||||
* Checks process.env first, then session.env if session is provided, then .env file if projectRoot provided.
|
||||
* @param {string} providerName - The name of the provider (e.g., 'openai', 'anthropic').
|
||||
* @param {object|null} [session=null] - The MCP session object (optional).
|
||||
* @param {string|null} [projectRoot=null] - The project root directory (optional, for .env file check).
|
||||
* @returns {boolean} True if the API key is set, false otherwise.
|
||||
*/
|
||||
function isApiKeySet(providerName, session = null) {
|
||||
function isApiKeySet(providerName, session = null, projectRoot = null) {
|
||||
// Define the expected environment variable name for each provider
|
||||
if (providerName?.toLowerCase() === 'ollama') {
|
||||
return true; // Indicate key status is effectively "OK"
|
||||
@@ -454,7 +455,7 @@ function isApiKeySet(providerName, session = null) {
|
||||
}
|
||||
|
||||
const envVarName = keyMap[providerKey];
|
||||
const apiKeyValue = resolveEnvVariable(envVarName, session);
|
||||
const apiKeyValue = resolveEnvVariable(envVarName, session, projectRoot);
|
||||
|
||||
// Check if the key exists, is not empty, and is not a placeholder
|
||||
return (
|
||||
|
||||
@@ -77,7 +77,7 @@ function fetchOpenRouterModels() {
|
||||
* @returns {Object} RESTful response with current model configuration
|
||||
*/
|
||||
async function getModelConfiguration(options = {}) {
|
||||
const { mcpLog, projectRoot } = options;
|
||||
const { mcpLog, projectRoot, session } = options;
|
||||
|
||||
const report = (level, ...args) => {
|
||||
if (mcpLog && typeof mcpLog[level] === 'function') {
|
||||
@@ -125,12 +125,16 @@ async function getModelConfiguration(options = {}) {
|
||||
const fallbackModelId = getFallbackModelId(projectRoot);
|
||||
|
||||
// Check API keys
|
||||
const mainCliKeyOk = isApiKeySet(mainProvider);
|
||||
const mainCliKeyOk = isApiKeySet(mainProvider, session, projectRoot);
|
||||
const mainMcpKeyOk = getMcpApiKeyStatus(mainProvider, projectRoot);
|
||||
const researchCliKeyOk = isApiKeySet(researchProvider);
|
||||
const researchCliKeyOk = isApiKeySet(
|
||||
researchProvider,
|
||||
session,
|
||||
projectRoot
|
||||
);
|
||||
const researchMcpKeyOk = getMcpApiKeyStatus(researchProvider, projectRoot);
|
||||
const fallbackCliKeyOk = fallbackProvider
|
||||
? isApiKeySet(fallbackProvider)
|
||||
? isApiKeySet(fallbackProvider, session, projectRoot)
|
||||
: true;
|
||||
const fallbackMcpKeyOk = fallbackProvider
|
||||
? getMcpApiKeyStatus(fallbackProvider, projectRoot)
|
||||
@@ -523,7 +527,7 @@ async function getApiKeyStatusReport(options = {}) {
|
||||
); // Ollama is not a provider, it's a service, doesn't need an api key usually
|
||||
const statusReport = providersToCheck.map((provider) => {
|
||||
// Use provided projectRoot for MCP status check
|
||||
const cliOk = isApiKeySet(provider, session); // Pass session for CLI check too
|
||||
const cliOk = isApiKeySet(provider, session, projectRoot); // Pass session and projectRoot for CLI check
|
||||
const mcpOk = getMcpApiKeyStatus(provider, projectRoot);
|
||||
return {
|
||||
provider,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import dotenv from 'dotenv';
|
||||
// Import specific config getters needed here
|
||||
import { getLogLevel, getDebugFlag } from './config-manager.js';
|
||||
|
||||
@@ -14,16 +15,47 @@ let silentMode = false;
|
||||
|
||||
// --- Environment Variable Resolution Utility ---
|
||||
/**
|
||||
* Resolves an environment variable by checking process.env first, then session.env.
|
||||
* @param {string} varName - The name of the environment variable.
|
||||
* @param {string|null} session - The MCP session object (optional).
|
||||
* Resolves an environment variable's value.
|
||||
* Precedence:
|
||||
* 1. session.env (if session provided)
|
||||
* 2. process.env
|
||||
* 3. .env file at projectRoot (if projectRoot provided)
|
||||
* @param {string} key - The environment variable key.
|
||||
* @param {object|null} [session=null] - The MCP session object.
|
||||
* @param {string|null} [projectRoot=null] - The project root directory (for .env fallback).
|
||||
* @returns {string|undefined} The value of the environment variable or undefined if not found.
|
||||
*/
|
||||
function resolveEnvVariable(varName, session) {
|
||||
// Ensure session and session.env exist before attempting access
|
||||
const sessionValue =
|
||||
session && session.env ? session.env[varName] : undefined;
|
||||
return process.env[varName] ?? sessionValue;
|
||||
function resolveEnvVariable(key, session = null, projectRoot = null) {
|
||||
// 1. Check session.env
|
||||
if (session?.env?.[key]) {
|
||||
return session.env[key];
|
||||
}
|
||||
|
||||
// 2. Read .env file at projectRoot
|
||||
if (projectRoot) {
|
||||
const envPath = path.join(projectRoot, '.env');
|
||||
if (fs.existsSync(envPath)) {
|
||||
try {
|
||||
const envFileContent = fs.readFileSync(envPath, 'utf-8');
|
||||
const parsedEnv = dotenv.parse(envFileContent); // Use dotenv to parse
|
||||
if (parsedEnv && parsedEnv[key]) {
|
||||
// console.log(`DEBUG: Found key ${key} in ${envPath}`); // Optional debug log
|
||||
return parsedEnv[key];
|
||||
}
|
||||
} catch (error) {
|
||||
// Log error but don't crash, just proceed as if key wasn't found in file
|
||||
log('warn', `Could not read or parse ${envPath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fallback: Check process.env
|
||||
if (process.env[key]) {
|
||||
return process.env[key];
|
||||
}
|
||||
|
||||
// Not found anywhere
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- Project Root Finding Utility ---
|
||||
|
||||
Reference in New Issue
Block a user