mcpbrowser 0.3.43 → 0.3.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -34
- package/package.json +1 -1
- package/src/actions/accept-eula.js +5 -5
- package/src/actions/click-element.js +25 -25
- package/src/actions/close-tab.js +8 -8
- package/src/actions/execute-javascript.js +9 -9
- package/src/actions/fetch-page.js +15 -15
- package/src/actions/get-current-html.js +16 -16
- package/src/actions/navigate-history.js +21 -21
- package/src/actions/plugin-action.js +15 -15
- package/src/actions/plugin-info.js +10 -10
- package/src/actions/scroll-page.js +21 -21
- package/src/actions/take-screenshot.js +16 -16
- package/src/actions/type-text.js +28 -28
- package/src/cli/help.js +1 -1
- package/src/core/logger.js +51 -2
- package/src/core/plugin-loader.js +2 -2
- package/src/core/responses.js +4 -4
- package/src/mcp-browser.js +20 -12
- package/src/plugins/_example/index.js +2 -2
- package/src/plugins/gcal/actions/check-availability.js +1 -1
- package/src/plugins/gcal/actions/create-event.js +1 -1
- package/src/plugins/gcal/actions/delete-event.js +1 -1
- package/src/plugins/gcal/actions/edit-event.js +1 -1
- package/src/plugins/gcal/actions/list-events.js +1 -1
- package/src/plugins/gcal/actions/read-event.js +1 -1
- package/src/plugins/gcal/actions/rsvp-event.js +1 -1
- package/src/plugins/gcal/actions/search-events.js +1 -1
- package/src/plugins/gcal/helpers.js +2 -2
- package/src/plugins/gmail/actions/archive-email.js +1 -1
- package/src/plugins/gmail/actions/compose-email.js +1 -1
- package/src/plugins/gmail/actions/delete-email.js +1 -1
- package/src/plugins/gmail/actions/forward-email.js +1 -1
- package/src/plugins/gmail/actions/label-email.js +1 -1
- package/src/plugins/gmail/actions/list-emails.js +1 -1
- package/src/plugins/gmail/actions/mark-read.js +1 -1
- package/src/plugins/gmail/actions/mark-unread.js +1 -1
- package/src/plugins/gmail/actions/read-email.js +1 -1
- package/src/plugins/gmail/actions/reply-email.js +1 -1
- package/src/plugins/gmail/actions/search-emails.js +1 -1
- package/src/plugins/gmail/helpers.js +3 -3
package/README.md
CHANGED
|
@@ -14,10 +14,10 @@ This is an [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) serv
|
|
|
14
14
|
Example workflow for AI assistant to use MCPBrowser
|
|
15
15
|
|
|
16
16
|
```
|
|
17
|
-
1.
|
|
18
|
-
2.
|
|
19
|
-
3.
|
|
20
|
-
4.
|
|
17
|
+
1. browser_fetch_webpage → Load the login page
|
|
18
|
+
2. browser_type_text → Enter username and password (multiple fields at once)
|
|
19
|
+
3. browser_click_element → Click "Sign In"
|
|
20
|
+
4. browser_get_current_html → Extract the content after login
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
|
|
@@ -30,14 +30,14 @@ Example workflow for AI assistant to use MCPBrowser
|
|
|
30
30
|
- [Claude Desktop](#option-3-claude-desktop)
|
|
31
31
|
- [npm Package](#option-4-npm-package)
|
|
32
32
|
- [MCP Tools](#mcp-tools)
|
|
33
|
-
- [
|
|
34
|
-
- [
|
|
35
|
-
- [
|
|
36
|
-
- [
|
|
37
|
-
- [
|
|
38
|
-
- [
|
|
39
|
-
- [
|
|
40
|
-
- [
|
|
33
|
+
- [browser_fetch_webpage](#browser_fetch_webpage)
|
|
34
|
+
- [browser_execute_javascript](#browser_execute_javascript)
|
|
35
|
+
- [browser_click_element](#browser_click_element)
|
|
36
|
+
- [browser_type_text](#browser_type_text)
|
|
37
|
+
- [browser_get_current_html](#browser_get_current_html)
|
|
38
|
+
- [browser_scroll_page](#browser_scroll_page)
|
|
39
|
+
- [browser_take_screenshot](#browser_take_screenshot)
|
|
40
|
+
- [browser_close_tab](#browser_close_tab)
|
|
41
41
|
- [CLI Mode](#cli-mode)
|
|
42
42
|
- [Configuration](#configuration-optional)
|
|
43
43
|
- [Troubleshooting](#troubleshooting)
|
|
@@ -144,7 +144,7 @@ For VS Code, Kiro, Antigravity, or other editors — manual MCP setup. Add to yo
|
|
|
144
144
|
|
|
145
145
|
## MCP Tools
|
|
146
146
|
|
|
147
|
-
### `
|
|
147
|
+
### `browser_fetch_webpage`
|
|
148
148
|
|
|
149
149
|
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.
|
|
150
150
|
|
|
@@ -167,11 +167,11 @@ Fetches web pages using your Chrome/Edge browser. Handles authentication, CAPTCH
|
|
|
167
167
|
|
|
168
168
|
---
|
|
169
169
|
|
|
170
|
-
### `
|
|
170
|
+
### `browser_execute_javascript`
|
|
171
171
|
|
|
172
172
|
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.
|
|
173
173
|
|
|
174
|
-
**⚠️ Note:** Page must be already loaded via `
|
|
174
|
+
**⚠️ Note:** Page must be already loaded via `browser_fetch_webpage` first.
|
|
175
175
|
|
|
176
176
|
**Parameters:**
|
|
177
177
|
- `url` (string, required) - The URL of the page (must match a previously fetched page)
|
|
@@ -184,7 +184,7 @@ Executes a JavaScript snippet in the active page context and returns the result
|
|
|
184
184
|
**Example:**
|
|
185
185
|
```json
|
|
186
186
|
{
|
|
187
|
-
"action": "
|
|
187
|
+
"action": "browser_execute_javascript",
|
|
188
188
|
"url": "https://mail.google.com/",
|
|
189
189
|
"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}))",
|
|
190
190
|
"timeoutMs": 30000,
|
|
@@ -194,11 +194,11 @@ Executes a JavaScript snippet in the active page context and returns the result
|
|
|
194
194
|
|
|
195
195
|
---
|
|
196
196
|
|
|
197
|
-
### `
|
|
197
|
+
### `browser_click_element`
|
|
198
198
|
|
|
199
199
|
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.
|
|
200
200
|
|
|
201
|
-
**⚠️ Note:** Page must be already loaded via `
|
|
201
|
+
**⚠️ Note:** Page must be already loaded via `browser_fetch_webpage` first.
|
|
202
202
|
|
|
203
203
|
**Parameters:**
|
|
204
204
|
- `url` (string, required) - The URL of the page (must match a previously fetched page)
|
|
@@ -228,11 +228,11 @@ Clicks on any clickable element (buttons, links, divs with onclick handlers, etc
|
|
|
228
228
|
|
|
229
229
|
---
|
|
230
230
|
|
|
231
|
-
### `
|
|
231
|
+
### `browser_type_text`
|
|
232
232
|
|
|
233
233
|
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.
|
|
234
234
|
|
|
235
|
-
**⚠️ Note:** Page must be already loaded via `
|
|
235
|
+
**⚠️ Note:** Page must be already loaded via `browser_fetch_webpage` first.
|
|
236
236
|
|
|
237
237
|
**Parameters:**
|
|
238
238
|
- `url` (string, required) - The URL of the page (must match a previously fetched page)
|
|
@@ -281,11 +281,11 @@ Types text into one or more input fields in a single call. Supports filling enti
|
|
|
281
281
|
|
|
282
282
|
---
|
|
283
283
|
|
|
284
|
-
### `
|
|
284
|
+
### `browser_get_current_html`
|
|
285
285
|
|
|
286
|
-
Gets the current HTML from an already-loaded page **WITHOUT** navigating or reloading. Much faster than `
|
|
286
|
+
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.
|
|
287
287
|
|
|
288
|
-
**⚠️ Note:** Page must be already loaded via `
|
|
288
|
+
**⚠️ Note:** Page must be already loaded via `browser_fetch_webpage` first.
|
|
289
289
|
|
|
290
290
|
**Parameters:**
|
|
291
291
|
- `url` (string, required) - The URL of the page (must match a previously fetched page)
|
|
@@ -301,20 +301,20 @@ Gets the current HTML from an already-loaded page **WITHOUT** navigating or relo
|
|
|
301
301
|
```
|
|
302
302
|
|
|
303
303
|
**Performance comparison:**
|
|
304
|
-
- `
|
|
305
|
-
- `
|
|
304
|
+
- `browser_fetch_webpage`: 2-5 seconds (full page reload)
|
|
305
|
+
- `browser_get_current_html`: 0.1-0.3 seconds (just extracts HTML) ✅
|
|
306
306
|
|
|
307
307
|
---
|
|
308
308
|
|
|
309
|
-
### `
|
|
309
|
+
### `browser_scroll_page`
|
|
310
310
|
|
|
311
|
-
Scrolls within an already-loaded page. Use before `
|
|
311
|
+
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:
|
|
312
312
|
|
|
313
313
|
- **By direction**: Scroll up/down/left/right by pixel amount
|
|
314
314
|
- **To element**: Scroll until a specific element is visible
|
|
315
315
|
- **To position**: Scroll to absolute coordinates
|
|
316
316
|
|
|
317
|
-
**⚠️ Note:** Page must be already loaded via `
|
|
317
|
+
**⚠️ Note:** Page must be already loaded via `browser_fetch_webpage` first.
|
|
318
318
|
|
|
319
319
|
**Parameters:**
|
|
320
320
|
- `url` (string, required) - The URL of the page (must match a previously fetched page)
|
|
@@ -346,11 +346,11 @@ Scrolls within an already-loaded page. Use before `take_screenshot` to capture d
|
|
|
346
346
|
|
|
347
347
|
---
|
|
348
348
|
|
|
349
|
-
### `
|
|
349
|
+
### `browser_take_screenshot`
|
|
350
350
|
|
|
351
351
|
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.
|
|
352
352
|
|
|
353
|
-
**⚠️ Note:** Page must be already loaded via `
|
|
353
|
+
**⚠️ Note:** Page must be already loaded via `browser_fetch_webpage` first.
|
|
354
354
|
|
|
355
355
|
**Parameters:**
|
|
356
356
|
- `url` (string, required) - The URL of the page (must match a previously fetched page)
|
|
@@ -374,7 +374,7 @@ Takes a screenshot of an already-loaded page for visual analysis. **Useful when
|
|
|
374
374
|
|
|
375
375
|
---
|
|
376
376
|
|
|
377
|
-
### `
|
|
377
|
+
### `browser_close_tab`
|
|
378
378
|
|
|
379
379
|
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.
|
|
380
380
|
|
|
@@ -446,18 +446,18 @@ Environment variables for advanced setup:
|
|
|
446
446
|
MCPBrowser logs all operations to help you understand what's happening:
|
|
447
447
|
|
|
448
448
|
```
|
|
449
|
-
[MCPBrowser]
|
|
449
|
+
[MCPBrowser] browser_fetch_webpage called: url=https://example.com
|
|
450
450
|
[MCPBrowser] Tab created: example.com
|
|
451
451
|
[MCPBrowser] Navigating to: https://example.com
|
|
452
452
|
[MCPBrowser] Navigation complete: https://example.com (1234ms)
|
|
453
453
|
[MCPBrowser] SPA detected: React, minimal content (0 chars)
|
|
454
454
|
[MCPBrowser] SPA content ready
|
|
455
|
-
[MCPBrowser]
|
|
455
|
+
[MCPBrowser] browser_fetch_webpage completed: https://example.com
|
|
456
456
|
```
|
|
457
457
|
|
|
458
458
|
**Error messages are marked with ❌:**
|
|
459
459
|
```
|
|
460
|
-
[MCPBrowser] ❌
|
|
460
|
+
[MCPBrowser] ❌ browser_fetch_webpage failed: net::ERR_NAME_NOT_RESOLVED
|
|
461
461
|
[MCPBrowser] ❌ No open page found for example.com
|
|
462
462
|
```
|
|
463
463
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcpbrowser",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.45",
|
|
4
4
|
"mcpName": "io.github.cherchyk/mcpbrowser",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "MCP browser server - fetch web pages using real Chrome/Edge/Brave browser. Handles authentication, SSO, CAPTCHAs, and anti-bot protection. Browser automation for AI assistants.",
|
|
@@ -154,8 +154,8 @@ export async function handleAcceptEula(args) {
|
|
|
154
154
|
return new EulaAcceptedResponse(
|
|
155
155
|
EULA_URL,
|
|
156
156
|
[
|
|
157
|
-
'Use
|
|
158
|
-
'Use
|
|
157
|
+
'Use browser_fetch_webpage to navigate to a URL',
|
|
158
|
+
'Use browser_get_current_html to see the current page content'
|
|
159
159
|
]
|
|
160
160
|
);
|
|
161
161
|
}
|
|
@@ -180,9 +180,9 @@ export async function handleAcceptEula(args) {
|
|
|
180
180
|
return new EulaAcceptedResponse(
|
|
181
181
|
EULA_URL,
|
|
182
182
|
[
|
|
183
|
-
'Use
|
|
184
|
-
'Use
|
|
185
|
-
'Use
|
|
183
|
+
'Use browser_fetch_webpage to navigate to a URL',
|
|
184
|
+
'Use browser_click_element to interact with page elements',
|
|
185
|
+
'Use browser_type_text to enter text into forms'
|
|
186
186
|
]
|
|
187
187
|
);
|
|
188
188
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* Why this design?
|
|
21
21
|
* - Solves SPA navigation issue: URL hash changes instantly (#inbox → #trash),
|
|
22
22
|
* but content loads asynchronously. Without waiting, we'd return old content.
|
|
23
|
-
* - Consistent with
|
|
23
|
+
* - Consistent with browser_fetch_webpage: Both wait for stability and return HTML
|
|
24
24
|
* - Flexible: Can disable waiting for fast form interactions
|
|
25
25
|
*/
|
|
26
26
|
|
|
@@ -35,7 +35,7 @@ import { getPluginNextSteps, getRecommendedPlugins } from '../core/plugin-loader
|
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Structured response for
|
|
38
|
+
* Structured response for browser_click_element with JS fallback metadata
|
|
39
39
|
*/
|
|
40
40
|
export class ClickWithFallbackResponse extends MCPResponse {
|
|
41
41
|
constructor({ status, fallbackUsed = false, nativeAttempt, fallbackAttempt, postClickWait, currentUrl, html = null, message, nextSteps = [], recommendedPlugins = [] }) {
|
|
@@ -79,9 +79,9 @@ export class ClickWithFallbackResponse extends MCPResponse {
|
|
|
79
79
|
* @type {Tool}
|
|
80
80
|
*/
|
|
81
81
|
export const CLICK_ELEMENT_TOOL = {
|
|
82
|
-
name: "
|
|
82
|
+
name: "browser_click_element",
|
|
83
83
|
title: "Click Element",
|
|
84
|
-
description: "**BROWSER INTERACTION** - Clicks elements on browser-loaded pages. Use this for navigation (clicking links/buttons), form submission, and any user interaction that requires clicking.\n\nWorks with any clickable element including buttons, links, or elements with onclick handlers. Can target by CSS selector or text content. Waits for page stability and returns updated HTML by default.\n\n**PREREQUISITE**: Page MUST be loaded with
|
|
84
|
+
description: "**BROWSER INTERACTION** - Clicks elements on browser-loaded pages. Use this for navigation (clicking links/buttons), form submission, and any user interaction that requires clicking.\n\nWorks with any clickable element including buttons, links, or elements with onclick handlers. Can target by CSS selector or text content. Waits for page stability and returns updated HTML by default.\n\n**PREREQUISITE**: Page MUST be loaded with browser_fetch_webpage first. This tool operates on an already-loaded page in the browser.",
|
|
85
85
|
inputSchema: {
|
|
86
86
|
type: "object",
|
|
87
87
|
properties: {
|
|
@@ -182,7 +182,7 @@ export const CLICK_ELEMENT_TOOL = {
|
|
|
182
182
|
* });
|
|
183
183
|
*/
|
|
184
184
|
export async function clickElement({ url, selector, text, waitForElementTimeout = 30000, returnHtml = true, removeUnnecessaryHTML = true, postClickWait = 1000 }) {
|
|
185
|
-
logger.info(`
|
|
185
|
+
logger.info(`browser_click_element called: ${selector || `text="${text}"`}`);
|
|
186
186
|
|
|
187
187
|
if (!url) {
|
|
188
188
|
throw new Error("url parameter is required");
|
|
@@ -203,7 +203,7 @@ export async function clickElement({ url, selector, text, waitForElementTimeout
|
|
|
203
203
|
try {
|
|
204
204
|
await getBrowser();
|
|
205
205
|
} catch (err) {
|
|
206
|
-
logger.error(`
|
|
206
|
+
logger.error(`browser_click_element: Failed to connect to browser: ${err.message}`);
|
|
207
207
|
return new InformationalResponse(
|
|
208
208
|
`Browser connection failed: ${err.message}`,
|
|
209
209
|
'The browser must be running with remote debugging enabled.',
|
|
@@ -220,15 +220,15 @@ export async function clickElement({ url, selector, text, waitForElementTimeout
|
|
|
220
220
|
|
|
221
221
|
if (!page) {
|
|
222
222
|
const isConnectionLost = pageError && pageError.includes('connection');
|
|
223
|
-
logger.debug(`
|
|
223
|
+
logger.debug(`browser_click_element: ${pageError || 'No page found for ' + hostname}`);
|
|
224
224
|
return new InformationalResponse(
|
|
225
225
|
isConnectionLost ? `Page connection lost for ${hostname}` : `No open page found for ${hostname}`,
|
|
226
226
|
isConnectionLost
|
|
227
227
|
? 'The browser tab was closed or the connection was lost. The page needs to be reloaded.'
|
|
228
228
|
: 'The page must be loaded before you can interact with elements on it',
|
|
229
229
|
[
|
|
230
|
-
"Use MCPBrowser's
|
|
231
|
-
"Then retry MCPBrowser's
|
|
230
|
+
"Use MCPBrowser's browser_fetch_webpage tool to load the page first",
|
|
231
|
+
"Then retry MCPBrowser's browser_click_element with the same URL"
|
|
232
232
|
]
|
|
233
233
|
);
|
|
234
234
|
}
|
|
@@ -271,8 +271,8 @@ export async function clickElement({ url, selector, text, waitForElementTimeout
|
|
|
271
271
|
selector ? `Element not found: ${selector}` : `Element with text "${text}" not found`,
|
|
272
272
|
'The element could not be located on the page. It may be hidden, dynamically loaded, or the selector/text may be incorrect.',
|
|
273
273
|
[
|
|
274
|
-
"Use MCPBrowser's
|
|
275
|
-
"Use MCPBrowser's
|
|
274
|
+
"Use MCPBrowser's browser_get_current_html to verify page content",
|
|
275
|
+
"Use MCPBrowser's browser_take_screenshot to see the visual layout if HTML is unclear",
|
|
276
276
|
"Try a different selector or text",
|
|
277
277
|
"Check if the element is visible on the page"
|
|
278
278
|
]
|
|
@@ -337,20 +337,20 @@ export async function clickElement({ url, selector, text, waitForElementTimeout
|
|
|
337
337
|
const nextSteps = returnHtml
|
|
338
338
|
? [
|
|
339
339
|
...(html ? getPluginNextSteps(currentUrl, html) : []),
|
|
340
|
-
"Use MCPBrowser's
|
|
341
|
-
"Use MCPBrowser's
|
|
342
|
-
"Use MCPBrowser's
|
|
343
|
-
"Use MCPBrowser's
|
|
344
|
-
"Use MCPBrowser's
|
|
340
|
+
"Use MCPBrowser's browser_click_element again to navigate further",
|
|
341
|
+
"Use MCPBrowser's browser_type_text to fill forms if needed",
|
|
342
|
+
"Use MCPBrowser's browser_get_current_html to refresh page state",
|
|
343
|
+
"Use MCPBrowser's browser_take_screenshot if page has popups or visual content that's hard to parse from HTML",
|
|
344
|
+
"Use MCPBrowser's browser_close_tab when finished"
|
|
345
345
|
]
|
|
346
346
|
: [
|
|
347
|
-
"Use MCPBrowser's
|
|
348
|
-
"Use MCPBrowser's
|
|
349
|
-
"Use MCPBrowser's
|
|
350
|
-
"Use MCPBrowser's
|
|
347
|
+
"Use MCPBrowser's browser_get_current_html to see updated page state",
|
|
348
|
+
"Use MCPBrowser's browser_take_screenshot if the page has popups, modals, or visual content",
|
|
349
|
+
"Use MCPBrowser's browser_click_element or MCPBrowser's browser_type_text for more interactions",
|
|
350
|
+
"Use MCPBrowser's browser_close_tab when finished"
|
|
351
351
|
];
|
|
352
352
|
|
|
353
|
-
logger.info(`
|
|
353
|
+
logger.info(`browser_click_element completed: ${selector || `text="${text}"`}${fallbackUsed ? ' (fallback used)' : ''}`);
|
|
354
354
|
|
|
355
355
|
return new ClickWithFallbackResponse({
|
|
356
356
|
status: finalStatus,
|
|
@@ -365,15 +365,15 @@ export async function clickElement({ url, selector, text, waitForElementTimeout
|
|
|
365
365
|
recommendedPlugins: html ? getRecommendedPlugins(currentUrl, html) : []
|
|
366
366
|
});
|
|
367
367
|
} catch (err) {
|
|
368
|
-
logger.error(`
|
|
368
|
+
logger.error(`browser_click_element failed: ${err.message}`);
|
|
369
369
|
return new InformationalResponse(
|
|
370
370
|
`Failed to click element: ${err.message}`,
|
|
371
371
|
'The element was found but could not be clicked. It may be covered by another element, not interactable, or the page may have changed.',
|
|
372
372
|
[
|
|
373
|
-
"Use MCPBrowser's
|
|
374
|
-
"Use MCPBrowser's
|
|
373
|
+
"Use MCPBrowser's browser_get_current_html to check current page state",
|
|
374
|
+
"Use MCPBrowser's browser_take_screenshot to see what's visually blocking the element",
|
|
375
375
|
"Verify the selector or text is correct",
|
|
376
|
-
"Try MCPBrowser's
|
|
376
|
+
"Try MCPBrowser's browser_fetch_webpage to reload if page is stale"
|
|
377
377
|
]
|
|
378
378
|
);
|
|
379
379
|
}
|
package/src/actions/close-tab.js
CHANGED
|
@@ -15,7 +15,7 @@ import logger from '../core/logger.js';
|
|
|
15
15
|
// ============================================================================
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Response for successful
|
|
18
|
+
* Response for successful browser_close_tab operations
|
|
19
19
|
*/
|
|
20
20
|
export class CloseTabSuccessResponse extends MCPResponse {
|
|
21
21
|
/**
|
|
@@ -57,7 +57,7 @@ export class CloseTabSuccessResponse extends MCPResponse {
|
|
|
57
57
|
* @type {Tool}
|
|
58
58
|
*/
|
|
59
59
|
export const CLOSE_TAB_TOOL = {
|
|
60
|
-
name: "
|
|
60
|
+
name: "browser_close_tab",
|
|
61
61
|
title: "Close Tab",
|
|
62
62
|
description: "**BROWSER MANAGEMENT** - Closes the browser tab for the given URL's hostname. This removes the page from the tab pool and forces a fresh session on the next visit to that hostname. Useful for memory management or when you need to clear session state. Note: Uses exact hostname match (www.example.com and example.com are treated as different tabs).",
|
|
63
63
|
inputSchema: {
|
|
@@ -97,7 +97,7 @@ export const CLOSE_TAB_TOOL = {
|
|
|
97
97
|
*/
|
|
98
98
|
export async function closeTab({ url }) {
|
|
99
99
|
const startTime = Date.now();
|
|
100
|
-
logger.info(`
|
|
100
|
+
logger.info(`browser_close_tab called: url=${url}`);
|
|
101
101
|
|
|
102
102
|
try {
|
|
103
103
|
// Validate URL
|
|
@@ -145,7 +145,7 @@ export async function closeTab({ url }) {
|
|
|
145
145
|
'No open tab found for this hostname',
|
|
146
146
|
hostname,
|
|
147
147
|
[
|
|
148
|
-
"Use MCPBrowser's
|
|
148
|
+
"Use MCPBrowser's browser_fetch_webpage to open a new page if needed"
|
|
149
149
|
]
|
|
150
150
|
);
|
|
151
151
|
}
|
|
@@ -164,7 +164,7 @@ export async function closeTab({ url }) {
|
|
|
164
164
|
'Tab was already closed',
|
|
165
165
|
hostname,
|
|
166
166
|
[
|
|
167
|
-
"Use MCPBrowser's
|
|
167
|
+
"Use MCPBrowser's browser_fetch_webpage to open a new page if needed"
|
|
168
168
|
]
|
|
169
169
|
);
|
|
170
170
|
}
|
|
@@ -175,18 +175,18 @@ export async function closeTab({ url }) {
|
|
|
175
175
|
// Remove from domain pool
|
|
176
176
|
domainPages.delete(hostname);
|
|
177
177
|
|
|
178
|
-
logger.info(`
|
|
178
|
+
logger.info(`browser_close_tab completed: closed tab for ${hostname}`);
|
|
179
179
|
|
|
180
180
|
return new CloseTabSuccessResponse(
|
|
181
181
|
`Successfully closed tab for ${hostname}`,
|
|
182
182
|
hostname,
|
|
183
183
|
[
|
|
184
|
-
"Use MCPBrowser's
|
|
184
|
+
"Use MCPBrowser's browser_fetch_webpage to open a new page if needed"
|
|
185
185
|
]
|
|
186
186
|
);
|
|
187
187
|
|
|
188
188
|
} catch (error) {
|
|
189
|
-
logger.error(`
|
|
189
|
+
logger.error(`browser_close_tab failed: ${error.message}`);
|
|
190
190
|
return new ErrorResponse(
|
|
191
191
|
error.message,
|
|
192
192
|
[
|
|
@@ -19,7 +19,7 @@ export const EXECUTION_RESULT_MAX_BYTES = 100_000;
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Structured response for
|
|
22
|
+
* Structured response for browser_execute_javascript action
|
|
23
23
|
*/
|
|
24
24
|
export class ExecuteJavascriptResponse extends MCPResponse {
|
|
25
25
|
constructor({ result, type, executionTimeMs, truncated = false, urlChanged = false, currentUrl = '', error = null, nextSteps = [], recommendedPlugins = [] }) {
|
|
@@ -57,7 +57,7 @@ export class ExecuteJavascriptResponse extends MCPResponse {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export const EXECUTE_JAVASCRIPT_TOOL = {
|
|
60
|
-
name: '
|
|
60
|
+
name: 'browser_execute_javascript',
|
|
61
61
|
title: 'Execute JavaScript',
|
|
62
62
|
description: '**BROWSER INTERACTION** - Executes a JavaScript snippet in the active page and returns the result with metadata (execution time, truncation, navigation detection). Use for structured extraction or UI actions that are unreliable via protocol clicks.',
|
|
63
63
|
inputSchema: {
|
|
@@ -103,7 +103,7 @@ function buildErrorResponse(message, reason, nextSteps) {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
export async function executeJavascript({ url, script, timeoutMs = EXECUTION_TIMEOUT_DEFAULT_MS, returnType = 'json' }) {
|
|
106
|
-
logger.info(`
|
|
106
|
+
logger.info(`browser_execute_javascript called: ${url}`);
|
|
107
107
|
|
|
108
108
|
if (!url) throw new Error('url parameter is required');
|
|
109
109
|
if (!script || typeof script !== 'string' || !script.trim()) throw new Error('script parameter is required');
|
|
@@ -118,7 +118,7 @@ export async function executeJavascript({ url, script, timeoutMs = EXECUTION_TIM
|
|
|
118
118
|
try {
|
|
119
119
|
await getBrowser();
|
|
120
120
|
} catch (err) {
|
|
121
|
-
logger.error(`
|
|
121
|
+
logger.error(`browser_execute_javascript: Failed to connect to browser: ${err.message}`);
|
|
122
122
|
return buildErrorResponse(
|
|
123
123
|
`Browser connection failed: ${err.message}`,
|
|
124
124
|
'The browser must be running with remote debugging enabled.',
|
|
@@ -133,15 +133,15 @@ export async function executeJavascript({ url, script, timeoutMs = EXECUTION_TIM
|
|
|
133
133
|
const { page, error: pageError } = await getValidatedPage(hostname);
|
|
134
134
|
if (!page) {
|
|
135
135
|
const isConnectionLost = pageError && pageError.includes('connection');
|
|
136
|
-
logger.debug(`
|
|
136
|
+
logger.debug(`browser_execute_javascript: ${pageError || 'No page found for ' + hostname}`);
|
|
137
137
|
return buildErrorResponse(
|
|
138
138
|
isConnectionLost ? `Page connection lost for ${hostname}` : `No open page found for ${hostname}`,
|
|
139
139
|
isConnectionLost
|
|
140
140
|
? 'The browser tab was closed or the connection was lost. The page needs to be reloaded.'
|
|
141
141
|
: 'The page must be loaded before you can run scripts on it.',
|
|
142
142
|
[
|
|
143
|
-
"Use MCPBrowser's
|
|
144
|
-
"Then retry MCPBrowser's
|
|
143
|
+
"Use MCPBrowser's browser_fetch_webpage tool to load the page first",
|
|
144
|
+
"Then retry MCPBrowser's browser_execute_javascript with the same URL"
|
|
145
145
|
]
|
|
146
146
|
);
|
|
147
147
|
}
|
|
@@ -232,7 +232,7 @@ export async function executeJavascript({ url, script, timeoutMs = EXECUTION_TIM
|
|
|
232
232
|
currentUrl,
|
|
233
233
|
nextSteps: [
|
|
234
234
|
...getPluginNextSteps(currentUrl, ''),
|
|
235
|
-
'Use
|
|
235
|
+
'Use browser_click_element or browser_type_text for follow-up actions',
|
|
236
236
|
'Inspect urlChanged to decide if navigation occurred',
|
|
237
237
|
serialization.truncated ? 'Narrow your selector or reduce returned fields to avoid truncation' : 'Proceed with the returned data'
|
|
238
238
|
],
|
|
@@ -248,7 +248,7 @@ export async function executeJavascriptWithReady(params) {
|
|
|
248
248
|
if (page) await waitForPageReady(page, { afterInteraction: true });
|
|
249
249
|
}
|
|
250
250
|
} catch (err) {
|
|
251
|
-
logger.debug(`
|
|
251
|
+
logger.debug(`browser_execute_javascript post-wait skipped: ${err.message}`);
|
|
252
252
|
}
|
|
253
253
|
return response;
|
|
254
254
|
}
|
|
@@ -19,7 +19,7 @@ import { getPluginNextSteps, getRecommendedPlugins } from '../core/plugin-loader
|
|
|
19
19
|
// ============================================================================
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Response for successful
|
|
22
|
+
* Response for successful browser_fetch_webpage operations
|
|
23
23
|
*/
|
|
24
24
|
export class FetchPageSuccessResponse extends MCPResponse {
|
|
25
25
|
/**
|
|
@@ -64,7 +64,7 @@ export class FetchPageSuccessResponse extends MCPResponse {
|
|
|
64
64
|
* @type {Tool}
|
|
65
65
|
*/
|
|
66
66
|
export const FETCH_WEBPAGE_TOOL = {
|
|
67
|
-
name: "
|
|
67
|
+
name: "browser_fetch_webpage",
|
|
68
68
|
title: "Fetch Web Page",
|
|
69
69
|
description: "Fetches web pages using Chrome/Edge browser with full JavaScript rendering and authentication support. **REQUIRED for corporate/enterprise sites, any page requiring login/SSO, anti-bot/CAPTCHA pages, and JavaScript-heavy applications.** Use this as the DEFAULT for all webpage fetching - it handles simple HTML pages too. Opens browser for user authentication when needed. Never use generic HTTP fetch for pages that might require authentication.",
|
|
70
70
|
inputSchema: {
|
|
@@ -123,7 +123,7 @@ export const FETCH_WEBPAGE_TOOL = {
|
|
|
123
123
|
* @returns {Promise<Object>} Result object with success status, URL, HTML content, or error details
|
|
124
124
|
*/
|
|
125
125
|
export async function fetchPage({ url, browser = '', removeUnnecessaryHTML = true, postLoadWait = 0 }) {
|
|
126
|
-
logger.info(`
|
|
126
|
+
logger.info(`browser_fetch_webpage called: url=${url}`);
|
|
127
127
|
|
|
128
128
|
// Handle missing URL with environment variable fallback
|
|
129
129
|
if (!url) {
|
|
@@ -166,7 +166,7 @@ async function doFetchPage({ url, browser, removeUnnecessaryHTML, postLoadWait }
|
|
|
166
166
|
try {
|
|
167
167
|
browserInstance = await getBrowser(browser);
|
|
168
168
|
} catch (err) {
|
|
169
|
-
logger.error(`
|
|
169
|
+
logger.error(`browser_fetch_webpage: Failed to connect to browser: ${err.message}`);
|
|
170
170
|
return new InformationalResponse(
|
|
171
171
|
`Browser connection failed: ${err.message}`,
|
|
172
172
|
'The browser must be running with remote debugging enabled.',
|
|
@@ -195,8 +195,8 @@ async function doFetchPage({ url, browser, removeUnnecessaryHTML, postLoadWait }
|
|
|
195
195
|
authResult.error,
|
|
196
196
|
[
|
|
197
197
|
"Complete authentication in the browser window",
|
|
198
|
-
"Call MCPBrowser's
|
|
199
|
-
"Use MCPBrowser's
|
|
198
|
+
"Call MCPBrowser's browser_fetch_webpage again with the same URL to retry",
|
|
199
|
+
"Use MCPBrowser's browser_close_tab to reset the session if authentication fails"
|
|
200
200
|
]
|
|
201
201
|
);
|
|
202
202
|
}
|
|
@@ -217,7 +217,7 @@ async function doFetchPage({ url, browser, removeUnnecessaryHTML, postLoadWait }
|
|
|
217
217
|
// Extract and process HTML
|
|
218
218
|
const processedHtml = await extractAndProcessHtml(page, removeUnnecessaryHTML);
|
|
219
219
|
|
|
220
|
-
logger.info(`
|
|
220
|
+
logger.info(`browser_fetch_webpage completed: ${page.url()}`);
|
|
221
221
|
|
|
222
222
|
// Check for non-2xx HTTP status codes
|
|
223
223
|
if (statusCode && (statusCode >= 400 && statusCode < 600)) {
|
|
@@ -230,22 +230,22 @@ async function doFetchPage({ url, browser, removeUnnecessaryHTML, postLoadWait }
|
|
|
230
230
|
processedHtml,
|
|
231
231
|
[
|
|
232
232
|
...getPluginNextSteps(page.url(), processedHtml),
|
|
233
|
-
"Use MCPBrowser's
|
|
234
|
-
"Use MCPBrowser's
|
|
235
|
-
"Use MCPBrowser's
|
|
236
|
-
"Use MCPBrowser's
|
|
237
|
-
"Use MCPBrowser's
|
|
233
|
+
"Use MCPBrowser's browser_click_element to interact with buttons/links on the page",
|
|
234
|
+
"Use MCPBrowser's browser_type_text to fill in form fields",
|
|
235
|
+
"Use MCPBrowser's browser_get_current_html to re-check page state after interactions",
|
|
236
|
+
"Use MCPBrowser's browser_take_screenshot if page has charts, images, or complex visual layout that's hard to understand from HTML",
|
|
237
|
+
"Use MCPBrowser's browser_close_tab when finished to free browser resources"
|
|
238
238
|
],
|
|
239
239
|
getRecommendedPlugins(page.url(), processedHtml)
|
|
240
240
|
);
|
|
241
241
|
} catch (err) {
|
|
242
|
-
logger.error(`
|
|
242
|
+
logger.error(`browser_fetch_webpage failed: ${err.message || String(err)}`);
|
|
243
243
|
return new ErrorResponse(
|
|
244
244
|
err.message || String(err),
|
|
245
245
|
[
|
|
246
246
|
"Complete authentication in the browser if prompted",
|
|
247
|
-
"Call MCPBrowser's
|
|
248
|
-
"Use MCPBrowser's
|
|
247
|
+
"Call MCPBrowser's browser_fetch_webpage again with the same URL to retry",
|
|
248
|
+
"Use MCPBrowser's browser_close_tab to reset the session if needed"
|
|
249
249
|
]
|
|
250
250
|
);
|
|
251
251
|
}
|