n8n-nodes-smart-browser-automation 1.3.1 → 1.4.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.
- package/dist/nodes/SmartBrowserAutomation/BrowserSessionManager.d.ts +1 -0
- package/dist/nodes/SmartBrowserAutomation/BrowserSessionManager.js +6 -0
- package/dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.d.ts +0 -1
- package/dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.js +138 -141
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@ declare class BrowserSessionManager {
|
|
|
15
15
|
initialize(mcpEndpoint: string, useCDP: boolean, cdpEndpoint?: string): Promise<MCPTool[]>;
|
|
16
16
|
callTool(toolName: string, toolArgs?: any): Promise<any>;
|
|
17
17
|
getTools(): MCPTool[];
|
|
18
|
+
listTools(): Promise<MCPTool[]>;
|
|
18
19
|
close(): Promise<void>;
|
|
19
20
|
isReady(): boolean;
|
|
20
21
|
}
|
|
@@ -93,6 +93,12 @@ class BrowserSessionManager {
|
|
|
93
93
|
getTools() {
|
|
94
94
|
return this.tools;
|
|
95
95
|
}
|
|
96
|
+
async listTools() {
|
|
97
|
+
if (!this.mcpClient || !this.isInitialized) {
|
|
98
|
+
throw new Error('MCP session not initialized. Call initialize() first.');
|
|
99
|
+
}
|
|
100
|
+
return this.tools;
|
|
101
|
+
}
|
|
96
102
|
async close() {
|
|
97
103
|
if (this.mcpClient && this.transport) {
|
|
98
104
|
await this.mcpClient.close();
|
|
@@ -6,6 +6,5 @@ export declare class SmartBrowserAutomation implements INodeType {
|
|
|
6
6
|
getAvailableTools(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
|
-
getTools(this: IExecuteFunctions): Promise<any[]>;
|
|
10
9
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
11
10
|
}
|
|
@@ -4,15 +4,15 @@ 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");
|
|
7
8
|
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',
|
|
12
12
|
name: 'smartBrowserAutomation',
|
|
13
13
|
group: ['transform'],
|
|
14
14
|
version: 1,
|
|
15
|
-
description: '
|
|
15
|
+
description: 'AI-powered browser automation via MCP Playwright server',
|
|
16
16
|
defaults: {
|
|
17
17
|
name: 'Browser Automation',
|
|
18
18
|
},
|
|
@@ -27,6 +27,14 @@ class SmartBrowserAutomation {
|
|
|
27
27
|
],
|
|
28
28
|
usableAsTool: true,
|
|
29
29
|
properties: [
|
|
30
|
+
{
|
|
31
|
+
displayName: 'CDP Endpoint Override',
|
|
32
|
+
name: 'cdpOverride',
|
|
33
|
+
type: 'string',
|
|
34
|
+
default: '',
|
|
35
|
+
placeholder: 'wss://gridnew.doingerp.com/devtools/...',
|
|
36
|
+
description: 'Override CDP endpoint from credentials. Use this to connect to a specific browser instance.',
|
|
37
|
+
},
|
|
30
38
|
{
|
|
31
39
|
displayName: 'Operation',
|
|
32
40
|
name: 'operation',
|
|
@@ -34,185 +42,174 @@ class SmartBrowserAutomation {
|
|
|
34
42
|
noDataExpression: true,
|
|
35
43
|
options: [
|
|
36
44
|
{
|
|
37
|
-
name: '
|
|
38
|
-
value: '
|
|
39
|
-
description: '
|
|
40
|
-
action: '
|
|
45
|
+
name: 'Click',
|
|
46
|
+
value: 'browser_click',
|
|
47
|
+
description: 'Click an element',
|
|
48
|
+
action: 'Click element',
|
|
41
49
|
},
|
|
42
50
|
{
|
|
43
|
-
name: '
|
|
44
|
-
value: '
|
|
45
|
-
description: '
|
|
46
|
-
action: '
|
|
51
|
+
name: 'Connect to Browser',
|
|
52
|
+
value: 'browser_connect_cdp',
|
|
53
|
+
description: 'Connect to browser via CDP',
|
|
54
|
+
action: 'Connect to browser via CDP',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'List All Tools',
|
|
58
|
+
value: 'listTools',
|
|
59
|
+
description: 'Get all available browser tools from MCP server',
|
|
60
|
+
action: 'List all browser tools',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'Navigate',
|
|
64
|
+
value: 'browser_navigate',
|
|
65
|
+
description: 'Navigate to a URL',
|
|
66
|
+
action: 'Navigate to URL',
|
|
47
67
|
},
|
|
48
|
-
],
|
|
49
|
-
default: 'initialize',
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
displayName: 'Options',
|
|
53
|
-
name: 'options',
|
|
54
|
-
type: 'collection',
|
|
55
|
-
placeholder: 'Add Option',
|
|
56
|
-
default: {},
|
|
57
|
-
options: [
|
|
58
68
|
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
placeholder: 'wss://gridnew.doingerp.com/devtools/...',
|
|
64
|
-
description: 'Browser CDP endpoint to connect to. If not provided, MCP server will launch a new browser.',
|
|
69
|
+
name: 'Take Snapshot',
|
|
70
|
+
value: 'browser_snapshot',
|
|
71
|
+
description: 'Capture page accessibility snapshot',
|
|
72
|
+
action: 'Take snapshot',
|
|
65
73
|
},
|
|
66
74
|
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
description: 'Whether to enable detailed logging',
|
|
75
|
+
name: 'Type',
|
|
76
|
+
value: 'browser_type',
|
|
77
|
+
description: 'Type text into an element',
|
|
78
|
+
action: 'Type text',
|
|
72
79
|
},
|
|
73
80
|
],
|
|
81
|
+
default: 'browser_connect_cdp',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
displayName: 'Tool Parameters',
|
|
85
|
+
name: 'toolParameters',
|
|
86
|
+
type: 'json',
|
|
87
|
+
required: true,
|
|
88
|
+
displayOptions: {
|
|
89
|
+
show: {
|
|
90
|
+
operation: [
|
|
91
|
+
'browser_connect_cdp',
|
|
92
|
+
'browser_navigate',
|
|
93
|
+
'browser_click',
|
|
94
|
+
'browser_type',
|
|
95
|
+
'browser_snapshot',
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
default: '{}',
|
|
100
|
+
description: 'Parameters to pass to the browser tool in JSON format',
|
|
74
101
|
},
|
|
75
102
|
],
|
|
76
103
|
};
|
|
77
104
|
methods = {
|
|
78
105
|
loadOptions: {
|
|
79
|
-
// Populate tool dropdown in manual mode
|
|
80
106
|
async getAvailableTools() {
|
|
81
107
|
try {
|
|
82
108
|
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
83
109
|
const sessionManager = BrowserSessionManager_1.default.getInstance();
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
];
|
|
92
|
-
if (tools && tools.length > 0) {
|
|
93
|
-
nodeTools.push(...tools.map((tool) => ({
|
|
94
|
-
name: tool.name.split('_').map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(' '),
|
|
95
|
-
value: tool.name,
|
|
96
|
-
})));
|
|
97
|
-
}
|
|
98
|
-
return nodeTools;
|
|
110
|
+
await sessionManager.initialize(credentials.mcpEndpoint, false, '');
|
|
111
|
+
const tools = await sessionManager.listTools();
|
|
112
|
+
return tools.map((tool) => ({
|
|
113
|
+
name: tool.name.split('_').map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(' '),
|
|
114
|
+
value: tool.name,
|
|
115
|
+
description: tool.description || '',
|
|
116
|
+
}));
|
|
99
117
|
}
|
|
100
118
|
catch (error) {
|
|
101
119
|
return [
|
|
102
|
-
{ name:
|
|
103
|
-
{ name: `Error loading MCP tools: ${error.message}`, value: 'error' }
|
|
120
|
+
{ name: `Error loading tools: ${error.message}`, value: 'error' }
|
|
104
121
|
];
|
|
105
122
|
}
|
|
106
123
|
},
|
|
107
124
|
},
|
|
108
125
|
};
|
|
109
|
-
// Expose tools to AI Agent nodes
|
|
110
|
-
async getTools() {
|
|
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
|
|
115
|
-
const connectTool = {
|
|
116
|
-
name: 'browser_connect_cdp',
|
|
117
|
-
displayName: 'Connect to Browser (CDP)',
|
|
118
|
-
description: 'Connect to a specific browser instance using a CDP endpoint URL',
|
|
119
|
-
properties: [
|
|
120
|
-
{
|
|
121
|
-
displayName: 'Endpoint URL',
|
|
122
|
-
name: 'endpoint',
|
|
123
|
-
type: 'string',
|
|
124
|
-
default: '',
|
|
125
|
-
required: true,
|
|
126
|
-
description: 'The wss:// or http:// CDP endpoint',
|
|
127
|
-
},
|
|
128
|
-
],
|
|
129
|
-
async execute(input) {
|
|
130
|
-
const sessionManager = BrowserSessionManager_1.default.getInstance();
|
|
131
|
-
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
132
|
-
await sessionManager.initialize(credentials.mcpEndpoint, true, input.endpoint);
|
|
133
|
-
return {
|
|
134
|
-
content: [{ type: 'text', text: `Connected to browser at ${input.endpoint}.` }],
|
|
135
|
-
isError: false,
|
|
136
|
-
toolName: 'browser_connect_cdp'
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
return [...mcpTools, connectTool];
|
|
141
|
-
}
|
|
142
126
|
async execute() {
|
|
143
|
-
const items = this.getInputData();
|
|
144
127
|
const returnData = [];
|
|
145
128
|
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
146
129
|
const sessionManager = BrowserSessionManager_1.default.getInstance();
|
|
147
|
-
|
|
130
|
+
// Get CDP override or use from credentials
|
|
131
|
+
const cdpOverride = this.getNodeParameter('cdpOverride', 0, '');
|
|
132
|
+
const operation = this.getNodeParameter('operation', 0);
|
|
133
|
+
try {
|
|
134
|
+
// Initialize session if not ready
|
|
135
|
+
if (!sessionManager.isReady()) {
|
|
136
|
+
const cdpUrl = cdpOverride || credentials.cdpEndpoint || '';
|
|
137
|
+
await sessionManager.initialize(credentials.mcpEndpoint, !!cdpUrl, cdpUrl);
|
|
138
|
+
}
|
|
139
|
+
// Handle listTools operation
|
|
140
|
+
if (operation === 'listTools') {
|
|
141
|
+
const tools = await sessionManager.listTools();
|
|
142
|
+
returnData.push({
|
|
143
|
+
json: { tools },
|
|
144
|
+
});
|
|
145
|
+
return [returnData];
|
|
146
|
+
}
|
|
147
|
+
// Handle tool execution
|
|
148
|
+
let toolParams;
|
|
148
149
|
try {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (options.cdpUrl) {
|
|
157
|
-
if (verbose) {
|
|
158
|
-
console.log(`Auto-calling 'browser_connect_cdp' with endpoint: ${options.cdpUrl}`);
|
|
159
|
-
}
|
|
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
|
-
});
|
|
167
|
-
}
|
|
168
|
-
catch (error) {
|
|
169
|
-
returnData.push({
|
|
170
|
-
json: {
|
|
171
|
-
success: false,
|
|
172
|
-
error: `Failed to connect: ${error.message}`
|
|
173
|
-
},
|
|
174
|
-
pairedItem: i,
|
|
175
|
-
});
|
|
176
|
-
}
|
|
150
|
+
const rawParams = this.getNodeParameter('toolParameters', 0);
|
|
151
|
+
if (rawParams === undefined || rawParams === null) {
|
|
152
|
+
toolParams = {};
|
|
153
|
+
}
|
|
154
|
+
else if (typeof rawParams === 'string') {
|
|
155
|
+
if (!rawParams || rawParams.trim() === '') {
|
|
156
|
+
toolParams = {};
|
|
177
157
|
}
|
|
178
158
|
else {
|
|
179
|
-
|
|
180
|
-
returnData.push({
|
|
181
|
-
json: {
|
|
182
|
-
success: true,
|
|
183
|
-
message: 'MCP session initialized (no browser connection)'
|
|
184
|
-
},
|
|
185
|
-
pairedItem: i,
|
|
186
|
-
});
|
|
159
|
+
toolParams = JSON.parse(rawParams);
|
|
187
160
|
}
|
|
188
161
|
}
|
|
189
|
-
else if (
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
162
|
+
else if (typeof rawParams === 'object') {
|
|
163
|
+
// Handle object input (when used as a tool in AI Agent)
|
|
164
|
+
toolParams = rawParams;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
try {
|
|
168
|
+
toolParams = JSON.parse(JSON.stringify(rawParams));
|
|
169
|
+
}
|
|
170
|
+
catch (parseError) {
|
|
171
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid parameter type: ${typeof rawParams}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Ensure toolParams is an object
|
|
175
|
+
if (typeof toolParams !== 'object' ||
|
|
176
|
+
toolParams === null ||
|
|
177
|
+
Array.isArray(toolParams)) {
|
|
178
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Tool parameters must be a JSON object');
|
|
198
179
|
}
|
|
199
180
|
}
|
|
200
181
|
catch (error) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
211
|
-
throw error;
|
|
182
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to parse tool parameters: ${error.message}. Make sure the parameters are valid JSON.`);
|
|
183
|
+
}
|
|
184
|
+
// Special handling for browser_connect_cdp
|
|
185
|
+
if (operation === 'browser_connect_cdp') {
|
|
186
|
+
const endpoint = toolParams.endpoint || cdpOverride || credentials.cdpEndpoint;
|
|
187
|
+
if (!endpoint) {
|
|
188
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'CDP endpoint is required. Provide it in tool parameters or CDP Endpoint Override field.');
|
|
212
189
|
}
|
|
190
|
+
// Reinitialize with new CDP endpoint
|
|
191
|
+
await sessionManager.close();
|
|
192
|
+
await sessionManager.initialize(credentials.mcpEndpoint, true, endpoint);
|
|
193
|
+
returnData.push({
|
|
194
|
+
json: {
|
|
195
|
+
result: {
|
|
196
|
+
content: [{ type: 'text', text: `Connected to browser at ${endpoint}` }],
|
|
197
|
+
isError: false,
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
return [returnData];
|
|
213
202
|
}
|
|
203
|
+
// Execute the tool via MCP
|
|
204
|
+
const result = await sessionManager.callTool(operation, toolParams);
|
|
205
|
+
returnData.push({
|
|
206
|
+
json: { result },
|
|
207
|
+
});
|
|
208
|
+
return [returnData];
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to execute operation: ${error.message}`);
|
|
214
212
|
}
|
|
215
|
-
return [returnData];
|
|
216
213
|
}
|
|
217
214
|
}
|
|
218
215
|
exports.SmartBrowserAutomation = SmartBrowserAutomation;
|