n8n-nodes-smart-browser-automation 1.1.13 → 1.3.0
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.
|
@@ -75,14 +75,14 @@ class BrowserSessionManager {
|
|
|
75
75
|
throw new Error('MCP client not initialized. Please configure credentials first.');
|
|
76
76
|
}
|
|
77
77
|
try {
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
console.log(`[MCP] Calling tool "${toolName}" with args:`, JSON.stringify(toolArgs || {}));
|
|
81
|
-
}
|
|
78
|
+
// Log tool call for debugging
|
|
79
|
+
console.log(`[MCP] Calling tool "${toolName}" with args:`, JSON.stringify(toolArgs || {}));
|
|
82
80
|
const result = await this.mcpClient.callTool({
|
|
83
81
|
name: toolName,
|
|
84
82
|
arguments: toolArgs || {}
|
|
85
83
|
});
|
|
84
|
+
// Log the response for debugging
|
|
85
|
+
console.log(`[MCP] Tool "${toolName}" response:`, JSON.stringify(result, null, 2));
|
|
86
86
|
return result;
|
|
87
87
|
}
|
|
88
88
|
catch (error) {
|
|
@@ -4,8 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.SmartBrowserAutomation = void 0;
|
|
7
|
-
const n8n_workflow_1 = require("n8n-workflow");
|
|
8
7
|
const BrowserSessionManager_1 = __importDefault(require("./BrowserSessionManager"));
|
|
8
|
+
const DynamicBrowserTools_1 = require("./tools/DynamicBrowserTools");
|
|
9
9
|
class SmartBrowserAutomation {
|
|
10
10
|
description = {
|
|
11
11
|
displayName: 'Smart Browser Automation',
|
|
@@ -27,81 +27,11 @@ class SmartBrowserAutomation {
|
|
|
27
27
|
],
|
|
28
28
|
usableAsTool: true,
|
|
29
29
|
properties: [
|
|
30
|
-
{
|
|
31
|
-
displayName: 'Mode',
|
|
32
|
-
name: 'mode',
|
|
33
|
-
type: 'options',
|
|
34
|
-
noDataExpression: true,
|
|
35
|
-
options: [
|
|
36
|
-
{
|
|
37
|
-
name: 'AI Agent (Auto)',
|
|
38
|
-
value: 'aiAgent',
|
|
39
|
-
description: 'Let AI decide which tools to use - use this with AI Agent node',
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
name: 'Manual',
|
|
43
|
-
value: 'manual',
|
|
44
|
-
description: 'Manually select tool and provide arguments',
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
default: 'aiAgent',
|
|
48
|
-
description: 'How to execute browser automation',
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
displayName: 'Tool Name or ID',
|
|
52
|
-
name: 'toolName',
|
|
53
|
-
type: 'options',
|
|
54
|
-
typeOptions: {
|
|
55
|
-
loadOptionsMethod: 'getAvailableTools',
|
|
56
|
-
},
|
|
57
|
-
displayOptions: {
|
|
58
|
-
show: {
|
|
59
|
-
mode: ['manual'],
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
default: 'browser_connect_cdp',
|
|
63
|
-
description: 'Select the browser automation tool to execute. Choose "Connect to Browser (CDP)" to initialize/switch browser sessions. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
64
|
-
required: true,
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
displayName: 'CDP Endpoint',
|
|
68
|
-
name: 'cdpUrl',
|
|
69
|
-
type: 'string',
|
|
70
|
-
displayOptions: {
|
|
71
|
-
show: {
|
|
72
|
-
mode: ['manual'],
|
|
73
|
-
toolName: ['browser_connect_cdp'],
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
default: '',
|
|
77
|
-
placeholder: 'wss://gridnew.doingerp.com/devtools/...',
|
|
78
|
-
description: 'The wss:// or http:// endpoint for the browser CDP connection',
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
displayName: 'Tool Arguments',
|
|
82
|
-
name: 'toolArgs',
|
|
83
|
-
type: 'json',
|
|
84
|
-
displayOptions: {
|
|
85
|
-
show: {
|
|
86
|
-
mode: ['manual'],
|
|
87
|
-
},
|
|
88
|
-
hide: {
|
|
89
|
-
toolName: ['browser_connect_cdp'],
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
default: '{}',
|
|
93
|
-
description: 'Arguments for the selected tool in JSON format',
|
|
94
|
-
},
|
|
95
30
|
{
|
|
96
31
|
displayName: 'Operation',
|
|
97
32
|
name: 'operation',
|
|
98
33
|
type: 'options',
|
|
99
34
|
noDataExpression: true,
|
|
100
|
-
displayOptions: {
|
|
101
|
-
show: {
|
|
102
|
-
mode: ['aiAgent'],
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
35
|
options: [
|
|
106
36
|
{
|
|
107
37
|
name: 'Initialize Session',
|
|
@@ -124,11 +54,6 @@ class SmartBrowserAutomation {
|
|
|
124
54
|
type: 'collection',
|
|
125
55
|
placeholder: 'Add Option',
|
|
126
56
|
default: {},
|
|
127
|
-
displayOptions: {
|
|
128
|
-
show: {
|
|
129
|
-
mode: ['aiAgent'],
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
57
|
options: [
|
|
133
58
|
{
|
|
134
59
|
displayName: 'CDP Endpoint',
|
|
@@ -136,20 +61,10 @@ class SmartBrowserAutomation {
|
|
|
136
61
|
type: 'string',
|
|
137
62
|
default: '',
|
|
138
63
|
placeholder: 'wss://gridnew.doingerp.com/devtools/...',
|
|
139
|
-
description: '
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
displayName: 'Enabled Tool Names or IDs',
|
|
143
|
-
name: 'enabledTools',
|
|
144
|
-
type: 'multiOptions',
|
|
145
|
-
typeOptions: {
|
|
146
|
-
loadOptionsMethod: 'getAvailableTools',
|
|
147
|
-
},
|
|
148
|
-
default: [],
|
|
149
|
-
description: 'Select which tools to expose to the AI Agent or Manual list. Leave empty for all. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
64
|
+
description: 'Browser CDP endpoint to connect to. If not provided, MCP server will launch a new browser.',
|
|
150
65
|
},
|
|
151
66
|
{
|
|
152
|
-
displayName: 'Verbose',
|
|
67
|
+
displayName: 'Verbose Logging',
|
|
153
68
|
name: 'verbose',
|
|
154
69
|
type: 'boolean',
|
|
155
70
|
default: false,
|
|
@@ -193,99 +108,14 @@ class SmartBrowserAutomation {
|
|
|
193
108
|
};
|
|
194
109
|
// Expose tools to AI Agent nodes
|
|
195
110
|
async getTools() {
|
|
196
|
-
|
|
197
|
-
//
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
displayName: 'Browser Action',
|
|
201
|
-
description: `Perform browser automation actions.
|
|
202
|
-
USAGE EXAMPLES:
|
|
203
|
-
- Navigate: action='navigate', params={ "url": "https://..." }
|
|
204
|
-
- Click: action='click', params={ "selector": "button.submit" }
|
|
205
|
-
- Type: action='type', params={ "selector": "#input", "text": "hello" }
|
|
206
|
-
- Scroll: action='scroll_to', params={ "selector": "footer" }
|
|
207
|
-
- Get Text: action='get_text', params={ "selector": ".content" }
|
|
208
|
-
- Screenshot: action='take_screenshot', params={}
|
|
209
|
-
|
|
210
|
-
Available actions: navigate, click, type, press_key, scroll_to, get_text, take_screenshot, evaluate, etc.
|
|
211
|
-
Supported Params depend on the action.`,
|
|
212
|
-
properties: [
|
|
213
|
-
{
|
|
214
|
-
displayName: 'Action Name',
|
|
215
|
-
name: 'action',
|
|
216
|
-
type: 'string',
|
|
217
|
-
required: true,
|
|
218
|
-
default: '',
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
displayName: 'Parameters',
|
|
222
|
-
name: 'params',
|
|
223
|
-
type: 'json',
|
|
224
|
-
default: '{}',
|
|
225
|
-
description: 'JSON parameters for the action (e.g., { "URL": "..." })',
|
|
226
|
-
},
|
|
227
|
-
],
|
|
228
|
-
async execute(input) {
|
|
229
|
-
const sessionManager = BrowserSessionManager_1.default.getInstance();
|
|
230
|
-
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
231
|
-
// Ensure session is initialized
|
|
232
|
-
if (!sessionManager.isReady()) {
|
|
233
|
-
// Check for connection tool usage specifically
|
|
234
|
-
if (input.action === 'connect_cdp' || input.action === 'browser_connect_cdp') {
|
|
235
|
-
const endpoint = input.params?.endpoint;
|
|
236
|
-
if (endpoint) {
|
|
237
|
-
await sessionManager.initialize(credentials.mcpEndpoint, true, endpoint);
|
|
238
|
-
return {
|
|
239
|
-
content: [{ type: 'text', text: `Connected to browser at ${endpoint}.` }],
|
|
240
|
-
isError: false,
|
|
241
|
-
toolName: 'browser_connect_cdp',
|
|
242
|
-
requestedAction: input.action
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
// Auto-initialize if possible (blindly)
|
|
247
|
-
await sessionManager.initialize(credentials.mcpEndpoint, credentials.browserMode === 'cdp', credentials.cdpEndpoint);
|
|
248
|
-
}
|
|
249
|
-
// Normalize action name
|
|
250
|
-
let toolName = input.action;
|
|
251
|
-
if (!toolName.startsWith('browser_') && toolName !== 'connect_cdp') {
|
|
252
|
-
toolName = `browser_${toolName}`;
|
|
253
|
-
}
|
|
254
|
-
// Handle params
|
|
255
|
-
let toolArgs = input.params || {};
|
|
256
|
-
if (typeof toolArgs === 'string') {
|
|
257
|
-
try {
|
|
258
|
-
toolArgs = JSON.parse(toolArgs);
|
|
259
|
-
}
|
|
260
|
-
catch (e) {
|
|
261
|
-
// ignore
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
console.log(`[Router] Routing '${input.action}' to '${toolName}' with args:`, toolArgs);
|
|
265
|
-
try {
|
|
266
|
-
const result = await sessionManager.callTool(toolName, toolArgs);
|
|
267
|
-
// Add tool name to result for visibility
|
|
268
|
-
if (result && typeof result === 'object') {
|
|
269
|
-
result.toolName = toolName;
|
|
270
|
-
result.requestedAction = input.action;
|
|
271
|
-
}
|
|
272
|
-
return result;
|
|
273
|
-
}
|
|
274
|
-
catch (error) {
|
|
275
|
-
return {
|
|
276
|
-
content: [{ type: 'text', text: `Error executing ${toolName}: ${error.message}` }],
|
|
277
|
-
isError: true,
|
|
278
|
-
toolName: toolName,
|
|
279
|
-
requestedAction: input.action
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
// Add a custom tool for specific CDP connection (legacy support)
|
|
111
|
+
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
112
|
+
// Get all individual MCP tools
|
|
113
|
+
const mcpTools = await (0, DynamicBrowserTools_1.createDynamicBrowserTools)(credentials);
|
|
114
|
+
// Add custom CDP connection tool
|
|
285
115
|
const connectTool = {
|
|
286
116
|
name: 'browser_connect_cdp',
|
|
287
117
|
displayName: 'Connect to Browser (CDP)',
|
|
288
|
-
description: 'Connect to a specific browser instance using a CDP
|
|
118
|
+
description: 'Connect to a specific browser instance using a CDP endpoint URL',
|
|
289
119
|
properties: [
|
|
290
120
|
{
|
|
291
121
|
displayName: 'Endpoint URL',
|
|
@@ -293,7 +123,7 @@ class SmartBrowserAutomation {
|
|
|
293
123
|
type: 'string',
|
|
294
124
|
default: '',
|
|
295
125
|
required: true,
|
|
296
|
-
description: 'The wss:// or http:// endpoint',
|
|
126
|
+
description: 'The wss:// or http:// CDP endpoint',
|
|
297
127
|
},
|
|
298
128
|
],
|
|
299
129
|
async execute(input) {
|
|
@@ -307,113 +137,65 @@ class SmartBrowserAutomation {
|
|
|
307
137
|
};
|
|
308
138
|
}
|
|
309
139
|
};
|
|
310
|
-
return [
|
|
140
|
+
return [...mcpTools, connectTool];
|
|
311
141
|
}
|
|
312
142
|
async execute() {
|
|
313
143
|
const items = this.getInputData();
|
|
314
144
|
const returnData = [];
|
|
315
145
|
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
316
146
|
const sessionManager = BrowserSessionManager_1.default.getInstance();
|
|
317
|
-
const mode = this.getNodeParameter('mode', 0);
|
|
318
147
|
for (let i = 0; i < items.length; i++) {
|
|
319
148
|
try {
|
|
320
149
|
const options = this.getNodeParameter('options', i, {});
|
|
321
150
|
const verbose = options.verbose || false;
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (!endpoint) {
|
|
329
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'CDP Endpoint URL is required for browser_connect_cdp');
|
|
330
|
-
}
|
|
151
|
+
const operation = this.getNodeParameter('operation', i);
|
|
152
|
+
if (operation === 'initialize') {
|
|
153
|
+
const cdpUrl = credentials.cdpEndpoint;
|
|
154
|
+
await sessionManager.initialize(credentials.mcpEndpoint, true, cdpUrl);
|
|
155
|
+
// New logic: Auto-call browser_connect_cdp tool if a URL is provided
|
|
156
|
+
if (options.cdpUrl) {
|
|
331
157
|
if (verbose) {
|
|
332
|
-
console.log(`
|
|
158
|
+
console.log(`Auto-calling 'browser_connect_cdp' with endpoint: ${options.cdpUrl}`);
|
|
333
159
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
pairedItem: i,
|
|
342
|
-
});
|
|
343
|
-
continue;
|
|
344
|
-
}
|
|
345
|
-
const toolArgsStr = this.getNodeParameter('toolArgs', i);
|
|
346
|
-
let toolArgs;
|
|
347
|
-
try {
|
|
348
|
-
toolArgs = JSON.parse(toolArgsStr);
|
|
349
|
-
}
|
|
350
|
-
catch (error) {
|
|
351
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid JSON in Tool Arguments: ${error.message}`);
|
|
352
|
-
}
|
|
353
|
-
// Initialize session if not ready
|
|
354
|
-
if (!sessionManager.isReady()) {
|
|
355
|
-
await sessionManager.initialize(credentials.mcpEndpoint, credentials.browserMode === 'cdp', credentials.cdpEndpoint);
|
|
356
|
-
}
|
|
357
|
-
if (verbose) {
|
|
358
|
-
console.log(`Executing tool: ${toolName} with args:`, toolArgs);
|
|
359
|
-
}
|
|
360
|
-
const result = await sessionManager.callTool(toolName, toolArgs);
|
|
361
|
-
returnData.push({
|
|
362
|
-
json: result,
|
|
363
|
-
pairedItem: i,
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
// AI Agent mode: Just initialize or close
|
|
368
|
-
const operation = this.getNodeParameter('operation', i);
|
|
369
|
-
if (operation === 'initialize') {
|
|
370
|
-
const cdpUrl = credentials.cdpEndpoint;
|
|
371
|
-
await sessionManager.initialize(credentials.mcpEndpoint, true, cdpUrl);
|
|
372
|
-
// New logic: Auto-call browser_connect_cdp tool if a URL is provided
|
|
373
|
-
if (options.cdpUrl) {
|
|
374
|
-
if (verbose) {
|
|
375
|
-
console.log(`Auto-calling 'browser_connect_cdp' with endpoint: ${options.cdpUrl}`);
|
|
376
|
-
}
|
|
377
|
-
try {
|
|
378
|
-
const connectionResult = await sessionManager.callTool('browser_connect_cdp', { endpoint: options.cdpUrl });
|
|
379
|
-
// Return only the connection result, no extra messages
|
|
380
|
-
returnData.push({
|
|
381
|
-
json: connectionResult,
|
|
382
|
-
pairedItem: i,
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
catch (error) {
|
|
386
|
-
returnData.push({
|
|
387
|
-
json: {
|
|
388
|
-
success: false,
|
|
389
|
-
error: `Failed to connect: ${error.message}`
|
|
390
|
-
},
|
|
391
|
-
pairedItem: i,
|
|
392
|
-
});
|
|
393
|
-
}
|
|
160
|
+
try {
|
|
161
|
+
const connectionResult = await sessionManager.callTool('browser_connect_cdp', { endpoint: options.cdpUrl });
|
|
162
|
+
// Return only the connection result, no extra messages
|
|
163
|
+
returnData.push({
|
|
164
|
+
json: connectionResult,
|
|
165
|
+
pairedItem: i,
|
|
166
|
+
});
|
|
394
167
|
}
|
|
395
|
-
|
|
396
|
-
// No CDP URL provided
|
|
168
|
+
catch (error) {
|
|
397
169
|
returnData.push({
|
|
398
170
|
json: {
|
|
399
|
-
success:
|
|
400
|
-
|
|
171
|
+
success: false,
|
|
172
|
+
error: `Failed to connect: ${error.message}`
|
|
401
173
|
},
|
|
402
174
|
pairedItem: i,
|
|
403
175
|
});
|
|
404
176
|
}
|
|
405
177
|
}
|
|
406
|
-
else
|
|
407
|
-
|
|
178
|
+
else {
|
|
179
|
+
// No CDP URL provided
|
|
408
180
|
returnData.push({
|
|
409
181
|
json: {
|
|
410
182
|
success: true,
|
|
411
|
-
message: '
|
|
183
|
+
message: 'MCP session initialized (no browser connection)'
|
|
412
184
|
},
|
|
413
185
|
pairedItem: i,
|
|
414
186
|
});
|
|
415
187
|
}
|
|
416
188
|
}
|
|
189
|
+
else if (operation === 'close') {
|
|
190
|
+
await sessionManager.close();
|
|
191
|
+
returnData.push({
|
|
192
|
+
json: {
|
|
193
|
+
success: true,
|
|
194
|
+
message: 'Browser session closed',
|
|
195
|
+
},
|
|
196
|
+
pairedItem: i,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
417
199
|
}
|
|
418
200
|
catch (error) {
|
|
419
201
|
if (this.continueOnFail()) {
|