#!/usr/bin/env node import { startStreamableHttpServer } from "./streamable-http.js"; import { BrowserService } from "./browser-service.js"; import { TOOL_DEFINITIONS } from "./tool-definitions.js"; function csv(value) { return (value ?? "").split(",").map((item) => item.trim()).filter(Boolean); } function integer(value, fallback) { const parsed = Number(value); return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback; } const maxSessions = integer(process.env.BROWSER_MCP_MAX_SESSIONS, 16); const browserService = new BrowserService({ allowedOrigins: csv(process.env.BROWSER_MCP_ALLOWED_ORIGINS), maxSessions, defaultTimeoutMs: integer(process.env.BROWSER_MCP_DEFAULT_TIMEOUT_MS, 15000), browserFactory: async () => { const { chromium } = await import("playwright"); return chromium.launch({ headless: true, chromiumSandbox: true }); } }); const calls = { browser_navigate: (args, context) => browserService.navigate(args, context), browser_click: (args, context) => browserService.click(args, context), browser_fill: (args, context) => browserService.fill(args, context), browser_wait: (args, context) => browserService.wait(args, context), browser_snapshot: (args, context) => browserService.snapshot(args, context), browser_screenshot: (args, context) => browserService.screenshot(args, context), browser_console_messages: (args, context) => browserService.consoleMessages(args, context), browser_network_errors: (args, context) => browserService.networkErrors(args, context) }; async function auditedCall(name, args, context) { const event = { timestamp: new Date().toISOString(), server: "browser-mcp", tool: name, subject: context.subject, sessionId: context.sessionId }; try { const result = await calls[name](args, context); process.stderr.write(`${JSON.stringify({ ...event, outcome: "success" })}\n`); return result; } catch (error) { process.stderr.write(`${JSON.stringify({ ...event, outcome: "failure", errorType: error instanceof Error ? error.name : "Error" })}\n`); throw error; } } const listener = await startStreamableHttpServer({ serverName: "browser-mcp", serverVersion: "1.0.0", tools: TOOL_DEFINITIONS, callTool: auditedCall, apiKeys: csv(process.env.BROWSER_MCP_API_KEYS), allowedOrigins: csv(process.env.BROWSER_MCP_CORS_ORIGINS), host: process.env.BROWSER_MCP_HOST ?? "0.0.0.0", port: integer(process.env.BROWSER_MCP_PORT, 3000), maxSessions, sessionTtlMs: integer(process.env.BROWSER_MCP_SESSION_TTL_SECONDS, 1800) * 1000, onSessionClose: ({ id }) => browserService.closeSession(id) }); process.stderr.write(`browser-mcp listening on ${listener.host}:${listener.port}\n`); async function shutdown() { await listener.close(); await browserService.close(); process.exit(0); } process.once("SIGTERM", shutdown); process.once("SIGINT", shutdown);