mcpField
M
MCP Browser

MCP Browser

Local
github.comBrowser Automation9Updated 2w ago

About MCP Browser

MCPBrowser is an MCP server that lets AI assistants browse and interact with websites through a user's Chrome, Edge, or Brave session. It targets authenticated and JavaScript-heavy pages, returning cleaned HTML and offering browser controls and script execution.

Key features

  1. 01Uses an existing browser session
  2. 02Handles SSO, CAPTCHA, and anti-bot protections
  3. 03Detects SPAs and waits for rendering
  4. 04Executes JavaScript in the page
  5. 05Cleans HTML and reuses domain tabs

Use cases

  1. 01Access pages that require sign-in
  2. 02Extract structured data from dynamic pages
  3. 03Interact with web apps and forms

MCP support

This stdio MCP server exposes browser navigation, JavaScript execution, clicking, typing, scrolling, screenshots, and HTML extraction to MCP clients. It uses Chrome, Edge, or Brave.

Configuration

Local server config is the same for every client. Copy it into your client’s MCP config file.

mcp.json · Universal config
{
"mcpServers": {
"cherchyk-mcpbrowser": {
"command": "npx",
"args": [
"-y",
"mcpbrowser"
]
}
}
}
Run commandnpx -y mcpbrowser

Local servers need a runtime on your machine (e.g. Node.js 18+). Config file locations differ by client; see your client’s docs.

Packages
npmmcpbrowser0.4.6

Tools

1

Saved tool list · updated 2w ago

ParameterTypeRequiredDescription
urlstringYesThe URL to fetch
keepPageOpenbooleanNoKeep the tab open after fetching for manual auth or reuse (default: true)

Details

From the project README

✅ MCPBrowser (MCP Browser)

VS Code Marketplace npm version Claude Desktop License: MIT

⚠️ Security Notice: MCPBrowser extracts webpage content and provides it to your AI agent (e.g., GitHub Copilot, Claude, Kiro, Antigravity), 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 combines private data access, untrusted content exposure, and external communication (the MCP "lethal trifecta") — all tool annotations accurately declare these risks so MCP clients can enforce appropriate safety controls. See MCP_COMPLIANCE.md for details.

💡 Why MCPBrowser over Puppeteer/Playwright MCP servers? Puppeteer and Playwright are browser automation libraries — their MCP servers give agents raw, low-level browser commands. MCPBrowser uses Puppeteer under the hood and was built specifically for AI agents, adding an intelligence layer that handles the hard parts automatically.

The agent gets clean HTML (90% smaller), automatic SPA detection (React, Vue, Angular), authentication flow handling (SSO, redirects, multi-step login), form discovery with multi-field filling, structured responses with next-step guidance, domain-based tab reuse, and instant DOM re-extraction without page reloads. Each MCPBrowser tool call replaces 5-8 raw browser automation calls — a typical 4-step workflow in MCPBrowser would take 20+ calls with Puppeteer/Playwright MCP, saving tokens and making the agent significantly faster. See full comparison below.

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 fetches any web page — especially those protected by authentication, CAPTCHAs, anti-bot protection, or requiring JavaScript rendering. Uses your real browser for web automation so you can log in normally, then automatically extracts content. Works with corporate SSO, login forms, Cloudflare, and JavaScript-heavy sites (SPAs, dashboards).

This is an MCP (Model Context Protocol) server using stdio transport. Your AI assistant uses this web browser MCP server when standard HTTP requests fail — pages requiring authentication, CAPTCHA protection, or heavy JavaScript (SPAs). Once connected, the browser MCP server can navigate through websites, interact with elements, and send HTML back to the AI assistant. This gives your AI the ability to browse the web just like you do.

Example workflow for AI assistant to use MCPBrowser

1. browser_fetch_webpage    → Load the login page
2. browser_type_text        → Enter username and password (multiple fields at once)
3. browser_click_element    → Click "Sign In"
4. browser_get_current_html → Extract the content after login

Why MCPBrowser over Puppeteer/Playwright MCP servers?

Puppeteer and Playwright are browser automation libraries — their MCP servers expose low-level browser commands and the agent has to handle SPAs, auth flows, messy HTML, and edge cases on its own. MCPBrowser was built specifically for AI agents. It uses Puppeteer under the hood and adds an intelligence layer so the agent can focus on the task instead of fighting the browser.

