mcpbrowser 0.3.33 → 0.3.34

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcpbrowser",
3
- "version": "0.3.33",
3
+ "version": "0.3.34",
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.",
@@ -0,0 +1,248 @@
1
+ /**
2
+ * navigate-history.js - Browser back/forward navigation
3
+ * Navigates browser history on an already-loaded page.
4
+ */
5
+
6
+ import { getBrowser, getValidatedPage, domainPages } from '../core/browser.js';
7
+ import { extractAndProcessHtml, waitForPageReady } from '../core/page.js';
8
+ import { MCPResponse, InformationalResponse } from '../core/responses.js';
9
+ import logger from '../core/logger.js';
10
+
11
+ /**
12
+ * @typedef {import('@modelcontextprotocol/sdk/types.js').Tool} Tool
13
+ */
14
+
15
+ // ============================================================================
16
+ // RESPONSE CLASS
17
+ // ============================================================================
18
+
19
+ /**
20
+ * Response for successful navigate_history operations
21
+ */
22
+ export class NavigateHistorySuccessResponse extends MCPResponse {
23
+ /**
24
+ * @param {string} direction - Navigation direction (back or forward)
25
+ * @param {string} previousUrl - URL before navigation
26
+ * @param {string} currentUrl - URL after navigation
27
+ * @param {string|null} html - Page HTML content (null if returnHtml=false)
28
+ * @param {string[]} nextSteps - Suggested next actions
29
+ */
30
+ constructor(direction, previousUrl, currentUrl, html, nextSteps) {
31
+ super(nextSteps);
32
+
33
+ if (typeof direction !== 'string') {
34
+ throw new TypeError('direction must be a string');
35
+ }
36
+ if (typeof previousUrl !== 'string') {
37
+ throw new TypeError('previousUrl must be a string');
38
+ }
39
+ if (typeof currentUrl !== 'string') {
40
+ throw new TypeError('currentUrl must be a string');
41
+ }
42
+ if (html !== null && typeof html !== 'string') {
43
+ throw new TypeError('html must be a string or null');
44
+ }
45
+
46
+ this.direction = direction;
47
+ this.previousUrl = previousUrl;
48
+ this.currentUrl = currentUrl;
49
+ this.html = html;
50
+ }
51
+
52
+ _getAdditionalFields() {
53
+ return {
54
+ direction: this.direction,
55
+ previousUrl: this.previousUrl,
56
+ currentUrl: this.currentUrl,
57
+ html: this.html
58
+ };
59
+ }
60
+
61
+ getTextSummary() {
62
+ return `Navigated ${this.direction}: ${this.previousUrl} → ${this.currentUrl}`;
63
+ }
64
+ }
65
+
66
+ // ============================================================================
67
+ // TOOL DEFINITION
68
+ // ============================================================================
69
+
70
+ /** @type {Tool} */
71
+ export const NAVIGATE_HISTORY_TOOL = {
72
+ name: "navigate_history",
73
+ title: "Navigate Back/Forward",
74
+ description: "**BROWSER HISTORY NAVIGATION** - Navigate back or forward in browser history on an already-loaded page. Use after clicking links to return to the previous page, or to go forward after going back.\n\n**PREREQUISITE**: Page MUST be loaded with fetch_webpage first. This tool navigates the history of an existing browser tab.",
75
+ inputSchema: {
76
+ type: "object",
77
+ properties: {
78
+ url: { type: "string", description: "URL of the already-loaded page (identifies which tab to navigate)" },
79
+ direction: {
80
+ type: "string",
81
+ enum: ["back", "forward"],
82
+ description: "Navigation direction: 'back' to go to previous page, 'forward' to go to next page",
83
+ default: "back"
84
+ },
85
+ returnHtml: { type: "boolean", description: "Return page HTML after navigation", default: true },
86
+ removeUnnecessaryHTML: { type: "boolean", description: "Remove unnecessary HTML elements (scripts, styles, etc.) for size reduction.", default: true }
87
+ },
88
+ required: ["url"],
89
+ additionalProperties: false
90
+ },
91
+ outputSchema: {
92
+ type: "object",
93
+ properties: {
94
+ direction: { type: "string", enum: ["back", "forward"], description: "Navigation direction used" },
95
+ previousUrl: { type: "string", description: "URL before navigation" },
96
+ currentUrl: { type: "string", description: "URL after navigation" },
97
+ html: { type: ["string", "null"], description: "Page HTML content after navigation (null if returnHtml=false)" },
98
+ nextSteps: {
99
+ type: "array",
100
+ items: { type: "string" },
101
+ description: "Suggested next actions"
102
+ }
103
+ },
104
+ required: ["direction", "previousUrl", "currentUrl", "nextSteps"],
105
+ additionalProperties: false
106
+ },
107
+ annotations: {
108
+ title: "Navigate Back/Forward",
109
+ readOnlyHint: false,
110
+ destructiveHint: false,
111
+ openWorldHint: true
112
+ }
113
+ };
114
+
115
+ // ============================================================================
116
+ // ACTION FUNCTION
117
+ // ============================================================================
118
+
119
+ /**
120
+ * Navigate browser history (back/forward) on an already-loaded page
121
+ * @param {Object} params - Parameters
122
+ * @param {string} params.url - URL of the already-loaded page
123
+ * @param {string} [params.direction='back'] - Navigation direction
124
+ * @param {boolean} [params.returnHtml=true] - Return page HTML after navigation
125
+ * @param {boolean} [params.removeUnnecessaryHTML=true] - Clean HTML
126
+ * @returns {Promise<MCPResponse>} Navigation result
127
+ */
128
+ export async function navigateHistory({ url, direction = 'back', returnHtml = true, removeUnnecessaryHTML = true }) {
129
+ logger.info(`navigate_history called: url=${url}, direction=${direction}`);
130
+
131
+ if (!url) {
132
+ throw new Error("url parameter is required");
133
+ }
134
+
135
+ let hostname;
136
+ try {
137
+ hostname = new URL(url).hostname;
138
+ } catch {
139
+ throw new Error(`Invalid URL: ${url}`);
140
+ }
141
+
142
+ // Ensure browser connection
143
+ try {
144
+ await getBrowser();
145
+ } catch (err) {
146
+ logger.error(`navigate_history: Failed to connect to browser: ${err.message}`);
147
+ return new InformationalResponse(
148
+ `Browser connection failed: ${err.message}`,
149
+ 'The browser must be running with remote debugging enabled.',
150
+ [
151
+ 'Ensure the browser is installed and running',
152
+ 'Check that remote debugging is enabled (--remote-debugging-port)',
153
+ 'Try restarting the MCP server'
154
+ ]
155
+ );
156
+ }
157
+
158
+ // Validate page exists and is usable
159
+ const { page, error: pageError } = await getValidatedPage(hostname);
160
+
161
+ if (!page) {
162
+ const isConnectionLost = pageError && pageError.includes('connection');
163
+ logger.debug(`navigate_history: ${pageError || 'No page found for ' + hostname}`);
164
+ return new InformationalResponse(
165
+ isConnectionLost ? `Page connection lost for ${hostname}` : `No open page found for ${hostname}`,
166
+ isConnectionLost
167
+ ? 'The browser tab was closed or the connection was lost. The page needs to be reloaded.'
168
+ : 'The page must be loaded before you can navigate its history.',
169
+ [
170
+ "Use MCPBrowser's fetch_webpage tool to load the page first",
171
+ "Then retry MCPBrowser's navigate_history with the same URL"
172
+ ]
173
+ );
174
+ }
175
+
176
+ try {
177
+ const previousUrl = page.url();
178
+
179
+ // Navigate history
180
+ let response;
181
+ if (direction === 'forward') {
182
+ response = await page.goForward({ waitUntil: 'domcontentloaded', timeout: 30000 });
183
+ } else {
184
+ response = await page.goBack({ waitUntil: 'domcontentloaded', timeout: 30000 });
185
+ }
186
+
187
+ // goBack/goForward return null if there's no history entry
188
+ if (response === null) {
189
+ logger.info(`navigate_history: No ${direction} history entry available`);
190
+ return new InformationalResponse(
191
+ `No ${direction} history entry available`,
192
+ `The page has no ${direction} history to navigate to. This means you're already at the ${direction === 'back' ? 'first' : 'last'} page in the browsing history for this tab.`,
193
+ [
194
+ direction === 'back'
195
+ ? "Use MCPBrowser's fetch_webpage to navigate to a different URL"
196
+ : "Use MCPBrowser's navigate_history with direction='back' to go back instead",
197
+ "Use MCPBrowser's get_current_html to check the current page content"
198
+ ]
199
+ );
200
+ }
201
+
202
+ const currentUrl = page.url();
203
+
204
+ // Update domainPages if hostname changed after navigation
205
+ try {
206
+ const newHostname = new URL(currentUrl).hostname;
207
+ if (newHostname !== hostname) {
208
+ domainPages.delete(hostname);
209
+ domainPages.set(newHostname, page);
210
+ logger.info(`navigate_history: Updated domainPages mapping: ${hostname} → ${newHostname}`);
211
+ }
212
+ } catch {
213
+ // If URL parsing fails, keep existing mapping
214
+ }
215
+
216
+ // Extract HTML if requested
217
+ let html = null;
218
+ if (returnHtml) {
219
+ await waitForPageReady(page);
220
+ html = await extractAndProcessHtml(page, removeUnnecessaryHTML);
221
+ }
222
+
223
+ logger.info(`navigate_history completed: ${direction} from ${previousUrl} to ${currentUrl}`);
224
+
225
+ return new NavigateHistorySuccessResponse(
226
+ direction,
227
+ previousUrl,
228
+ currentUrl,
229
+ html,
230
+ [
231
+ "Use MCPBrowser's navigate_history to go back or forward again",
232
+ "Use MCPBrowser's click_element to interact with elements on the page",
233
+ "Use MCPBrowser's get_current_html to re-read the page content",
234
+ "Use MCPBrowser's fetch_webpage to navigate to a new URL"
235
+ ]
236
+ );
237
+ } catch (err) {
238
+ logger.error(`navigate_history failed: ${err.message}`);
239
+ return new InformationalResponse(
240
+ `Navigation ${direction} failed: ${err.message}`,
241
+ 'The browser could not navigate. The page may have been closed or the connection was lost.',
242
+ [
243
+ "Try MCPBrowser's fetch_webpage to reload the page",
244
+ "Use MCPBrowser's close_tab and start fresh if needed"
245
+ ]
246
+ );
247
+ }
248
+ }
@@ -28,6 +28,7 @@ import { getCurrentHtml, GET_CURRENT_HTML_TOOL } from './actions/get-current-htm
28
28
  import { takeScreenshot, TAKE_SCREENSHOT_TOOL } from './actions/take-screenshot.js';
