Skip to main content
Glama

Puppeteer Real Browser MCP Server

by withLinda
index.ts•10.9 kB
#!/usr/bin/env node // Debug logging setup - Log process start console.error(`šŸ” [DEBUG] Process starting - PID: ${process.pid}, Node: ${process.version}, Platform: ${process.platform}`); console.error(`šŸ” [DEBUG] Working directory: ${process.cwd()}`); console.error(`šŸ” [DEBUG] Command args: ${process.argv.join(' ')}`); import { Server } from '@modelContextProtocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelContextProtocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListPromptsRequestSchema, InitializeRequestSchema, } from '@modelContextProtocol/sdk/types.js'; console.error('šŸ” [DEBUG] MCP SDK imports completed successfully'); // Import extracted modules console.error('šŸ” [DEBUG] Loading tool definitions...'); import { TOOLS, SERVER_INFO, CAPABILITIES, TOOL_NAMES, NavigateArgs, ClickArgs, TypeArgs, WaitArgs, SolveCaptchaArgs, FindSelectorArgs, SaveContentAsMarkdownArgs } from './tool-definitions.js'; console.error('šŸ” [DEBUG] Loading system utils...'); import { withErrorHandling } from './system-utils.js'; console.error('šŸ” [DEBUG] Loading browser manager...'); import { closeBrowser, forceKillAllChromeProcesses } from './browser-manager.js'; console.error('šŸ” [DEBUG] Loading core infrastructure...'); import { setupProcessCleanup, MCP_SERVER_CONFIG } from './core-infrastructure.js'; // Import handlers console.error('šŸ” [DEBUG] Loading handlers...'); import { handleBrowserInit, handleBrowserClose } from './handlers/browser-handlers.js'; import { handleNavigate, handleWait } from './handlers/navigation-handlers.js'; import { handleClick, handleType, handleSolveCaptcha, handleRandomScroll } from './handlers/interaction-handlers.js'; import { handleGetContent, handleFindSelector } from './handlers/content-handlers.js'; import { handleSaveContentAsMarkdown } from './handlers/file-handlers.js'; console.error('šŸ” [DEBUG] All modules loaded successfully'); console.error(`šŸ” [DEBUG] Server info: ${JSON.stringify(SERVER_INFO)}`); console.error(`šŸ” [DEBUG] Available tools: ${TOOLS.length} tools loaded`); // Initialize MCP server console.error('šŸ” [DEBUG] Creating MCP server instance...'); const server = new Server(SERVER_INFO, { capabilities: CAPABILITIES }); console.error('šŸ” [DEBUG] MCP server instance created successfully'); // Register initialize handler (CRITICAL - missing handler can cause crash) console.error('šŸ” [DEBUG] Registering initialize handler...'); server.setRequestHandler(InitializeRequestSchema, async (request) => { console.error(`šŸ” [DEBUG] Initialize request received: ${JSON.stringify(request)}`); // Use the client's protocol version to ensure compatibility const clientProtocolVersion = request.params.protocolVersion; console.error(`šŸ” [DEBUG] Client protocol version: ${clientProtocolVersion}`); const response = { protocolVersion: clientProtocolVersion, // Match client version for compatibility capabilities: CAPABILITIES, serverInfo: SERVER_INFO, }; console.error(`šŸ” [DEBUG] Sending initialize response: ${JSON.stringify(response)}`); // Add a small delay to see if there are any immediate errors after response setTimeout(() => { console.error(`šŸ” [DEBUG] 1 second after initialize response - server still alive`); }, 1000); setTimeout(() => { console.error(`šŸ” [DEBUG] 5 seconds after initialize response - server still alive`); }, 5000); return response; }); // Register tool handlers console.error('šŸ” [DEBUG] Registering tools handler...'); server.setRequestHandler(ListToolsRequestSchema, async () => { console.error('šŸ” [DEBUG] Tools list requested'); return { tools: TOOLS }; }); // Register resource handlers (placeholder) console.error('šŸ” [DEBUG] Registering resources handler...'); server.setRequestHandler(ListResourcesRequestSchema, async () => { console.error('šŸ” [DEBUG] Resources list requested'); return { resources: [] }; }); // Register prompt handlers (placeholder) console.error('šŸ” [DEBUG] Registering prompts handler...'); server.setRequestHandler(ListPromptsRequestSchema, async () => { console.error('šŸ” [DEBUG] Prompts list requested'); return { prompts: [] }; }); // Main tool call handler console.error('šŸ” [DEBUG] Registering tool call handler...'); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; console.error(`šŸ” [DEBUG] Tool call received: ${name} with args: ${JSON.stringify(args)}`); try { switch (name) { case TOOL_NAMES.BROWSER_INIT: return await handleBrowserInit(args || {}); case TOOL_NAMES.NAVIGATE: return await handleNavigate(args as unknown as NavigateArgs); case TOOL_NAMES.GET_CONTENT: return await handleGetContent(args || {}); case TOOL_NAMES.CLICK: return await handleClick(args as unknown as ClickArgs); case TOOL_NAMES.TYPE: return await handleType(args as unknown as TypeArgs); case TOOL_NAMES.WAIT: return await handleWait(args as unknown as WaitArgs); case TOOL_NAMES.BROWSER_CLOSE: return await handleBrowserClose(); case TOOL_NAMES.SOLVE_CAPTCHA: return await handleSolveCaptcha(args as unknown as SolveCaptchaArgs); case TOOL_NAMES.RANDOM_SCROLL: return await handleRandomScroll(); case TOOL_NAMES.FIND_SELECTOR: return await handleFindSelector(args as unknown as FindSelectorArgs); case TOOL_NAMES.SAVE_CONTENT_AS_MARKDOWN: return await handleSaveContentAsMarkdown(args as unknown as SaveContentAsMarkdownArgs); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error(`Tool ${name} failed:`, errorMessage); return { content: [ { type: 'text', text: `āŒ Tool execution failed: ${errorMessage}`, }, ], isError: true, }; } }); // Main function to start the server async function main(): Promise<void> { console.error('šŸ” [DEBUG] Main function starting...'); // Setup process cleanup handlers console.error('šŸ” [DEBUG] Setting up process cleanup handlers...'); setupProcessCleanup(async () => { console.error('šŸ” [DEBUG] Process cleanup triggered'); await closeBrowser(); await forceKillAllChromeProcesses(); }); // Create and start the server transport console.error('šŸ” [DEBUG] Creating StdioServerTransport...'); const transport = new StdioServerTransport(); console.error('šŸ” [DEBUG] StdioServerTransport created successfully'); await withErrorHandling(async () => { console.error('šŸ” [DEBUG] Attempting to connect server to transport...'); await server.connect(transport); console.error('šŸ” [DEBUG] Server connected to transport successfully'); console.error('šŸš€ Puppeteer Real Browser MCP Server started successfully'); console.error('šŸ“‹ Available tools:', TOOLS.map(t => t.name).join(', ')); console.error('šŸ”§ Workflow validation: Active'); console.error('šŸ’” Content priority mode: Enabled (use get_content for better reliability)'); console.error('šŸ” [DEBUG] Server is now ready and waiting for requests...'); // Keep the process alive by maintaining the connection console.error('šŸ” [DEBUG] Maintaining process alive - server will wait for requests'); // Add a heartbeat to confirm the process is still running const heartbeat = setInterval(() => { console.error(`šŸ” [DEBUG] Heartbeat - Server alive at ${new Date().toISOString()}`); }, 30000); // Every 30 seconds // Cleanup heartbeat on process exit process.on('exit', () => { console.error('šŸ” [DEBUG] Process exiting - clearing heartbeat'); clearInterval(heartbeat); }); }, 'Failed to start MCP server'); console.error('šŸ” [DEBUG] Main function completed - server should be running'); } // Enhanced error handling with debug info console.error('šŸ” [DEBUG] Setting up error handlers...'); process.on('uncaughtException', (error) => { console.error(`šŸ” [DEBUG] Uncaught exception at ${new Date().toISOString()}`); console.error('āŒ Uncaught exception:', error); console.error(`šŸ” [DEBUG] Stack trace:`, error.stack); process.exit(1); }); process.on('unhandledRejection', (reason, promise) => { console.error(`šŸ” [DEBUG] Unhandled rejection at ${new Date().toISOString()}`); console.error('āŒ Unhandled rejection:', reason); console.error(`šŸ” [DEBUG] Promise:`, promise); process.exit(1); }); // Process lifecycle debugging process.on('exit', (code) => { console.error(`šŸ” [DEBUG] Process exiting with code: ${code} at ${new Date().toISOString()}`); }); process.on('beforeExit', (code) => { console.error(`šŸ” [DEBUG] Before exit event with code: ${code} at ${new Date().toISOString()}`); }); process.on('SIGTERM', () => { console.error(`šŸ” [DEBUG] SIGTERM received at ${new Date().toISOString()}`); }); process.on('SIGINT', () => { console.error(`šŸ” [DEBUG] SIGINT received at ${new Date().toISOString()}`); }); console.error('šŸ” [DEBUG] All error handlers registered'); // Start the server console.error('šŸ” [DEBUG] Checking if module is main...'); console.error(`šŸ” [DEBUG] import.meta.url: ${import.meta.url}`); console.error(`šŸ” [DEBUG] process.argv[1]: ${process.argv[1]}`); console.error(`šŸ” [DEBUG] process.argv[0]: ${process.argv[0]}`); // Enhanced main module detection for npx compatibility const isMain = import.meta.url === `file://${process.argv[1]}` || process.argv[1].includes('puppeteer-real-browser-mcp-server') || process.argv[1].endsWith('.bin/puppeteer-real-browser-mcp-server') || process.argv.some(arg => arg.includes('puppeteer-real-browser-mcp-server')); console.error(`šŸ” [DEBUG] Enhanced main detection result: ${isMain}`); if (isMain) { console.error('šŸ” [DEBUG] Module is main - starting server...'); main().catch((error) => { console.error(`šŸ” [DEBUG] Main function failed at ${new Date().toISOString()}`); console.error('āŒ Failed to start server:', error); console.error(`šŸ” [DEBUG] Error stack:`, error.stack); process.exit(1); }); } else { console.error('šŸ” [DEBUG] Module is not main - not starting server'); console.error('šŸ” [DEBUG] FORCE STARTING - This is likely an npx execution'); main().catch((error) => { console.error(`šŸ” [DEBUG] Forced main function failed at ${new Date().toISOString()}`); console.error('āŒ Failed to start server:', error); console.error(`šŸ” [DEBUG] Error stack:`, error.stack); process.exit(1); }); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/withLinda/puppeteer-real-browser-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server