MCPBrowserPuppeteer/Playwright MCP
HTML outputClean, LLM-optimized (~90% smaller) — strips scripts, styles, SVGs, tracking attrs, converts relative URLsRaw DOM
SPA supportAuto-detects React, Vue, Angular, Svelte, Next.js, Nuxt — applies framework-aware wait strategiesAgent must configure waits manually
AuthenticationDetects login pages, SSO redirects, multi-step auth — follows redirect chains, two-phase timeouts (5s SSO → 20min manual)Agent must script each auth step
Form interactionbrowser_detect_forms discovers all fields, labels, constraints; browser_type_text fills multiple fields at onceOne field at a time, manual selectors
Response formatTyped, structured with nextSteps guidance — soft vs hard failure distinction with recovery actionsRaw results, generic errors
Tab managementDomain-pooled — reuses tabs, survives browser reconnectionNew context per request
DOM re-extractionbrowser_get_current_html — instant, no reload (10-50x faster)Must re-fetch full page
Plugin systemDetects known sites by URL/DOM patterns, offers site-specific actions with confidence scoringN/A
Built forAI agentsBrowser test automation
Agent efficiency1 tool call replaces 5-8 raw browser calls — a 4-step login flow takes 4 calls instead of 20+, saving tokens and round-tripsEach step (navigate, wait, query, type, click) is a separate call

Contents

Requirements

  • 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.

Installation

#PlatformDifficulty
1VS Code ExtensionOne Click
2Claude CodeOne Command
3OpenClawOne Command
4Claude DesktopManual
5npm PackageManual
Option 1: VS Code Extension

Install from VS Code Marketplace or Open VSX Registry, or run:

code --install-extension cherchyk.mcpbrowser

The extension automatically installs and configures everything for your AI agent (GitHub Copilot, Kiro Agent, Antigravity Agent). Also works with VSCodium and other Open VSX-compatible editors.

Option 2: Claude Code
claude mcp add mcpbrowser --scope user -- npx -y mcpbrowser@latest

Verify it's working:

claude mcp list

You should see:

mcpbrowser: npx -y mcpbrowser@latest - ✓ Connected

That's it! Ask Claude to fetch any protected page:

"Fetch https://portal.azure.com using mcpbrowser"

Option 3: OpenClaw

OpenClaw is a personal AI assistant that runs on your devices. Add MCPBrowser to give it browser automation capabilities:

openclaw mcp add mcpbrowser -- npx -y mcpbrowser@latest

Verify it's working:

openclaw mcp list

Now OpenClaw can browse authenticated pages, fill forms, and interact with web apps using your existing browser sessions.

Option 4: Claude Desktop

Add to your config file (create it if it doesn't exist):

Windows: %APPDATA%\Claude\claude_desktop_config.json (e.g., C:\Users\<username>\AppData\Roaming\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.

Option 5: npm Package

For VS Code, Kiro, Antigravity, or other editors — manual MCP setup. Add to your mcp.json:

Windows: %APPDATA%\Code\User\mcp.json Mac/Linux: ~/.config/Code/User/mcp.json

{
  "servers": {
    "MCPBrowser": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "mcpbrowser@latest"]
    }
  }
}

MCP Tools

browser_fetch_webpage

Fetches web pages using your Chrome/Edge/Brave 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 fetch
  • removeUnnecessaryHTML (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 }

browser_execute_javascript

Executes a JavaScript snippet in the active page context and returns the result with metadata (execution time, truncation flag, URL-change flag). Use this for structured extraction (e.g., inbox rows) or JS-driven UI actions that are unreliable via protocol clicks.

⚠️ Note: Page must be already loaded via browser_fetch_webpage first.

Parameters:

  • url (string, required) - The URL of the page (must match a previously fetched page)
  • script (string, required) - JavaScript source to execute in the page context
  • timeoutMs (number, optional, default: 30000, max: 60000) - Execution timeout
  • returnType (string, optional, default: json) - json | text | void

Returns: Serialized result (outerHTML for DOM nodes), type, executionTimeMs, truncated, urlChanged, currentUrl, and structured error when the script throws or times out.

Example:

{
  "action": "browser_execute_javascript",
  "url": "https://mail.google.com/",
  "script": "[...document.querySelectorAll('tr.zA')].slice(0,5).map((row,i)=>({index:i+1,sender:row.querySelector('.zF,.yP')?.textContent,subject:row.querySelector('.bog')?.textContent}))",
  "timeoutMs": 30000,
  "returnType": "json"
}

