Skip to main content
Glama

Smart Code Search MCP Server

browser-mcp.js13.1 kB
/** * Browser MCP Integration * Connects to Playwright MCP server for browser automation and screenshots */ const { Client } = require('@modelcontextprotocol/sdk/client/index.js'); const { StdioClientTransport } = require('@modelcontextprotocol/sdk/client/stdio.js'); class BrowserMCP { constructor() { this.client = null; this.connected = false; this.capabilities = null; } async connect() { try { console.log('Connecting to Playwright MCP server...'); const transport = new StdioClientTransport({ command: 'npx', args: ['-y', '@modelcontextprotocol/server-playwright'], env: { ...process.env } }); this.client = new Client({ name: 'voice-assistant-browser', version: '1.0.0' }, { capabilities: {} }); await this.client.connect(transport); this.connected = true; // Get available tools const tools = await this.client.listTools(); this.capabilities = tools; console.log('✅ Browser MCP connected'); console.log(`Available tools: ${tools.tools?.map(t => t.name).join(', ')}`); return true; } catch (error) { console.error('Failed to connect to Browser MCP:', error); this.connected = false; return false; } } async disconnect() { if (this.client) { await this.client.close(); this.client = null; this.connected = false; console.log('Browser MCP disconnected'); } } isConnected() { return this.connected; } async navigate(url) { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const result = await this.client.callTool('browser_navigate', { url }); return result; } catch (error) { console.error('Navigation failed:', error); throw error; } } async takeScreenshot(options = {}) { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const params = { fullPage: options.fullPage || false, raw: options.raw || false, filename: options.filename }; if (options.element) { params.element = options.element; params.ref = options.ref; } const result = await this.client.callTool('browser_take_screenshot', params); // Extract image data from result if (result.content && result.content[0]) { const content = result.content[0]; if (content.type === 'image') { return { data: content.data, mimeType: content.mimeType || 'image/png' }; } else if (content.type === 'text') { // Base64 encoded image return { data: content.text, mimeType: 'image/png' }; } } throw new Error('No screenshot data received'); } catch (error) { console.error('Screenshot failed:', error); throw error; } } async captureSnapshot() { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const result = await this.client.callTool('browser_snapshot', {}); // Parse snapshot data if (result.content && result.content[0]) { const content = result.content[0]; return { type: 'snapshot', data: content.text || content.data, timestamp: new Date().toISOString() }; } throw new Error('No snapshot data received'); } catch (error) { console.error('Snapshot failed:', error); throw error; } } async click(element, ref) { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const result = await this.client.callTool('browser_click', { element, ref }); return result; } catch (error) { console.error('Click failed:', error); throw error; } } async type(element, ref, text, options = {}) { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const result = await this.client.callTool('browser_type', { element, ref, text, slowly: options.slowly || false, submit: options.submit || false }); return result; } catch (error) { console.error('Type failed:', error); throw error; } } async evaluate(functionStr, element = null, ref = null) { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const params = { function: functionStr }; if (element && ref) { params.element = element; params.ref = ref; } const result = await this.client.callTool('browser_evaluate', params); return result; } catch (error) { console.error('Evaluate failed:', error); throw error; } } async getConsoleMessages() { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const result = await this.client.callTool('browser_console_messages', {}); return result; } catch (error) { console.error('Failed to get console messages:', error); throw error; } } async getNetworkRequests() { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const result = await this.client.callTool('browser_network_requests', {}); return result; } catch (error) { console.error('Failed to get network requests:', error); throw error; } } async waitFor(options = {}) { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const params = {}; if (options.text) params.text = options.text; if (options.textGone) params.textGone = options.textGone; if (options.time) params.time = options.time; const result = await this.client.callTool('browser_wait_for', params); return result; } catch (error) { console.error('Wait failed:', error); throw error; } } async close() { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const result = await this.client.callTool('browser_close', {}); return result; } catch (error) { console.error('Close failed:', error); throw error; } } // Tab management async listTabs() { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const result = await this.client.callTool('browser_tab_list', {}); return result; } catch (error) { console.error('Failed to list tabs:', error); throw error; } } async newTab(url = null) { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const params = {}; if (url) params.url = url; const result = await this.client.callTool('browser_tab_new', params); return result; } catch (error) { console.error('Failed to create new tab:', error); throw error; } } async selectTab(index) { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const result = await this.client.callTool('browser_tab_select', { index }); return result; } catch (error) { console.error('Failed to select tab:', error); throw error; } } async closeTab(index = null) { if (!this.connected) { throw new Error('Browser MCP not connected'); } try { const params = {}; if (index !== null) params.index = index; const result = await this.client.callTool('browser_tab_close', params); return result; } catch (error) { console.error('Failed to close tab:', error); throw error; } } // Utility methods for common tasks async captureFullPage(url, filename) { try { await this.navigate(url); await this.waitFor({ time: 2 }); // Wait for page to load const screenshot = await this.takeScreenshot({ fullPage: true, filename: filename }); return screenshot; } catch (error) { console.error('Full page capture failed:', error); throw error; } } async captureElementScreenshot(url, selector, filename) { try { await this.navigate(url); await this.waitFor({ text: selector }); // Get element reference const snapshot = await this.captureSnapshot(); // Parse snapshot to find element ref (simplified) const screenshot = await this.takeScreenshot({ element: selector, ref: 'element_ref', // Would need to extract from snapshot filename: filename }); return screenshot; } catch (error) { console.error('Element capture failed:', error); throw error; } } async recordPageInteraction(url, actions) { const recording = { url, timestamp: new Date().toISOString(), actions: [], screenshots: [] }; try { await this.navigate(url); for (const action of actions) { switch (action.type) { case 'click': await this.click(action.element, action.ref); break; case 'type': await this.type(action.element, action.ref, action.text, action.options); break; case 'wait': await this.waitFor(action.options); break; case 'screenshot': const screenshot = await this.takeScreenshot(action.options); recording.screenshots.push(screenshot); break; } recording.actions.push({ ...action, timestamp: new Date().toISOString() }); } return recording; } catch (error) { console.error('Recording failed:', error); recording.error = error.message; return recording; } } // Debug helper async getPageInfo() { if (!this.connected) { return { connected: false }; } try { const [console, network, snapshot] = await Promise.all([ this.getConsoleMessages(), this.getNetworkRequests(), this.captureSnapshot() ]); return { connected: true, console, network, snapshot, timestamp: new Date().toISOString() }; } catch (error) { return { connected: true, error: error.message }; } } } // Singleton instance let browserMCPInstance = null; function getBrowserMCP() { if (!browserMCPInstance) { browserMCPInstance = new BrowserMCP(); } return browserMCPInstance; } module.exports = { BrowserMCP, getBrowserMCP };

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/stevenjjobson/scs-mcp'

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