camoufox-mcp-server
Version:
MCP server for browser automation using Camoufox - a privacy-focused Firefox fork with advanced anti-detection features
125 lines (124 loc) • 5.42 kB
JavaScript
import { existsSync, readFileSync } from "node:fs";
export const SERVER_VERSION = "2.0.7";
export const DEFAULT_MAX_CHARS = 30000;
export const MAX_MAX_CHARS = 200000;
export const DEFAULT_MAX_ELEMENTS = 100;
export const MAX_MAX_ELEMENTS = 500;
export const MAX_SEQUENCE_ACTIONS = 25;
export const DEFAULT_ACTION_TIMEOUT_MS = 10000;
export const MAX_GUARDED_REQUESTS = 1024;
export const MAX_EXTRACT_NODES = 50000;
export const GUARD_SETTLE_MS = 100;
export const SESSION_CLOSE_GRACE_MS = 5000;
export const ALLOW_UNSAFE_OPTIONS = process.env.CAMOUFOX_MCP_ALLOW_UNSAFE_OPTIONS === "1";
export const ALLOW_EVALUATE = process.env.CAMOUFOX_MCP_ALLOW_EVALUATE === "1";
export const CAPTCHA_AUTONOMOUS = process.env.CAPTCHA_AUTONOMOUS === "true";
export const NETWORK_SANDBOX_DECLARED = process.env.CAMOUFOX_MCP_NETWORK_SANDBOX === "1";
export const REQUIRE_NETWORK_SANDBOX = process.env.CAMOUFOX_MCP_REQUIRE_NETWORK_SANDBOX === "1";
export const SUPPORTED_OSES = ["windows", "macos", "linux"];
export const DENIED_BROWSER_ARG_FLAGS = new Set([
"--allow-insecure-localhost",
"--allow-running-insecure-content",
"--disable-extensions-except",
"--disable-setuid-sandbox",
"--disable-web-security",
"--host-resolver-rules",
"--ignore-certificate-errors",
"--load-extension",
"--no-proxy-server",
"--no-sandbox",
"--profile",
"--proxy-bypass-list",
"--proxy-pac-url",
"--proxy-server",
"--remote-allow-origins",
"--remote-debugging-address",
"--remote-debugging-pipe",
"--remote-debugging-port",
"--user-data-dir",
"-profile",
]);
export const DENIED_FIREFOX_PREF_KEYS = new Set([
"devtools.chrome.enabled",
"devtools.debugger.prompt-connection",
"devtools.debugger.remote-enabled",
"dom.serviceWorkers.enabled",
"media.peerconnection.enabled",
"network.proxy.allow_hijacking_localhost",
"network.proxy.no_proxies_on",
"security.cert_pinning.enforcement_level",
"security.fileuri.strict_origin_policy",
"security.mixed_content.block_active_content",
]);
export const DENIED_FIREFOX_PREF_PREFIXES = [
"devtools.",
"network.proxy.",
"security.sandbox.",
];
export function readBoundedInteger(name, defaultValue, min, max) {
const raw = process.env[name];
if (raw === undefined) {
return defaultValue;
}
const value = Number.parseInt(raw, 10);
if (!Number.isFinite(value)) {
return defaultValue;
}
return Math.min(max, Math.max(min, value));
}
export const MAX_CONCURRENCY = readBoundedInteger("CAMOUFOX_MCP_MAX_CONCURRENCY", 1, 1, 8);
export const MAX_QUEUE = readBoundedInteger("CAMOUFOX_MCP_MAX_QUEUE", 8, 0, 100);
export const QUEUE_TIMEOUT_MS = readBoundedInteger("CAMOUFOX_MCP_QUEUE_TIMEOUT_MS", 30000, 1000, 300000);
export const LAUNCH_TIMEOUT_MS = readBoundedInteger("CAMOUFOX_MCP_LAUNCH_TIMEOUT_MS", 30000, 1000, 300000);
export const SEQUENCE_TIMEOUT_MS = readBoundedInteger("CAMOUFOX_MCP_SEQUENCE_TIMEOUT_MS", 120000, 1000, 300000);
export const MAX_SCREENSHOT_BYTES = readBoundedInteger("CAMOUFOX_MCP_MAX_SCREENSHOT_BYTES", 5 * 1024 * 1024, 1024, 20 * 1024 * 1024);
export const MAX_SCREENSHOT_WIDTH = readBoundedInteger("CAMOUFOX_MCP_MAX_SCREENSHOT_WIDTH", 1920, 320, 3840);
export const MAX_SCREENSHOT_HEIGHT = readBoundedInteger("CAMOUFOX_MCP_MAX_SCREENSHOT_HEIGHT", 1080, 240, 2160);
export const MAX_SCREENSHOT_AREA = MAX_SCREENSHOT_WIDTH * MAX_SCREENSHOT_HEIGHT;
export const MAX_DIAGNOSTIC_ENTRIES = readBoundedInteger("CAMOUFOX_MCP_MAX_DIAGNOSTIC_ENTRIES", 100, 1, 1000);
export const MAX_DIAGNOSTIC_TEXT_CHARS = readBoundedInteger("CAMOUFOX_MCP_MAX_DIAGNOSTIC_TEXT_CHARS", 2000, 100, 20000);
export const MAX_SESSIONS = readBoundedInteger("CAMOUFOX_MCP_MAX_SESSIONS", 1, 1, 4);
export const SESSION_TTL_MS = readBoundedInteger("CAMOUFOX_MCP_SESSION_TTL_MS", 600000, 300000, 900000);
export function fileContains(path, value) {
try {
return readFileSync(path, "utf8").includes(value);
}
catch {
return false;
}
}
export function isLikelyContainerRuntime() {
return existsSync("/.dockerenv")
|| fileContains("/proc/1/cgroup", "docker")
|| fileContains("/proc/1/cgroup", "kubepods");
}
export function detectNetworkSandboxMode() {
if (NETWORK_SANDBOX_DECLARED && REQUIRE_NETWORK_SANDBOX) {
return "strict-declared";
}
if (NETWORK_SANDBOX_DECLARED) {
return "declared";
}
if (isLikelyContainerRuntime()) {
return "docker";
}
return "unknown";
}
export function buildNetworkSecurityStatus() {
const sandboxMode = detectNetworkSandboxMode();
const warning = sandboxMode === "unknown" || sandboxMode === "docker"
? "SSRF filtering is application-layer best effort. Use container, VM, or firewall egress rules for untrusted URLs. Container detection is not proof of private-network egress filtering."
: undefined;
return {
ssrfPolicy: "app_layer_best_effort",
sandboxMode,
sandboxDeclared: NETWORK_SANDBOX_DECLARED,
strictSandboxRequired: REQUIRE_NETWORK_SANDBOX,
warning,
};
}
export function assertNetworkSandboxPolicy() {
if (REQUIRE_NETWORK_SANDBOX && !NETWORK_SANDBOX_DECLARED) {
throw new Error("CAMOUFOX_MCP_REQUIRE_NETWORK_SANDBOX=1 requires CAMOUFOX_MCP_NETWORK_SANDBOX=1 after configuring container/VM/firewall egress controls.");
}
}