browser_click_element

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.

⚠️ Note: Page must be already loaded via browser_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 to false for fast form interactions (checkboxes, radio buttons)
  • removeUnnecessaryHTML (boolean, optional, default: true) - Remove unnecessary HTML for size reduction. Only used when returnHtml is true
  • postClickWait (number, optional, default: 1000) - Milliseconds to wait after click for SPAs to render dynamic content
  • waitForElementTimeout (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 }

Fallback behavior: If the native click times out after locating the element, MCPBrowser automatically retries with a JavaScript-based click and returns fallbackUsed, nativeAttempt, and fallbackAttempt metadata. If both attempts fail, the response lists both errors so you can choose another strategy.


browser_type_text

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.

⚠️ Note: Page must be already loaded via browser_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 field
    • clear (boolean, optional, default: true) - Whether to clear existing text first
    • waitForElementTimeout (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 typing
  • removeUnnecessaryHTML (boolean, optional, default: true) - Remove unnecessary HTML for size reduction. Only used when returnHtml is true
  • postTypeWait (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: "[email protected]" },
    { 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: "[email protected]" }
  ],
  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

browser_get_current_html

Gets the current HTML from an already-loaded page WITHOUT navigating or reloading. Much faster than browser_fetch_webpage since it only extracts the current DOM state. Use this after interactions (click, type) to get the updated page content efficiently.

⚠️ Note: Page must be already loaded via browser_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:

  • browser_fetch_webpage: 2-5 seconds (full page reload)
  • browser_get_current_html: 0.1-0.3 seconds (just extracts HTML) ✅

browser_scroll_page

Scrolls within an already-loaded page. Use before browser_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

⚠️ Note: Page must be already loaded via browser_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 with amount.
  • 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 with y.
  • y (number, optional) - Absolute vertical scroll position. Use with x.

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.


browser_take_screenshot

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.

⚠️ Note: Page must be already loaded via browser_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

browser_close_tab

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.

