import { readFileSync } from 'node:fs'; import { readFile } from 'node:fs/promises'; import { phpApi } from './api.mjs'; import { startRelay } from './relay.mjs'; /** * Starts the MCP relay (#429) from the environment. On stein2 it runs in the container * `feuerwerk-mcp` (tools/mcp/compose.yml), in CI beside the PHP server (tools/ci/serve.sh). * * FEUERWERK_MCP_API the API's index.php, as the relay reaches it * FEUERWERK_MCP_KEY_FILE the key both sides share (default data/mcp-relay.key) * FEUERWERK_MCP_ORIGINS the editor's origins, comma-separated * FEUERWERK_MCP_PORT, _HOST where to listen (8090 on all interfaces) * FEUERWERK_MCP_TRUST_PROXY 1: the agent's address is nginx's X-Real-IP * FEUERWERK_MCP_BACKEND pass everything else on to this server (CI) */ const env = process.env; const keyFile = env.FEUERWERK_MCP_KEY_FILE ?? new URL('../../data/mcp-relay.key', import.meta.url); const key = readFileSync(keyFile, 'utf8').trim(); if (key.length < 32) throw new Error('The relay key has to be at least 32 characters'); if (!env.FEUERWERK_MCP_API) throw new Error('FEUERWERK_MCP_API is not set'); const origins = (env.FEUERWERK_MCP_ORIGINS ?? '') .split(',') .map((origin) => origin.trim()) .filter(Boolean); if (origins.length === 0) throw new Error('FEUERWERK_MCP_ORIGINS is not set'); // Read on every use: a deployment that brings new tools needs no restart of the relay. const toolsFile = new URL('../../src/editor/agent/tools.json', import.meta.url); const relay = await startRelay({ port: Number(env.FEUERWERK_MCP_PORT ?? 8090), host: env.FEUERWERK_MCP_HOST ?? '0.0.0.0', api: phpApi(env.FEUERWERK_MCP_API, key), tools: async () => JSON.parse(await readFile(toolsFile, 'utf8')), origins, trustProxy: env.FEUERWERK_MCP_TRUST_PROXY === '1', backend: env.FEUERWERK_MCP_BACKEND || undefined, log: (line) => console.log(`${new Date().toISOString()} ${line}`), }); console.log(`${new Date().toISOString()} relay on port ${relay.port} for ${origins.join(', ')}`); for (const signal of ['SIGTERM', 'SIGINT']) { process.on(signal, () => void relay.close().then(() => process.exit(0))); }