29
29
  import { scrollPage, SCROLL_PAGE_TOOL } from './actions/scroll-page.js';
30
30
  import { executeJavascript, EXECUTE_JAVASCRIPT_TOOL } from './actions/execute-javascript.js';
31
+ import { navigateHistory, NAVIGATE_HISTORY_TOOL } from './actions/navigate-history.js';
31
32
 
32
33
  // Import functions for testing exports
33
34
  import { getBrowser, closeBrowser } from './core/browser.js';
@@ -67,7 +68,8 @@ async function main() {
67
68
  CLOSE_TAB_TOOL,
68
69
  GET_CURRENT_HTML_TOOL,
69
70
  TAKE_SCREENSHOT_TOOL,
70
- SCROLL_PAGE_TOOL
71
+ SCROLL_PAGE_TOOL,
72
+ NAVIGATE_HISTORY_TOOL
71
73
  ];
72
74
 
73
75
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
@@ -121,6 +123,10 @@ async function main() {
121
123
  case "scroll_page":
122
124
  result = await scrollPage(safeArgs);
123
125
  break;
126
+
127
+ case "navigate_history":
128
+ result = await navigateHistory(safeArgs);
129
+ break;
124
130
 
125
131
  default:
126
132
  throw new Error(`Unknown tool: ${name}`);
@@ -171,6 +177,7 @@ export {
171
177
  getCurrentHtml,
172
178
  takeScreenshot,
173
179
  scrollPage,
180
+ navigateHistory,
174
181
  handleAcceptEula
175
182
  };
176
183