Skip to main content
Glama
RomanGod6

Browser Testing MCP Server

by RomanGod6
browser_testing_mcp.py9.17 kB
#!/usr/bin/env python3 """ Browser Testing MCP Server """ import asyncio import json import base64 import sys from typing import Any, Dict, List, Optional from datetime import datetime from mcp import types from mcp.server import Server from mcp.server.stdio import stdio_server from playwright.async_api import async_playwright, Browser, BrowserContext, Page # Global browser state browser_state = { "browser": None, "context": None, "page": None, "playwright": None, "console_logs": [] } # Create the MCP server server = Server("browser-testing", version="1.0.0") @server.list_tools() async def list_tools() -> list[types.Tool]: """List available browser testing tools.""" return [ types.Tool( name="launch_browser", description="Launch a new browser instance", inputSchema={ "type": "object", "properties": { "headless": { "type": "boolean", "description": "Run in headless mode", "default": False } } } ), types.Tool( name="navigate_to", description="Navigate to a URL", inputSchema={ "type": "object", "properties": { "url": { "type": "string", "description": "URL to navigate to" } }, "required": ["url"] } ), types.Tool( name="click_element", description="Click on an element", inputSchema={ "type": "object", "properties": { "selector": { "type": "string", "description": "CSS selector" } }, "required": ["selector"] } ), types.Tool( name="type_text", description="Type text into an input field", inputSchema={ "type": "object", "properties": { "selector": { "type": "string", "description": "CSS selector" }, "text": { "type": "string", "description": "Text to type" } }, "required": ["selector", "text"] } ), types.Tool( name="get_console_logs", description="Get browser console logs", inputSchema={ "type": "object", "properties": {} } ), types.Tool( name="take_screenshot", description="Take a screenshot of the current page", inputSchema={ "type": "object", "properties": {} } ), types.Tool( name="get_page_content", description="Get the HTML content of the page", inputSchema={ "type": "object", "properties": {} } ), types.Tool( name="close_browser", description="Close the browser", inputSchema={ "type": "object", "properties": {} } ) ] @server.call_tool() async def call_tool(name: str, arguments: dict) -> list[types.TextContent]: """Execute browser testing tools.""" try: if name == "launch_browser": headless = arguments.get("headless", False) # Close existing browser if any if browser_state["browser"]: await browser_state["browser"].close() try: # Launch new browser browser_state["playwright"] = await async_playwright().start() browser_state["browser"] = await browser_state["playwright"].chromium.launch(headless=headless) browser_state["context"] = await browser_state["browser"].new_context() browser_state["page"] = await browser_state["context"].new_page() # Set up console logging browser_state["console_logs"] = [] browser_state["page"].on("console", lambda msg: browser_state["console_logs"].append({ "type": msg.type, "text": msg.text, "timestamp": datetime.now().isoformat() })) return [types.TextContent(type="text", text="Browser launched successfully")] except Exception as e: error_msg = str(e) if "Executable doesn't exist" in error_msg: return [types.TextContent(type="text", text="Error: Playwright browsers not installed. Please run: playwright install chromium")] elif "Host system is missing dependencies" in error_msg or "missing dependencies" in error_msg: return [types.TextContent(type="text", text="Error: System dependencies missing. Please run: sudo playwright install-deps")] else: return [types.TextContent(type="text", text=f"Error launching browser: {error_msg}")] elif name == "navigate_to": if not browser_state["page"]: return [types.TextContent(type="text", text="Error: Browser not launched. Call launch_browser first.")] url = arguments["url"] await browser_state["page"].goto(url) return [types.TextContent(type="text", text=f"Navigated to {url}")] elif name == "click_element": if not browser_state["page"]: return [types.TextContent(type="text", text="Error: Browser not launched. Call launch_browser first.")] selector = arguments["selector"] await browser_state["page"].click(selector) return [types.TextContent(type="text", text=f"Clicked element: {selector}")] elif name == "type_text": if not browser_state["page"]: return [types.TextContent(type="text", text="Error: Browser not launched. Call launch_browser first.")] selector = arguments["selector"] text = arguments["text"] await browser_state["page"].type(selector, text) return [types.TextContent(type="text", text=f"Typed text into: {selector}")] elif name == "get_console_logs": logs = json.dumps(browser_state["console_logs"], indent=2) return [types.TextContent(type="text", text=logs)] elif name == "take_screenshot": if not browser_state["page"]: return [types.TextContent(type="text", text="Error: Browser not launched. Call launch_browser first.")] screenshot = await browser_state["page"].screenshot() base64_img = base64.b64encode(screenshot).decode('utf-8') # Return truncated version for display return [types.TextContent(type="text", text=f"Screenshot taken. Base64 data: {base64_img[:100]}...")] elif name == "get_page_content": if not browser_state["page"]: return [types.TextContent(type="text", text="Error: Browser not launched. Call launch_browser first.")] content = await browser_state["page"].content() return [types.TextContent(type="text", text=content)] elif name == "close_browser": if browser_state["browser"]: await browser_state["browser"].close() browser_state["browser"] = None if browser_state["playwright"]: await browser_state["playwright"].stop() browser_state["playwright"] = None return [types.TextContent(type="text", text="Browser closed")] else: return [types.TextContent(type="text", text=f"Unknown tool: {name}")] except Exception as e: return [types.TextContent(type="text", text=f"Error: {str(e)}")] async def main(): """Run the MCP server.""" async with stdio_server() as (read_stream, write_stream): try: await server.run(read_stream, write_stream, server.create_initialization_options()) finally: # Clean up browser if still open if browser_state["browser"]: await browser_state["browser"].close() if browser_state["playwright"]: await browser_state["playwright"].stop() if __name__ == "__main__": try: asyncio.run(main()) except KeyboardInterrupt: print("\nServer stopped", file=sys.stderr) except Exception as e: print(f"Server error: {e}", file=sys.stderr) sys.exit(1)

Latest Blog Posts

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/RomanGod6/browserbot'

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