#!/usr/bin/env php getMessage() . PHP_EOL); exit(1); } putenv('MCP_HTTP_PATH=' . $path); if ($debugLog !== null && $debugLog !== '') { putenv('MCP_DEBUG_LOG=' . $debugLog); } $router = __DIR__ . '/../app/mcp-http-router.php'; $command = [ PHP_BINARY, '-S', $host . ':' . $port, $router, ]; fwrite(STDERR, "redMCP HTTP server listening on http://{$host}:{$port}{$path}\n"); fwrite(STDERR, "Authorization: Bearer is required.\n"); if ($debugLog !== null && $debugLog !== '') { fwrite(STDERR, "Debug log: {$debugLog}\n"); } $descriptorSpec = [ 0 => STDIN, 1 => STDOUT, 2 => STDERR, ]; $process = proc_open($command, $descriptorSpec, $pipes); if (!is_resource($process)) { fwrite(STDERR, "Could not start PHP built-in HTTP server.\n"); exit(1); } $status = proc_get_status($process); $pid = (int) ($status['pid'] ?? 0); if ($pid <= 0) { proc_terminate($process); fwrite(STDERR, "Could not determine HTTP server PID.\n"); exit(1); } $pidDir = dirname($pidFile); if ($pidDir !== '' && $pidDir !== '.' && !is_dir($pidDir)) { mkdir($pidDir, 0775, true); } file_put_contents($pidFile, (string) $pid); fwrite(STDERR, "PID file: {$pidFile} ({$pid})\n"); $exitCode = proc_close($process); if (is_file($pidFile) && trim((string) file_get_contents($pidFile)) === (string) $pid) { unlink($pidFile); } exit((int) $exitCode); function showStatus(string $pidFile): void { if (!is_file($pidFile)) { fwrite(STDOUT, "stopped: no PID file at {$pidFile}\n"); return; } $pid = (int) trim((string) file_get_contents($pidFile)); if ($pid > 0 && pidAlive($pid)) { fwrite(STDOUT, "running: PID {$pid} from {$pidFile}\n"); return; } fwrite(STDOUT, "stale: PID file {$pidFile} points to non-running PID {$pid}\n"); } function stopServer(string $pidFile): void { if (!is_file($pidFile)) { fwrite(STDOUT, "stopped: no PID file at {$pidFile}\n"); return; } $pid = (int) trim((string) file_get_contents($pidFile)); if ($pid <= 0 || !pidAlive($pid)) { unlink($pidFile); fwrite(STDOUT, "removed stale PID file {$pidFile}\n"); return; } if (!stopPid($pid)) { fwrite(STDERR, "could not stop PID {$pid}\n"); exit(1); } $deadline = time() + 5; while (pidAlive($pid) && time() < $deadline) { usleep(100000); } if (pidAlive($pid)) { fwrite(STDERR, "PID {$pid} did not stop within timeout\n"); exit(1); } if (is_file($pidFile)) { unlink($pidFile); } fwrite(STDOUT, "stopped PID {$pid}\n"); } function isLivePidFile(string $pidFile): bool { if (!is_file($pidFile)) { return false; } $pid = (int) trim((string) file_get_contents($pidFile)); return $pid > 0 && pidAlive($pid); } function pidAlive(int $pid): bool { if (function_exists('posix_kill')) { return posix_kill($pid, 0); } exec('kill -0 ' . escapeshellarg((string) $pid) . ' 2>/dev/null', $output, $exitCode); return $exitCode === 0; } function stopPid(int $pid): bool { if (function_exists('posix_kill')) { return posix_kill($pid, 15); } exec('kill ' . escapeshellarg((string) $pid) . ' 2>/dev/null', $output, $exitCode); return $exitCode === 0; }