n8n-nodes-smart-browser-automation 1.0.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/LICENSE +21 -0
- package/README.md +203 -0
- package/dist/credentials/SmartBrowserAutomationApi.credentials.d.ts +7 -0
- package/dist/credentials/SmartBrowserAutomationApi.credentials.js +50 -0
- package/dist/nodes/SmartBrowserAutomation/BrowserSessionManager.d.ts +21 -0
- package/dist/nodes/SmartBrowserAutomation/BrowserSessionManager.js +72 -0
- package/dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.d.ts +11 -0
- package/dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.js +216 -0
- package/dist/nodes/SmartBrowserAutomation/tools/DynamicBrowserTools.d.ts +1 -0
- package/dist/nodes/SmartBrowserAutomation/tools/DynamicBrowserTools.js +84 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ejaz Ullah
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# n8n-nodes-smart-browser-automation
|
|
2
|
+
|
|
3
|
+
n8n community node for AI-driven browser automation using Model Context Protocol (MCP).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Two Modes**:
|
|
8
|
+
- **AI Agent Mode**: Let AI decide which browser tools to use (works with any AI model in n8n)
|
|
9
|
+
- **Manual Mode**: Choose specific browser tools from a dropdown list
|
|
10
|
+
|
|
11
|
+
- **MCP Integration**: Connect to MCP server once, reuse for all operations
|
|
12
|
+
- **Browser Flexibility**: Auto-launch browser or connect via CDP (Chrome DevTools Protocol)
|
|
13
|
+
- **Dynamic Tool Loading**: All MCP tools automatically available to AI agents
|
|
14
|
+
- **Persistent Session**: Browser stays open across multiple operations
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### Community Node Installation
|
|
19
|
+
|
|
20
|
+
1. In n8n, go to **Settings** > **Community Nodes**
|
|
21
|
+
2. Click **Install** and enter: `n8n-nodes-smart-browser-automation`
|
|
22
|
+
3. Install the node
|
|
23
|
+
|
|
24
|
+
### Manual Installation (for development)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cd ~/.n8n/custom
|
|
28
|
+
git clone https://github.com/Ejazullah42/n8n-nodes-smart-browser-automation.git
|
|
29
|
+
cd n8n-nodes-smart-browser-automation
|
|
30
|
+
npm install
|
|
31
|
+
npm run build
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Restart n8n to load the node.
|
|
35
|
+
|
|
36
|
+
## Prerequisites
|
|
37
|
+
|
|
38
|
+
1. **MCP Server**: You need a running MCP server (e.g., from `@ejazullah/smart-browser-automation`)
|
|
39
|
+
2. **Node.js**: Version 18 or higher
|
|
40
|
+
|
|
41
|
+
## Configuration
|
|
42
|
+
|
|
43
|
+
### Credentials Setup
|
|
44
|
+
|
|
45
|
+
Add new credentials for **Smart Browser Automation API**:
|
|
46
|
+
|
|
47
|
+
1. **MCP Endpoint**: URL of your MCP server (e.g., `http://localhost:3000`)
|
|
48
|
+
2. **Browser Mode**:
|
|
49
|
+
- **Auto Launch**: Automatically start a new browser
|
|
50
|
+
- **CDP Connection**: Connect to existing browser
|
|
51
|
+
3. **CDP Endpoint** (if using CDP mode): WebSocket URL (e.g., `ws://localhost:9222`)
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
### Mode 1: AI Agent (Automatic)
|
|
56
|
+
|
|
57
|
+
Use with n8n's **AI Agent** node to let AI decide which browser tools to use:
|
|
58
|
+
|
|
59
|
+
1. Add **Smart Browser Automation** node
|
|
60
|
+
2. Select **Mode**: `AI Agent (Auto)`
|
|
61
|
+
3. Operation: `Initialize Session`
|
|
62
|
+
4. Connect to **AI Agent** node
|
|
63
|
+
5. AI can now use all browser tools automatically
|
|
64
|
+
|
|
65
|
+
**Example AI Agent Workflow**:
|
|
66
|
+
```
|
|
67
|
+
Trigger → AI Agent (with Smart Browser Automation tools)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
AI Agent prompt: "Go to google.com and search for 'n8n automation', then extract the top 3 results"
|
|
71
|
+
|
|
72
|
+
The AI will automatically:
|
|
73
|
+
- Call `browser_navigate` to go to google.com
|
|
74
|
+
- Call `browser_type` to enter search text
|
|
75
|
+
- Call `browser_click` to submit
|
|
76
|
+
- Call `browser_snapshot` to see results
|
|
77
|
+
- Extract the data
|
|
78
|
+
|
|
79
|
+
### Mode 2: Manual
|
|
80
|
+
|
|
81
|
+
Choose specific tools yourself:
|
|
82
|
+
|
|
83
|
+
1. Add **Smart Browser Automation** node
|
|
84
|
+
2. Select **Mode**: `Manual`
|
|
85
|
+
3. **Tool**: Select from dropdown (browser_navigate, browser_click, etc.)
|
|
86
|
+
4. **Tool Arguments**: Provide JSON arguments
|
|
87
|
+
|
|
88
|
+
**Example Manual Workflow**:
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"url": "https://google.com"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Available Browser Tools
|
|
96
|
+
|
|
97
|
+
All MCP browser tools are dynamically loaded. Common tools include:
|
|
98
|
+
|
|
99
|
+
- `browser_navigate` - Navigate to URL
|
|
100
|
+
- `browser_click` - Click element
|
|
101
|
+
- `browser_type` - Type text into input
|
|
102
|
+
- `browser_snapshot` - Capture page accessibility tree
|
|
103
|
+
- `browser_take_screenshot` - Take screenshot
|
|
104
|
+
- `browser_evaluate` - Execute JavaScript
|
|
105
|
+
- `browser_fill_form` - Fill multiple form fields
|
|
106
|
+
- `browser_select_option` - Select dropdown option
|
|
107
|
+
- `browser_hover` - Hover over element
|
|
108
|
+
- And more...
|
|
109
|
+
|
|
110
|
+
## Example Workflows
|
|
111
|
+
|
|
112
|
+
### Example 1: AI-Driven Web Scraping
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
Webhook Trigger
|
|
116
|
+
→ Smart Browser (Initialize)
|
|
117
|
+
→ AI Agent (GPT-4)
|
|
118
|
+
- Tools: Smart Browser Automation
|
|
119
|
+
- Prompt: "Scrape product prices from example.com"
|
|
120
|
+
→ Database Node (Save results)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Example 2: Manual Form Filling
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
Trigger
|
|
127
|
+
→ Smart Browser (Manual Mode)
|
|
128
|
+
- Tool: browser_navigate
|
|
129
|
+
- Args: {"url": "https://form.com"}
|
|
130
|
+
→ Smart Browser (Manual Mode)
|
|
131
|
+
- Tool: browser_fill_form
|
|
132
|
+
- Args: {"fields": [...]}
|
|
133
|
+
→ Smart Browser (Manual Mode)
|
|
134
|
+
- Tool: browser_click
|
|
135
|
+
- Args: {"element": "Submit button"}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Example 3: Testing with Multiple AI Models
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
Trigger
|
|
142
|
+
→ Smart Browser (Initialize)
|
|
143
|
+
→ Switch Node
|
|
144
|
+
- Route to OpenAI Agent
|
|
145
|
+
- Route to Claude Agent
|
|
146
|
+
- Route to Gemini Agent
|
|
147
|
+
(All can use the same browser session)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Closing Browser Session
|
|
151
|
+
|
|
152
|
+
Always close the session when done:
|
|
153
|
+
|
|
154
|
+
1. **AI Agent Mode**: Set Operation to `Close Session`
|
|
155
|
+
2. **Manual Mode**: Switch to AI Agent mode and close
|
|
156
|
+
|
|
157
|
+
## Troubleshooting
|
|
158
|
+
|
|
159
|
+
### Browser Not Connecting
|
|
160
|
+
- Verify MCP server is running
|
|
161
|
+
- Check MCP endpoint URL
|
|
162
|
+
- For CDP mode, ensure browser is running with remote debugging
|
|
163
|
+
|
|
164
|
+
### Tools Not Appearing
|
|
165
|
+
- Click "Refresh" in the tool dropdown
|
|
166
|
+
- Verify credentials are configured correctly
|
|
167
|
+
- Check MCP server logs
|
|
168
|
+
|
|
169
|
+
### AI Not Using Tools
|
|
170
|
+
- Ensure AI Agent node has access to the tools
|
|
171
|
+
- Check AI model supports function calling
|
|
172
|
+
- Verify tool descriptions are clear
|
|
173
|
+
|
|
174
|
+
## Development
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
# Install dependencies
|
|
178
|
+
npm install
|
|
179
|
+
|
|
180
|
+
# Build
|
|
181
|
+
npm run build
|
|
182
|
+
|
|
183
|
+
# Watch mode
|
|
184
|
+
npm run dev
|
|
185
|
+
|
|
186
|
+
# Lint
|
|
187
|
+
npm run lint
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Links
|
|
191
|
+
|
|
192
|
+
- [GitHub Repository](https://github.com/Ejazullah42/n8n-nodes-smart-browser-automation)
|
|
193
|
+
- [Smart Browser Automation Library](https://github.com/Ejazullah42/smart-browser-automation)
|
|
194
|
+
- [n8n Community Nodes](https://docs.n8n.io/integrations/community-nodes/)
|
|
195
|
+
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT
|
|
200
|
+
|
|
201
|
+
## Author
|
|
202
|
+
|
|
203
|
+
Ejaz Ullah - ejaz@doinger.com
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SmartBrowserAutomationApi = void 0;
|
|
4
|
+
class SmartBrowserAutomationApi {
|
|
5
|
+
name = 'smartBrowserAutomationApi';
|
|
6
|
+
displayName = 'Smart Browser Automation API';
|
|
7
|
+
documentationUrl = 'https://github.com/Ejazullah42/smart-browser-automation';
|
|
8
|
+
properties = [
|
|
9
|
+
{
|
|
10
|
+
displayName: 'MCP Endpoint',
|
|
11
|
+
name: 'mcpEndpoint',
|
|
12
|
+
type: 'string',
|
|
13
|
+
default: 'http://localhost:3000',
|
|
14
|
+
required: true,
|
|
15
|
+
description: 'MCP server endpoint URL (set once, reused for all operations)',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
displayName: 'Browser Mode',
|
|
19
|
+
name: 'browserMode',
|
|
20
|
+
type: 'options',
|
|
21
|
+
options: [
|
|
22
|
+
{
|
|
23
|
+
name: 'Auto Launch',
|
|
24
|
+
value: 'launch',
|
|
25
|
+
description: 'Automatically launch a new browser instance',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'CDP Connection',
|
|
29
|
+
value: 'cdp',
|
|
30
|
+
description: 'Connect to existing browser via Chrome DevTools Protocol',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
default: 'launch',
|
|
34
|
+
description: 'How to connect to the browser',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
displayName: 'CDP Endpoint',
|
|
38
|
+
name: 'cdpEndpoint',
|
|
39
|
+
type: 'string',
|
|
40
|
+
default: 'ws://localhost:9222',
|
|
41
|
+
displayOptions: {
|
|
42
|
+
show: {
|
|
43
|
+
browserMode: ['cdp'],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
description: 'Chrome DevTools Protocol WebSocket URL (supports dynamic URLs)',
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
exports.SmartBrowserAutomationApi = SmartBrowserAutomationApi;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface MCPTool {
|
|
2
|
+
name: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
inputSchema?: any;
|
|
5
|
+
}
|
|
6
|
+
declare class BrowserSessionManager {
|
|
7
|
+
private static instance;
|
|
8
|
+
private mcpClient;
|
|
9
|
+
private transport;
|
|
10
|
+
private isInitialized;
|
|
11
|
+
private config;
|
|
12
|
+
private tools;
|
|
13
|
+
private constructor();
|
|
14
|
+
static getInstance(): BrowserSessionManager;
|
|
15
|
+
initialize(mcpEndpoint: string, useCDP: boolean, cdpEndpoint?: string): Promise<MCPTool[]>;
|
|
16
|
+
callTool(toolName: string, toolArgs?: any): Promise<any>;
|
|
17
|
+
getTools(): MCPTool[];
|
|
18
|
+
close(): Promise<void>;
|
|
19
|
+
isReady(): boolean;
|
|
20
|
+
}
|
|
21
|
+
export default BrowserSessionManager;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
|
|
4
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
|
|
5
|
+
class BrowserSessionManager {
|
|
6
|
+
static instance;
|
|
7
|
+
mcpClient = null;
|
|
8
|
+
transport = null;
|
|
9
|
+
isInitialized = false;
|
|
10
|
+
config = {};
|
|
11
|
+
tools = [];
|
|
12
|
+
constructor() { }
|
|
13
|
+
static getInstance() {
|
|
14
|
+
if (!BrowserSessionManager.instance) {
|
|
15
|
+
BrowserSessionManager.instance = new BrowserSessionManager();
|
|
16
|
+
}
|
|
17
|
+
return BrowserSessionManager.instance;
|
|
18
|
+
}
|
|
19
|
+
async initialize(mcpEndpoint, useCDP, cdpEndpoint) {
|
|
20
|
+
// Only initialize if not already done or config changed
|
|
21
|
+
if (this.isInitialized &&
|
|
22
|
+
this.config.mcpEndpoint === mcpEndpoint &&
|
|
23
|
+
this.config.cdpEndpoint === cdpEndpoint) {
|
|
24
|
+
return this.tools;
|
|
25
|
+
}
|
|
26
|
+
// Close existing session if config changed
|
|
27
|
+
if (this.mcpClient) {
|
|
28
|
+
await this.close();
|
|
29
|
+
}
|
|
30
|
+
// Initialize MCP client
|
|
31
|
+
this.mcpClient = new index_js_1.Client({ name: 'n8n-browser-automation', version: '1.0.0' }, { capabilities: {} });
|
|
32
|
+
// Connect to MCP server
|
|
33
|
+
this.transport = new stdio_js_1.StdioClientTransport({
|
|
34
|
+
command: 'node',
|
|
35
|
+
args: [mcpEndpoint],
|
|
36
|
+
env: useCDP && cdpEndpoint ? { CDP_URL: cdpEndpoint } : undefined
|
|
37
|
+
});
|
|
38
|
+
await this.mcpClient.connect(this.transport);
|
|
39
|
+
// Fetch available tools from MCP server
|
|
40
|
+
const toolsResponse = await this.mcpClient.listTools();
|
|
41
|
+
this.tools = toolsResponse.tools || [];
|
|
42
|
+
this.config = { mcpEndpoint, cdpEndpoint };
|
|
43
|
+
this.isInitialized = true;
|
|
44
|
+
return this.tools;
|
|
45
|
+
}
|
|
46
|
+
async callTool(toolName, toolArgs) {
|
|
47
|
+
if (!this.mcpClient || !this.isInitialized) {
|
|
48
|
+
throw new Error('MCP client not initialized. Please configure credentials first.');
|
|
49
|
+
}
|
|
50
|
+
const result = await this.mcpClient.callTool({
|
|
51
|
+
name: toolName,
|
|
52
|
+
arguments: toolArgs || {}
|
|
53
|
+
});
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
getTools() {
|
|
57
|
+
return this.tools;
|
|
58
|
+
}
|
|
59
|
+
async close() {
|
|
60
|
+
if (this.mcpClient && this.transport) {
|
|
61
|
+
await this.mcpClient.close();
|
|
62
|
+
this.mcpClient = null;
|
|
63
|
+
this.transport = null;
|
|
64
|
+
this.isInitialized = false;
|
|
65
|
+
this.tools = [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
isReady() {
|
|
69
|
+
return this.isInitialized && this.mcpClient !== null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.default = BrowserSessionManager;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IExecuteFunctions, ILoadOptionsFunctions, INodeExecutionData, INodePropertyOptions, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class SmartBrowserAutomation implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
methods: {
|
|
5
|
+
loadOptions: {
|
|
6
|
+
getAvailableTools(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
getTools?(this: IExecuteFunctions): Promise<any[]>;
|
|
10
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SmartBrowserAutomation = void 0;
|
|
7
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
8
|
+
const DynamicBrowserTools_1 = require("./tools/DynamicBrowserTools");
|
|
9
|
+
const BrowserSessionManager_1 = __importDefault(require("./BrowserSessionManager"));
|
|
10
|
+
class SmartBrowserAutomation {
|
|
11
|
+
description = {
|
|
12
|
+
displayName: 'Smart Browser Automation',
|
|
13
|
+
name: 'smartBrowserAutomation',
|
|
14
|
+
group: ['transform'],
|
|
15
|
+
version: 1,
|
|
16
|
+
description: 'Browser automation with AI Agent mode (auto) or Manual mode (user choice)',
|
|
17
|
+
defaults: {
|
|
18
|
+
name: 'Browser Automation',
|
|
19
|
+
},
|
|
20
|
+
inputs: ['main'],
|
|
21
|
+
outputs: ['main'],
|
|
22
|
+
credentials: [
|
|
23
|
+
{
|
|
24
|
+
name: 'smartBrowserAutomationApi',
|
|
25
|
+
required: true,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
properties: [
|
|
29
|
+
{
|
|
30
|
+
displayName: 'Mode',
|
|
31
|
+
name: 'mode',
|
|
32
|
+
type: 'options',
|
|
33
|
+
noDataExpression: true,
|
|
34
|
+
options: [
|
|
35
|
+
{
|
|
36
|
+
name: 'AI Agent (Auto)',
|
|
37
|
+
value: 'aiAgent',
|
|
38
|
+
description: 'Let AI decide which tools to use - use this with AI Agent node',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'Manual',
|
|
42
|
+
value: 'manual',
|
|
43
|
+
description: 'Manually select tool and provide arguments',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
default: 'aiAgent',
|
|
47
|
+
description: 'How to execute browser automation',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
displayName: 'Tool Name or ID',
|
|
51
|
+
name: 'toolName',
|
|
52
|
+
type: 'options',
|
|
53
|
+
typeOptions: {
|
|
54
|
+
loadOptionsMethod: 'getAvailableTools',
|
|
55
|
+
},
|
|
56
|
+
displayOptions: {
|
|
57
|
+
show: {
|
|
58
|
+
mode: ['manual'],
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
default: '',
|
|
62
|
+
description: 'Select the browser automation tool to execute. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
63
|
+
required: true,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
displayName: 'Tool Arguments',
|
|
67
|
+
name: 'toolArgs',
|
|
68
|
+
type: 'json',
|
|
69
|
+
displayOptions: {
|
|
70
|
+
show: {
|
|
71
|
+
mode: ['manual'],
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
default: '{}',
|
|
75
|
+
description: 'Arguments for the selected tool in JSON format',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
displayName: 'Operation',
|
|
79
|
+
name: 'operation',
|
|
80
|
+
type: 'options',
|
|
81
|
+
noDataExpression: true,
|
|
82
|
+
displayOptions: {
|
|
83
|
+
show: {
|
|
84
|
+
mode: ['aiAgent'],
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
options: [
|
|
88
|
+
{
|
|
89
|
+
name: 'Initialize Session',
|
|
90
|
+
value: 'initialize',
|
|
91
|
+
description: 'Initialize browser session and load available tools',
|
|
92
|
+
action: 'Initialize browser session and load available tools',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'Close Session',
|
|
96
|
+
value: 'close',
|
|
97
|
+
description: 'Close browser session and cleanup',
|
|
98
|
+
action: 'Close browser session and cleanup',
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
default: 'initialize',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
displayName: 'Verbose',
|
|
105
|
+
name: 'verbose',
|
|
106
|
+
type: 'boolean',
|
|
107
|
+
default: false,
|
|
108
|
+
description: 'Whether to enable detailed logging',
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
methods = {
|
|
113
|
+
loadOptions: {
|
|
114
|
+
// Populate tool dropdown in manual mode
|
|
115
|
+
async getAvailableTools() {
|
|
116
|
+
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
117
|
+
const sessionManager = BrowserSessionManager_1.default.getInstance();
|
|
118
|
+
const tools = await sessionManager.initialize(credentials.mcpEndpoint, credentials.browserMode === 'cdp', credentials.cdpEndpoint);
|
|
119
|
+
return tools.map((tool) => ({
|
|
120
|
+
name: tool.name.split('_').map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(' '),
|
|
121
|
+
value: tool.name,
|
|
122
|
+
}));
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
// Expose tools to AI Agent nodes
|
|
127
|
+
async getTools() {
|
|
128
|
+
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
129
|
+
return await (0, DynamicBrowserTools_1.createDynamicBrowserTools)(credentials);
|
|
130
|
+
}
|
|
131
|
+
async execute() {
|
|
132
|
+
const items = this.getInputData();
|
|
133
|
+
const returnData = [];
|
|
134
|
+
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
135
|
+
const sessionManager = BrowserSessionManager_1.default.getInstance();
|
|
136
|
+
const mode = this.getNodeParameter('mode', 0);
|
|
137
|
+
for (let i = 0; i < items.length; i++) {
|
|
138
|
+
try {
|
|
139
|
+
if (mode === 'manual') {
|
|
140
|
+
// Manual mode: User selects tool and provides arguments
|
|
141
|
+
const toolName = this.getNodeParameter('toolName', i);
|
|
142
|
+
const toolArgsStr = this.getNodeParameter('toolArgs', i);
|
|
143
|
+
const verbose = this.getNodeParameter('verbose', i, false);
|
|
144
|
+
// Initialize session if not ready
|
|
145
|
+
if (!sessionManager.isReady()) {
|
|
146
|
+
await sessionManager.initialize(credentials.mcpEndpoint, credentials.browserMode === 'cdp', credentials.cdpEndpoint);
|
|
147
|
+
}
|
|
148
|
+
let toolArgs;
|
|
149
|
+
try {
|
|
150
|
+
toolArgs = JSON.parse(toolArgsStr);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid JSON in Tool Arguments: ${error.message} `);
|
|
154
|
+
}
|
|
155
|
+
if (verbose) {
|
|
156
|
+
console.log(`Executing tool: ${toolName} with args: `, toolArgs);
|
|
157
|
+
}
|
|
158
|
+
const result = await sessionManager.callTool(toolName, toolArgs);
|
|
159
|
+
returnData.push({
|
|
160
|
+
json: {
|
|
161
|
+
success: true,
|
|
162
|
+
tool: toolName,
|
|
163
|
+
result,
|
|
164
|
+
},
|
|
165
|
+
pairedItem: i,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// AI Agent mode: Just initialize or close
|
|
170
|
+
const operation = this.getNodeParameter('operation', i);
|
|
171
|
+
if (operation === 'initialize') {
|
|
172
|
+
const tools = await sessionManager.initialize(credentials.mcpEndpoint, credentials.browserMode === 'cdp', credentials.cdpEndpoint);
|
|
173
|
+
returnData.push({
|
|
174
|
+
json: {
|
|
175
|
+
success: true,
|
|
176
|
+
message: 'Browser session initialized. Tools are now available to AI Agent.',
|
|
177
|
+
toolsCount: tools.length,
|
|
178
|
+
tools: tools.map((t) => ({
|
|
179
|
+
name: t.name,
|
|
180
|
+
description: t.description
|
|
181
|
+
})),
|
|
182
|
+
},
|
|
183
|
+
pairedItem: i,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
else if (operation === 'close') {
|
|
187
|
+
await sessionManager.close();
|
|
188
|
+
returnData.push({
|
|
189
|
+
json: {
|
|
190
|
+
success: true,
|
|
191
|
+
message: 'Browser session closed',
|
|
192
|
+
},
|
|
193
|
+
pairedItem: i,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
if (this.continueOnFail()) {
|
|
200
|
+
returnData.push({
|
|
201
|
+
json: {
|
|
202
|
+
success: false,
|
|
203
|
+
error: error.message
|
|
204
|
+
},
|
|
205
|
+
pairedItem: i,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return [returnData];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
exports.SmartBrowserAutomation = SmartBrowserAutomation;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function createDynamicBrowserTools(credentials: any): Promise<any[]>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createDynamicBrowserTools = createDynamicBrowserTools;
|
|
7
|
+
const BrowserSessionManager_1 = __importDefault(require("../BrowserSessionManager"));
|
|
8
|
+
// Convert MCP tool schema to n8n properties
|
|
9
|
+
function mcpSchemaToN8nProperties(mcpSchema) {
|
|
10
|
+
const properties = [];
|
|
11
|
+
if (!mcpSchema || !mcpSchema.properties) {
|
|
12
|
+
return properties;
|
|
13
|
+
}
|
|
14
|
+
for (const [key, value] of Object.entries(mcpSchema.properties)) {
|
|
15
|
+
const prop = value;
|
|
16
|
+
const nodeProperty = {
|
|
17
|
+
displayName: key.charAt(0).toUpperCase() + key.slice(1).replace(/_/g, ' '),
|
|
18
|
+
name: key,
|
|
19
|
+
type: 'string',
|
|
20
|
+
default: '',
|
|
21
|
+
description: prop.description || '',
|
|
22
|
+
required: mcpSchema.required?.includes(key) || false,
|
|
23
|
+
};
|
|
24
|
+
// Map types from JSON Schema to n8n types
|
|
25
|
+
if (prop.type === 'boolean') {
|
|
26
|
+
nodeProperty.type = 'boolean';
|
|
27
|
+
nodeProperty.default = false;
|
|
28
|
+
}
|
|
29
|
+
else if (prop.type === 'number' || prop.type === 'integer') {
|
|
30
|
+
nodeProperty.type = 'number';
|
|
31
|
+
nodeProperty.default = 0;
|
|
32
|
+
}
|
|
33
|
+
else if (prop.type === 'object' || prop.type === 'array') {
|
|
34
|
+
nodeProperty.type = 'json';
|
|
35
|
+
nodeProperty.default = prop.type === 'array' ? '[]' : '{}';
|
|
36
|
+
}
|
|
37
|
+
// Handle enums
|
|
38
|
+
if (prop.enum && Array.isArray(prop.enum)) {
|
|
39
|
+
nodeProperty.type = 'options';
|
|
40
|
+
nodeProperty.options = prop.enum.map((val) => ({
|
|
41
|
+
name: String(val),
|
|
42
|
+
value: val,
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
properties.push(nodeProperty);
|
|
46
|
+
}
|
|
47
|
+
return properties;
|
|
48
|
+
}
|
|
49
|
+
// Create n8n tool instances from MCP tools
|
|
50
|
+
async function createDynamicBrowserTools(credentials) {
|
|
51
|
+
const sessionManager = BrowserSessionManager_1.default.getInstance();
|
|
52
|
+
// Initialize and get MCP tools
|
|
53
|
+
const mcpTools = await sessionManager.initialize(credentials.mcpEndpoint, credentials.browserMode === 'cdp', credentials.cdpEndpoint);
|
|
54
|
+
// Create n8n tool for each MCP tool
|
|
55
|
+
const n8nTools = mcpTools.map((mcpTool) => {
|
|
56
|
+
const toolName = mcpTool.name;
|
|
57
|
+
const displayName = toolName
|
|
58
|
+
.split('_')
|
|
59
|
+
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
|
60
|
+
.join(' ');
|
|
61
|
+
return {
|
|
62
|
+
name: toolName,
|
|
63
|
+
displayName: displayName,
|
|
64
|
+
description: mcpTool.description || `Execute ${displayName} browser action`,
|
|
65
|
+
properties: mcpSchemaToN8nProperties(mcpTool.inputSchema),
|
|
66
|
+
async execute(toolInput) {
|
|
67
|
+
try {
|
|
68
|
+
const result = await sessionManager.callTool(toolName, toolInput);
|
|
69
|
+
return {
|
|
70
|
+
success: true,
|
|
71
|
+
result: JSON.stringify(result, null, 2),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
error: error.message || 'Unknown error occurred',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
return n8nTools;
|
|
84
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-smart-browser-automation",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "n8n node for AI-driven browser automation using MCP",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"browser-automation",
|
|
8
|
+
"ai",
|
|
9
|
+
"mcp",
|
|
10
|
+
"playwright"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"homepage": "https://github.com/Ejazullah42/n8n-nodes-smart-browser-automation",
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "Ejaz Ullah",
|
|
16
|
+
"email": "ejaz@doinger.com"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/Ejazullah42/n8n-nodes-smart-browser-automation.git"
|
|
21
|
+
},
|
|
22
|
+
"main": "index.js",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc && gulp build:icons",
|
|
25
|
+
"dev": "tsc --watch",
|
|
26
|
+
"format": "prettier nodes credentials --write",
|
|
27
|
+
"lint": "eslint \"nodes/**/*.ts\" \"credentials/**/*.ts\"",
|
|
28
|
+
"lintfix": "eslint \"nodes/**/*.ts\" \"credentials/**/*.ts\" --fix",
|
|
29
|
+
"prepublishOnly": "npm run build && npm run lint"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"n8n": {
|
|
35
|
+
"n8nNodesApiVersion": 1,
|
|
36
|
+
"credentials": [
|
|
37
|
+
"dist/credentials/SmartBrowserAutomationApi.credentials.js"
|
|
38
|
+
],
|
|
39
|
+
"nodes": [
|
|
40
|
+
"dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.js"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^20.10.0",
|
|
45
|
+
"@typescript-eslint/parser": "^6.13.0",
|
|
46
|
+
"eslint": "^8.55.0",
|
|
47
|
+
"eslint-plugin-n8n-nodes-base": "^1.16.1",
|
|
48
|
+
"gulp": "^4.0.2",
|
|
49
|
+
"n8n-workflow": "^1.0.0",
|
|
50
|
+
"prettier": "^3.1.0",
|
|
51
|
+
"typescript": "^5.3.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"n8n-workflow": "*"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@modelcontextprotocol/sdk": "^1.17.0"
|
|
58
|
+
}
|
|
59
|
+
}
|