Files
agenticSystem/mcp-server/tools/helpers/pythonServerClient.js
Jordan 5dc2dbcf4a analyze/upload vía /api/image-bytes + MCP HTTP (vscode) forzado a test
Imágenes:
- analyze_image y upload resuelven los bytes por el endpoint Python
  /api/image-bytes (pythonGetBinary). analyze_image enruta los dominios
  forge (env ACAI_FORGE_DOMAIN) al endpoint en vez de fetch directo (que
  daba ECONNREFUSED 127.0.0.1 dentro del container).

Aislamiento de entorno (vscode = solo test):
- resolveCurrentModeOverride(): sesión MCP HTTP (mcpSessionId presente) →
  "local"; stdio (chat/cron) → ACAI_MODE_OVERRIDE de entorno. Lo usan los
  builders de headers (pythonServerClient, files/helpers) → toda tool del
  MCP HTTP manda X-Acai-Mode: local.
- httpServer.resolveProjectCredentials fuerza forceMode:"local" al resolver
  project-info → la sesión obtiene web_url/api_web_url forge-local y opera
  siempre contra test, nunca producción.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 19:11:50 +01:00

63 lines
2.2 KiB
JavaScript

import axios from "axios";
import { resolveCurrentAcaiUser, resolveCurrentModeOverride } from "./sessionHelpers.js";
const PYTHON_BASE = `http://app:${process.env.ACAI_PORT || 9091}`;
/**
* Construye el set de headers comunes para llamadas al server Python interno.
* Inyecta automaticamente `X-Acai-User` cuando hay sesion MCP activa con
* `acai_user` conocido, lo que permite a los endpoints autenticados identificar
* al usuario sin Authorization Basic.
*/
function buildPythonHeaders(extra = {}) {
const authHeader = process.env.ACAI_AUTH_HEADER || "";
const mode = resolveCurrentModeOverride();
const role = process.env.ACAI_ROLE_OVERRIDE || "";
const acaiUser = resolveCurrentAcaiUser();
return {
"Content-Type": "application/json",
...(authHeader ? { "Authorization": authHeader } : {}),
...(mode ? { "X-Acai-Mode": mode } : {}),
...(role ? { "X-Acai-Role": role } : {}),
...(acaiUser ? { "X-Acai-User": acaiUser } : {}),
...extra,
};
}
export async function pythonPost(path, data, timeout = 120000) {
const response = await axios.post(`${PYTHON_BASE}${path}`, data, {
headers: buildPythonHeaders(),
timeout,
maxBodyLength: Infinity,
maxContentLength: Infinity,
});
return response.data;
}
export async function pythonGet(path, params = null, timeout = 30000) {
const response = await axios.get(`${PYTHON_BASE}${path}`, {
params: params || undefined,
headers: buildPythonHeaders(),
timeout,
});
return response.data;
}
/**
* GET binario al server Python (p.ej. /api/image-bytes). Devuelve
* { buffer: Buffer, mimeType: string }. Lanza si el status no es 2xx.
*/
export async function pythonGetBinary(path, params = null, timeout = 30000) {
const response = await axios.get(`${PYTHON_BASE}${path}`, {
params: params || undefined,
headers: buildPythonHeaders(),
responseType: "arraybuffer",
timeout,
maxContentLength: Infinity,
});
const mimeType = (response.headers?.["content-type"] || "").split(";")[0].trim()
|| "application/octet-stream";
return { buffer: Buffer.from(response.data), mimeType };
}