Files
agenticSystem/mcp-server/config/index.js
Jordan Diaz 43337e8554 Hardening: lock de sesion atomico, monitor off por defecto, fix DeepSeek reasoning-only
- session_lock: token uuid + compare-and-delete (Lua), TTL > timeout de
  ejecucion; abort solo limpia el lock tras cancelacion confirmada.
  Evita doble ejecucion concurrente sobre la misma sesion.
- monitor HTTP (puerto 4545) deshabilitado salvo MCP_MONITOR_ENABLED=true
  y atado a 127.0.0.1; no se acumula historial en memoria si esta off.
- DeepSeek/LiteLLM: turnos que llegan solo con reasoning_content (sin
  content ni tool_calls) ya no rompen la sesion (400 'Invalid assistant
  message') ni se pintan como 'pensando': se promueven a texto en el
  historial y en el snapshot persistido.
- litellm pinneado a ==1.80.0 (builds reproducibles).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 15:17:52 +00:00

110 lines
3.7 KiB
JavaScript

import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import dotenv from "dotenv";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Load .env from server directory
dotenv.config({ path: path.join(__dirname, '..', '.env') });
export const CONFIG_FILE_PATH =
process.env.ACAI_CONFIG_PATH ||
path.join(__dirname, "..", "..", "mcp-config.json");
export const MCP_PORT = Number(process.env.MCP_PORT || 3000);
export const MONITOR_PORT = Number(process.env.MCP_MONITOR_PORT || 4545);
// El monitor HTTP (UI + POST /retry) queda DESACTIVADO por defecto. Solo se
// arranca si MCP_MONITOR_ENABLED === 'true' de forma explicita.
export const MONITOR_ENABLED =
String(process.env.MCP_MONITOR_ENABLED || "").toLowerCase() === "true";
// Por seguridad escucha solo en loopback salvo que se defina MCP_MONITOR_HOST.
export const MONITOR_HOST = process.env.MCP_MONITOR_HOST || "127.0.0.1";
// Compatibilidad: si alguien fuerza MCP_MONITOR_DISABLED tambien lo respetamos.
export const MONITOR_DISABLED =
String(process.env.MCP_MONITOR_DISABLED || "").toLowerCase() === "1" ||
String(process.env.MCP_MONITOR_DISABLED || "").toLowerCase() === "true";
export const JWT_SECRET =
process.env.MCP_JWT_SECRET ||
process.env.JWT_SECRET ||
"change_me_in_env";
if (JWT_SECRET === "change_me_in_env") {
console.warn("[config] WARNING: JWT_SECRET is using the default value. Set MCP_JWT_SECRET or JWT_SECRET in your .env file for production.");
}
export const LOCAL_SERVER_URL = process.env.LOCAL_SERVER_URL || 'http://localhost:29871';
// Auth headers para llamadas internas al server Python
export function getLocalServerHeaders() {
const headers = { "Content-Type": "application/json" };
// En Forge, usar X-Acai-Token para auth interna
const token = process.env.ACAI_TOKEN || "";
const website = process.env.ACAI_WEBSITE || "";
if (token && website) {
headers["X-Acai-Token"] = token;
headers["X-Acai-Website"] = website;
}
return headers;
}
export const SAAS_URL = "https://ws.cocosolution.com/api/schemas/";
export const CMS_URL = "https://acai.cms.cocosolution.com";
const selectProfile = (config) => {
if (!config || typeof config !== "object") {
return null;
}
if (config.token && config.website) {
return { ...config, profileName: config.profileName || "default" };
}
const profiles = config.profiles || {};
const profileKey =
process.env.ACAI_PROFILE ||
config.defaultProfile ||
Object.keys(profiles)[0];
if (profileKey && profiles[profileKey]) {
return {
...profiles[profileKey],
profileName: profileKey,
};
}
return null;
};
export const loadLocalConfigProfile = () => {
if (!fs.existsSync(CONFIG_FILE_PATH)) {
return null;
}
try {
const raw = fs.readFileSync(CONFIG_FILE_PATH, "utf-8");
const parsed = JSON.parse(raw);
return selectProfile(parsed);
} catch (error) {
console.error(`[config] Could not read ${CONFIG_FILE_PATH}: ${error.message}`);
return null;
}
};
export const applyProfileToEnv = (profile) => {
if (!profile) {
return;
}
if (!process.env.ACAI_TOKEN && profile.token) {
process.env.ACAI_TOKEN = profile.token;
}
if (!process.env.ACAI_TOKEN_HASH && profile.tokenHash) {
process.env.ACAI_TOKEN_HASH = profile.tokenHash;
}
if (!process.env.ACAI_WEBSITE && profile.website) {
process.env.ACAI_WEBSITE = profile.website;
}
console.error(`[config] Loaded Acai profile '${profile.profileName}' from ${CONFIG_FILE_PATH}`);
};