⚠️ Security Notice: MCPBrowser extracts webpage content and provides it to your AI agent (e.g., GitHub Copilot, Claude), which then sends it to the LLM provider it uses (e.g., Anthropic, OpenAI, GitHub) for processing. Make sure you trust both your agent and the LLM provider — especially when accessing pages with sensitive or private data.
MCPBrowser is an MCP browser server that gives AI assistants the ability to browse web pages using a real Chrome, Edge, or Brave browser. This browser-based MCP server lets AI assistants (Claude, Copilot) access any website — especially those protected by authentication, CAPTCHAs, anti-bot restrictions, or requiring JavaScript rendering. Uses your real browser session for web automation, so you log in once, and your AI can navigate, click buttons, fill forms, and extract content from sites that block automated requests.
Built on the Model Context Protocol (MCP), this web browser MCP server works seamlessly with Claude Desktop, Claude Code (CLI), GitHub Copilot, and any MCP-compatible AI assistant. It handles corporate SSO, CAPTCHAs, Cloudflare protection, SPAs, dashboards, and any site that blocks automated requests. Your AI gets the same browser access you have — no special APIs, no headless browser detection, just your authenticated browser session.
Example workflow for AI assistant to use MCPBrowser
1. fetch_webpage → Load the login page
2. type_text → Enter username & password (multiple fields at once)
3. click_element → Click "Sign In"
4. get_current_html → Extract the content after login
- Chrome, Edge, or Brave browser
- Node.js 18+ (includes npm)
Note: Node.js must be installed on your system. The VS Code extension and npm package both require Node.js to run the MCP server. Download from nodejs.org if not already installed.
First, install MCPBrowser with your MCP client.
Standard config works in most tools:
{
"mcpServers": {
"mcpbrowser": {
"command": "npx",
"args": ["-y", "mcpbrowser@latest"]
}
}
}Add via the Amp VS Code extension settings screen or by updating your settings.json file:
"amp.mcpServers": {
"mcpbrowser": {
"command": "npx",
"args": ["-y", "mcpbrowser@latest"]
}
}Amp CLI Setup:
amp mcp add mcpbrowser -- npx -y mcpbrowser@latestUse the Claude Code CLI to add the MCPBrowser MCP server:
claude mcp add mcpbrowser --scope user -- npx -y mcpbrowser@latestVerify it's working:
claude mcp listYou should see:
mcpbrowser: npx -y mcpbrowser@latest - ✓ Connected
Add to your config file:
Windows: %APPDATA%\Claude\claude_desktop_config.json
Mac: ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"mcpbrowser": {
"command": "npx",
"args": ["-y", "mcpbrowser@latest"]
}
}
}Restart Claude Desktop after saving.
Follow the instruction in the section Configuring MCP Servers.
Add the following to your cline_mcp_settings.json file:
{
"mcpServers": {
"mcpbrowser": {
"type": "stdio",
"command": "npx",
"timeout": 30,
"args": ["-y", "mcpbrowser@latest"],
"disabled": false
}
}
}Use the Codex CLI to add the MCPBrowser MCP server:
codex mcp add mcpbrowser npx "-y" "mcpbrowser@latest"Alternatively, create or edit the configuration file ~/.codex/config.toml and add:
[mcp_servers.mcpbrowser]
command = "npx"
args = ["-y", "mcpbrowser@latest"]For more information, see the Codex MCP documentation.
Use the Copilot CLI to interactively add the MCPBrowser MCP server:
/mcp addAlternatively, create or edit the configuration file ~/.copilot/mcp-config.json and add:
{
"mcpServers": {
"mcpbrowser": {
"type": "local",
"command": "npx",
"tools": ["*"],
"args": ["-y", "mcpbrowser@latest"]
}
}
}For more information, see the Copilot CLI documentation.
Or install manually:
Go to Cursor Settings -> MCP -> Add new MCP Server. Name to your liking, use command type with the command npx -y mcpbrowser@latest. You can also verify config or add command like arguments via clicking Edit.
Use the Factory CLI to add the MCPBrowser MCP server:
droid mcp add mcpbrowser "npx -y mcpbrowser@latest"Alternatively, type /mcp within Factory droid to open an interactive UI for managing MCP servers.
For more information, see the Factory MCP documentation.
Follow the MCP install guide, use the standard config above.
Or install manually:
Go to Advanced settings -> Extensions -> Add custom extension. Name to your liking, use type STDIO, and set the command to npx -y mcpbrowser@latest. Click "Add Extension".
Follow the MCP Servers documentation. For example in .kiro/settings/mcp.json:
{
"mcpServers": {
"mcpbrowser": {
"command": "npx",
"args": ["-y", "mcpbrowser@latest"]
}
}
}Or install manually:
Go to Program in the right sidebar -> Install -> Edit mcp.json. Use the standard config above.
Follow the MCP Servers documentation. For example in ~/.config/opencode/opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"mcpbrowser": {
"type": "local",
"command": ["npx", "-y", "mcpbrowser@latest"],
"enabled": true
}
}
}OpenClaw is a personal AI assistant that runs on your devices. Add MCPBrowser using the CLI:
openclaw mcp add mcpbrowser -- npx -y mcpbrowser@latestVerify it's working:
openclaw mcp listFor more information, see the OpenClaw MCP documentation.
Open Qodo Gen chat panel in VSCode or IntelliJ → Connect more tools → + Add new MCP → Paste the standard config above.
Click Save.
Or install manually:
Follow the MCP install guide, use the standard config above. You can also install the MCPBrowser MCP server using the VS Code CLI:
# For VS Code
code --add-mcp '{"name":"mcpbrowser","command":"npx","args":["-y","mcpbrowser@latest"]}'After installation, the MCPBrowser MCP server will be available for use with your GitHub Copilot agent in VS Code.
Install from VS Code Marketplace or run:
code --install-extension cherchyk.mcpbrowserThe extension automatically installs and configures everything for GitHub Copilot.
Go to Settings -> AI -> Manage MCP Servers -> + Add to add an MCP Server. Use the standard config above.
Alternatively, use the slash command /add-mcp in the Warp prompt and paste the standard config from above.
Follow Windsurf MCP documentation. Use the standard config above.
Fetches web pages using your Chrome/Edge browser. Handles authentication, CAPTCHA, SSO, anti-bot protection, and JavaScript-heavy sites. Opens the URL in a browser tab (reuses existing tab for same domain) and waits for the page to fully load before returning content. Automatically detects SPAs (React, Vue, Angular) and waits for JavaScript to render content.
Parameters:
url(string, required) - The URL to fetchremoveUnnecessaryHTML(boolean, optional, default:true) - Remove unnecessary HTML for size reduction by ~90%postLoadWait(number, optional, default:0) - Additional milliseconds to wait after page load before extracting HTML. Use for pages that need extra time to render.
Examples:
// Basic fetch
{ url: "https://example.com" }
// Fetch with extra wait time for slow-rendering pages
{ url: "https://dashboard.example.com", postLoadWait: 2000 }
// Keep full HTML without cleanup
{ url: "https://example.com", removeUnnecessaryHTML: false }Clicks on any clickable element (buttons, links, divs with onclick handlers, etc.). Can target by CSS selector or visible text content. Automatically scrolls element into view and waits for page stability after clicking.
fetch_webpage first.
Parameters:
url(string, required) - The URL of the page (must match a previously fetched page)selector(string, optional) - CSS selector for the element (e.g.,#submit-btn,.login-button)text(string, optional) - Text content to search for if selector not provided (e.g., "Sign In", "Submit")returnHtml(boolean, optional, default:true) - Whether to wait for stability and return HTML after clicking. Set tofalsefor fast form interactions (checkboxes, radio buttons)removeUnnecessaryHTML(boolean, optional, default:true) - Remove unnecessary HTML for size reduction. Only used whenreturnHtmlistruepostClickWait(number, optional, default:1000) - Milliseconds to wait after click for SPAs to render dynamic contentwaitForElementTimeout(number, optional, default:1000) - Maximum time to wait for element in milliseconds
Examples:
// Click by text content
{ url: "https://example.com", text: "Sign In" }
// Click by CSS selector
{ url: "https://example.com", selector: "#login-button" }
// Click without waiting for HTML (fast checkbox toggle)
{ url: "https://example.com", selector: "#agree-checkbox", returnHtml: false }
// Click with custom wait time
{ url: "https://example.com", text: "Load More", postClickWait: 2000 }Types text into one or more input fields in a single call. Supports filling entire forms at once for efficient automation. Automatically clears existing text by default.
fetch_webpage first.
Parameters:
url(string, required) - The URL of the page (must match a previously fetched page)fields(array, required) - Array of fields to fill. Each field object contains:selector(string, required) - CSS selector for the input element (e.g.,#username,input[name="email"])text(string, required) - Text to type into the fieldclear(boolean, optional, default:true) - Whether to clear existing text firstwaitForElementTimeout(number, optional, default:5000) - Maximum time to wait for element in milliseconds
returnHtml(boolean, optional, default:true) - Whether to wait for stability and return HTML after typingremoveUnnecessaryHTML(boolean, optional, default:true) - Remove unnecessary HTML for size reduction. Only used whenreturnHtmlistruepostTypeWait(number, optional, default:1000) - Milliseconds to wait after typing for SPAs to render dynamic content
Examples:
// Fill multiple fields at once (login form)
{
url: "https://example.com/login",
fields: [
{ selector: "#username", text: "john@example.com" },
{ selector: "#password", text: "secretpass123" }
]
}
// Single field input
{ url: "https://example.com", fields: [{ selector: "#search", text: "query" }] }
// Append text without clearing
{ url: "https://example.com", fields: [{ selector: "#notes", text: " additional text", clear: false }] }
// Fast form fill without HTML return
{
url: "https://example.com/signup",
fields: [
{ selector: "#firstName", text: "John" },
{ selector: "#lastName", text: "Doe" },
{ selector: "#email", text: "john@example.com" }
],
returnHtml: false
}Error handling: If a field fails, the response indicates:
- Which field number failed (e.g., "Failed on field 2 of 3")
- Which fields were successfully filled
- Clear guidance to NOT re-type already filled fields
Gets the current HTML from an already-loaded page WITHOUT navigating or reloading. Much faster than fetch_webpage since it only extracts the current DOM state. Use this after interactions (click, type) to get the updated page content efficiently.
fetch_webpage first.
Parameters:
url(string, required) - The URL of the page (must match a previously fetched page)removeUnnecessaryHTML(boolean, optional, default:true) - Remove unnecessary HTML for size reduction by ~90%
Examples:
// Get current HTML after interactions
{ url: "https://example.com" }
// Get full HTML without cleanup
{ url: "https://example.com", removeUnnecessaryHTML: false }Performance comparison:
fetch_webpage: 2-5 seconds (full page reload)get_current_html: 0.1-0.3 seconds (just extracts HTML) ✅
Scrolls within an already-loaded page. Use before take_screenshot to capture different parts of the page, or to bring elements into view before interaction. Supports multiple scroll modes:
- By direction: Scroll up/down/left/right by pixel amount
- To element: Scroll until a specific element is visible
- To position: Scroll to absolute coordinates
fetch_webpage first.
Parameters:
url(string, required) - The URL of the page (must match a previously fetched page)direction(string, optional) - Direction to scroll:up,down,left,right. Use withamount.amount(number, optional, default:500) - Pixels to scroll in the specified direction (~half a viewport)selector(string, optional) - CSS selector of element to scroll into view. Ignores direction/amount.x(number, optional) - Absolute horizontal scroll position. Use withy.y(number, optional) - Absolute vertical scroll position. Use withx.
Examples:
// Scroll down by 500px (default)
{ url: "https://example.com", direction: "down" }
// Scroll down by 1000px
{ url: "https://example.com", direction: "down", amount: 1000 }
// Scroll an element into view
{ url: "https://example.com", selector: "#footer" }
// Scroll to specific position
{ url: "https://example.com", x: 0, y: 2000 }
// Scroll to top of page
{ url: "https://example.com", x: 0, y: 0 }Returns: Current scroll position, page dimensions, and viewport size — useful for understanding where you are on the page.
Takes a screenshot of an already-loaded page for visual analysis. Useful when HTML parsing is insufficient — for example, pages with charts, images, complex layouts, popups, or visual content that's hard to understand from HTML alone. Returns a PNG image.
fetch_webpage first.
Parameters:
url(string, required) - The URL of the page (must match a previously fetched page)fullPage(boolean, optional, default:false) - Capture the full scrollable page instead of just the viewport
Examples:
// Capture viewport screenshot (default)
{ url: "https://example.com" }
// Capture full scrollable page
{ url: "https://dashboard.example.com", fullPage: true }Use cases:
- Visualize page layout when HTML is hard to parse
- Capture charts, graphs, or data visualizations
- Debug popups, modals, or overlays
- Understand visual feedback (highlights, animations)
- See what's blocking an element click
Closes the browser tab for the given URL's hostname. Removes the page from the tab pool and forces a fresh session on the next visit to that hostname. Useful for clearing authentication state, managing memory, or starting fresh with a domain.
www.example.com and example.com are treated as different tabs).
Parameters:
url(string, required) - The URL whose hostname tab should be closed
Examples:
// Close tab for a domain
{ url: "https://example.com" }
// This will close the tab for portal.azure.com
{ url: "https://portal.azure.com/dashboard" }Use cases:
- Clear authentication/session state
- Free up browser memory
- Reset to fresh state before new login
Environment variables for advanced setup:
| Variable | Description | Default |
|---|---|---|
CHROME_PATH |
Path to Chrome/Edge | Auto-detect |
CHROME_USER_DATA_DIR |
Browser profile directory | %LOCALAPPDATA%/ChromeAuthProfile |
CHROME_REMOTE_DEBUG_PORT |
DevTools port | 9222 |
Browser doesn't open?
- Make sure Chrome, Edge, or Brave is installed
- Try setting
CHROME_PATHexplicitly
Can't connect to browser?
- Close all Chrome instances and try again
- Check if port 9222 is in use
Authentication not preserved?
- Keep the browser tab open (default behavior)
- Use the same domain for related requests
Clone and setup:
git clone https://github.com/cherchyk/MCPBrowser.git
cd MCPBrowser
npm run install:all # Installs dependencies for all workspace packagesRun tests:
# Test everything
npm test
# Test MCP server only
npm run test:mcp
# Test extension only
npm run test:extensionMIT