⚠️ Note: Uses exact hostname match (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

Microsoft Word Online Plugin

The enabled word plugin reads and replaces content in authenticated Word Online documents hosted by SharePoint or OneDrive. Open the document with browser_fetch_webpage, then discover or run actions through browser_plugin_info and browser_plugin_action.

ActionPurpose
open_documentOpen a document URL, safely promote the SharePoint-hosted editor, and verify edit/view mode
read_documentReturn bounded rendered document text and structural metadata
replace_document_textReplace the entire document with plain text
replace_document_htmlReplace the entire document with sanitized rich HTML and a plain-text fallback
insert_document_textPrepend or append plain text without replacing existing content
insert_document_htmlPrepend or append sanitized rich HTML without replacing existing content
import_markdownImport a local Markdown file and local images by absolute file path
export_markdownExport the complete document to a local Markdown path and sibling image folder
find_textSearch the full document with optional case and whole-word matching
replace_textSurgically replace one occurrence or every occurrence using Word's native document model
get_document_infoRead title, mode, word count, rendered layout, and save state
get_outlineRead Word's native heading outline
read_rangeNavigate to a heading and read rendered paragraph ranges
get_text_contextInspect native search context for one occurrence
insert_atInsert text before or after an exact occurrence
replace_range / delete_rangeReplace or delete one anchored occurrence
format_rangeApply bold, italic, underline, or strikethrough to anchored text
list_tables / read_table / update_table_cellInspect and safely update rendered tables
list_links / add_link / update_link / remove_linkInspect and edit rendered hyperlinks
list_comments / add_comment / resolve_commentWork with Word comments
get_stateReport editor mode, layout counts, bounded text checks, and Word's save signal
wait_for_saveRequire stable layout, optional prefix/suffix matches, and Word's confirmed Saved state
close_documentConfirm save, then close the Word tab

Supported entry points include https://word.cloud.microsoft/, HTTPS SharePoint/OneDrive Word links, and Word editor hosts under *.officeapps.live.com. The plugin uses the existing browser session; complete sign-in, MFA, or consent directly in the browser.

Rich HTML updates remove active content, event handlers, embedded resources, forms, images, and unsafe URL schemes before dispatch. import_markdown is the exception for images: it reads supported local image files referenced by the Markdown, validates their type and size, and embeds them through the bounded Word clipboard operation. Remote and data URL images in Markdown input are rejected. Source and verification content is processed in memory, not returned by mutation actions. The plugin does not expose SharePoint WOPI access tokens, cookies, or authorization headers.

Use import_markdown with an absolute sourcePath and placement of replace, start, or end. Large documents are split at Markdown block boundaries rather than being sent through the MCP request. Use export_markdown with an absolute outputPath; for D:\docs\guide.md, extracted images are written to D:\docs\guide.assets\ with their Word-provided names preserved when available. The action returns paths, counts, and unresolved-image metadata rather than the exported content. Existing Markdown files are not replaced unless overwrite is true.

Imports and whole-document text/HTML edits use native keyboard navigation and compare Word's full-document clipboard text with the expected result before reporting success or inserting the next chunk. replace_text, replace_range, delete_range, and their table/anchored-text callers also verify the expected text while retaining unrelated content. A paste event acknowledgement or a Replace button click is not proof of a change. Verification retries transient unavailable clipboard reads, scales its bounded clipboard and polling waits with the expected document size, and normalizes layout whitespace; this is not proof of rich formatting, image fidelity, comment anchors, or persistence. Inspect built-in Normal/Heading styles and rich content separately, then use wait_for_save. If full text cannot be copied, these edits refuse to proceed and report the last clipboard-read reason when available.

An unverified mutation reports an unknown outcome rather than claiming the document was unchanged. A partial import identifies the stopped chunk and the number of chunks whose resulting text was verified. Do not automatically repeat or append after an error or MCP timeout: inspect the affected content and save state first. Automatic resume and cross-session operation tracking are not implemented.

Run Word actions sequentially. Within one server process, overlapping Word plugin actions are rejected as busy, including reads that move focus, navigate, or select text. The guard is held until the active action settles, even if its caller times out. Separate MCPBrowser processes, generic browser tools, and human/coauthor input are not coordinated by this guard; avoid editing the same document concurrently.

read_document supports offset and maxCharacters for chunked reading. It reflects Word's currently rendered pages and reports mayBePartial: true because Word virtualizes large documents. wait_for_save fails rather than assuming persistence when Word's save indicator is unavailable.

For large documents, prefer find_text and replace_text over reading and rebuilding the file. replace_text preserves unaffected content and formatting, supports a 1-based occurrence or replaceAll, and can require expectedMatchCount so ambiguous or stale edits fail without changing the document.

For “update Word according to Markdown changes,” use targeted replacements for the actual changed text, preferably with expectedMatchCount: 1. Do not use import_markdown with placement: replace unless the user explicitly wants the whole body replaced. There is no automatic Markdown merge or baseline-management workflow. Independent Word edits must not be overwritten just to match the source file; report conflicts. Native targeted edits leave unrelated content in place, but review comments anchored to the changed/deleted text before editing—comment preservation at those anchors is not guaranteed.

Table and link enumeration is limited to currently rendered pages because Word virtualizes large documents. Use get_outline, read_range, or find_text to navigate the relevant area first. Anchored mutations fail when a locator is ambiguous unless an occurrence or expected match count is supplied.

Developing Actions

Every action uses the shared contract in src/core/actions.js: tool contains its metadata and schemas, response identifies its successful MCPResponse type, and handler contains the implementation. Callers invoke execute(), which rejects handlers that return anything other than an MCPResponse. Every actions/ folder has an index.js that exports its complete ACTIONS array; registration code consumes that array instead of rebuilding action lists.

Each action module has exactly one public export: its CoreAction or PluginAction descriptor. The tool schema, response class, and handler remain private and are available through the descriptor's tool, response, and handler properties. Every descriptor also has an immutable id equal to tool.name, allowing callers and tests to select it from the folder's ACTIONS array.

export const FETCH_WEBPAGE_ACTION = new CoreAction({
  tool: FETCH_WEBPAGE_TOOL,
  response: FetchPageSuccessResponse,
  handler: fetchPage,
});

A core action can opt into the CLI by adding a cli object, or an array when one action provides multiple commands. The CLI registry derives its entries from the core ACTIONS array, so no separate command registration is required.

Plugin interface version 2 exports a PluginAction beside each plugin handler. Existing parameter metadata is converted into an MCP-compatible inputSchema, while name, description, and params remain available to plugin discovery:

// plugins/example/actions/list-items.js
export async function listItems({ page, params }) {
  return new MyPluginResponse(...);
}

export const listItemsAction = new PluginAction({
  name: 'list_items',
  description: 'List items from the current page',
  params: [{ name: 'limit', type: 'number', required: false, default: 10 }],
  response: MyPluginResponse,
  handler: listItems
});

The action folder's index.js imports these descriptors into ACTIONS. Production modules consume that folder index rather than importing individual action files. Tests may import an individual action module when isolation is useful, but the module still exposes only its descriptor; handler, tool, and response access goes through that object.

Each plugin-level index.js has exactly one public export: a CorePlugin descriptor containing its manifest, detection function, actions, and information provider. Production code accesses plugins only through the PLUGINS array exported by src/plugins/index.js; adding or removing an entry there enables or disables that plugin. Only plugin-specific tests import an individual plugin entry point directly.

export const EXAMPLE_PLUGIN = new CorePlugin({
  manifest,
  matchesPage,
  actions: ACTIONS,
  getInfo,
});

Plugin handlers receive { page, params } and must return the declared response type or another MCPResponse, such as ErrorResponse. Raw objects are rejected at the action boundary.

CLI Mode

MCPBrowser can also be used as a standalone command-line tool, making it easy to use from shell scripts, CI/CD pipelines, or AI agents that work through shell commands (like GitHub Copilot CLI).

# Show help
mcpbrowser --help

# Fetch a page (handles auth, SSO, SPAs automatically)
mcpbrowser fetch https://eng.ms/docs/my-page

# Fetch with raw HTML output
mcpbrowser fetch https://github.com --browser chrome --raw

# Take a screenshot
mcpbrowser screenshot https://example.com --output page.png --full-page

# Click an element on a loaded page
mcpbrowser click https://example.com --selector "#login-btn"

# Type into a form field
mcpbrowser type https://example.com --selector "input[name=q]" --text "search query"

# Execute JavaScript
mcpbrowser exec https://example.com --script "document.title"

# Get current HTML of a loaded page
mcpbrowser html https://example.com

CLI vs MCP mode: When run without arguments, MCPBrowser starts as an MCP server (stdin/stdout JSON-RPC). When run with a subcommand, it executes the command and exits — no MCP protocol needed.

Configuration (Optional)

Environment variables for advanced setup:

VariableDescriptionDefault
CHROME_PATHPath to Chrome/Edge/BraveAuto-detect
CHROME_USER_DATA_DIRBrowser profile directory%LOCALAPPDATA%/ChromeAuthProfile
CHROME_REMOTE_DEBUG_PORTDevTools port9222

Observability & Logging

MCPBrowser logs all operations to help you understand what's happening:

[MCPBrowser] browser_fetch_webpage called: url=https://example.com
[MCPBrowser] Tab created: example.com
[MCPBrowser] Navigating to: https://example.com
[MCPBrowser] Navigation complete: https://example.com (1234ms)
[MCPBrowser] SPA detected: React, minimal content (0 chars)
[MCPBrowser] SPA content ready
[MCPBrowser] browser_fetch_webpage completed: https://example.com

Error messages are marked with ❌:

[MCPBrowser] ❌ browser_fetch_webpage failed: net::ERR_NAME_NOT_RESOLVED
[MCPBrowser] ❌ No open page found for example.com

Logs go to stderr so they don't interfere with MCP protocol on stdout.

Troubleshooting

Browser doesn't open?

  • Make sure Chrome, Edge, or Brave is installed
  • Try setting CHROME_PATH explicitly

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

E401 error with npx / private npm registry?

If your project has a .npmrc that points to a private registry (e.g., Azure Artifacts, GitHub Packages, Artifactory), npx will try to fetch mcpbrowser from that registry instead of npmjs.org and fail with E401.

Fix: Add npm_config_registry to the env block in your MCP config:

{
  "mcpServers": {
    "mcpbrowser": {
      "command": "npx",
      "args": ["-y", "mcpbrowser@latest"],
      "env": {
        "npm_config_registry": "https://registry.npmjs.org"
      }
    }
  }
}

Alternative: Install globally to skip npx entirely:

npm install -g mcpbrowser

Then use "command": "mcpbrowser" with no args in your MCP config.

Links

License

MIT

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.