Files
agenticSystem/mcp-server/stdio.js
2026-04-08 23:52:54 +00:00

99 lines
3.8 KiB
JavaScript

/**
* Acai Code MCP Server - Stdio Entry Point
*
* Used when Claude Code launches the MCP server directly via .mcp.json.
* Reads credentials from the local Python server on each tool call.
*/
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { createMcpServer } from "./server.js";
import { registerPrompts } from "./prompts/index.js";
import { registerTools } from "./tools/index.js";
import { registerResources } from "./resources/index.js";
import { sessionCredentials } from "./auth/credentials.js";
import { fetchProjectInfo } from "./auth/localClient.js";
// Create server instance
const server = createMcpServer();
registerPrompts(server);
registerTools(server);
registerResources(server);
const projectDir = process.env.ACAI_PROJECT_DIR || "";
// Aplica vars de override de entorno (usado por cronjobs para forzar el
// entorno objetivo sin tocar el .acai del proyecto). Modifica creds in-place.
function applyEnvironmentOverride(creds) {
const modeOverride = process.env.ACAI_MODE_OVERRIDE;
if (!modeOverride) return creds;
creds.mode = modeOverride;
if (process.env.ACAI_WEB_URL_OVERRIDE) creds.web_url = process.env.ACAI_WEB_URL_OVERRIDE;
if (process.env.ACAI_API_WEB_URL_OVERRIDE) creds.api_web_url = process.env.ACAI_API_WEB_URL_OVERRIDE;
if (process.env.ACAI_FORGE_HOST_OVERRIDE !== undefined) {
creds.forge_host = process.env.ACAI_FORGE_HOST_OVERRIDE;
}
return creds;
}
async function readFreshCredentials() {
if (projectDir) {
try {
const data = await fetchProjectInfo({ project_dir: projectDir });
if (data?.success) {
return applyEnvironmentOverride({
token: data.token || "",
tokenHash: data.tokenHash || "",
website: data.domain || "",
web_url: data.web_url || "",
api_web_url: data.api_web_url || data.web_url || "",
forge_host: data.forge_host || "",
mode: data.mode || "local",
profileName: "stdio",
role: "developer",
});
}
} catch (error) {
console.error(`[MCP stdio] Failed to resolve project-info: ${error.message}`);
}
}
return applyEnvironmentOverride({
token: process.env.ACAI_TOKEN || "",
tokenHash: process.env.ACAI_TOKEN_HASH || "",
website: process.env.ACAI_WEBSITE || "",
web_url: process.env.ACAI_WEB_URL || "",
api_web_url: process.env.ACAI_API_WEB_URL || "",
forge_host: process.env.ACAI_FORGE_HOST || "",
mode: process.env.ACAI_MODE || "local",
profileName: "stdio-fallback",
role: "developer",
});
}
const initialCreds = await readFreshCredentials();
if (!initialCreds.web_url) {
console.error("[MCP stdio] WARNING: No ACAI_WEB_URL in environment. Tools will fail.");
}
// Set initial credentials
sessionCredentials.set("_default", initialCreds);
// Intercept tool calls to refresh credentials from the Python server before each call
const _origSetHandler = server.server.setRequestHandler;
server.server.setRequestHandler = (schema, handler) => {
return _origSetHandler.call(server.server, schema, async (request, extra) => {
const freshCreds = await readFreshCredentials();
sessionCredentials.set("_default", freshCreds);
if (extra?.sessionId) {
sessionCredentials.set(extra.sessionId, freshCreds);
}
return handler(request, extra);
});
};
// Connect via stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);
console.error(`[MCP stdio] Connected — ${initialCreds.website}${initialCreds.web_url} (project: ${projectDir})`);