n8n-nodes-smart-browser-automation 1.6.5 → 1.6.6
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 +7 -6
- package/dist/nodes/SmartBrowserAutomation/BrowserSessionManager.d.ts +1 -0
- package/dist/nodes/SmartBrowserAutomation/BrowserSessionManager.js +38 -5
- package/dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.js +14 -1
- package/dist/nodes/SmartBrowserAutomation/SmartBrowserAutomationTools.node.d.ts +5 -0
- package/dist/nodes/SmartBrowserAutomation/SmartBrowserAutomationTools.node.js +121 -0
- package/dist/nodes/SmartBrowserAutomation/jsonSchemaToZod.d.ts +16 -0
- package/dist/nodes/SmartBrowserAutomation/jsonSchemaToZod.js +108 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -54,13 +54,14 @@ Add new credentials for **Smart Browser Automation API**:
|
|
|
54
54
|
|
|
55
55
|
### Mode 1: AI Agent (Automatic)
|
|
56
56
|
|
|
57
|
-
Use with n8n's **AI Agent** node to let AI decide which browser tools to use
|
|
57
|
+
Use with n8n's **AI Agent** node to let AI decide which browser tools to use.
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
Use the dedicated tool node so the agent can discover each MCP tool and its JSON-schema arguments:
|
|
60
|
+
|
|
61
|
+
1. Add **Smart Browser Automation Tools** node
|
|
62
|
+
2. Configure credentials (MCP endpoint + browser mode)
|
|
63
|
+
3. Connect its **Tools** output to **AI Agent**
|
|
64
|
+
4. The agent can now call MCP tools (e.g. `browser_navigate`, `browser_click`) with correct argument schemas
|
|
64
65
|
|
|
65
66
|
**Example AI Agent Workflow**:
|
|
66
67
|
```
|
|
@@ -13,6 +13,7 @@ declare class BrowserSessionManager {
|
|
|
13
13
|
private constructor();
|
|
14
14
|
static getInstance(): BrowserSessionManager;
|
|
15
15
|
initialize(mcpEndpoint: string, useCDP: boolean, cdpEndpoint?: string): Promise<MCPTool[]>;
|
|
16
|
+
private getAllTools;
|
|
16
17
|
callTool(toolName: string, toolArgs?: any): Promise<any>;
|
|
17
18
|
getTools(): MCPTool[];
|
|
18
19
|
listTools(): Promise<MCPTool[]>;
|
|
@@ -21,6 +21,7 @@ class BrowserSessionManager {
|
|
|
21
21
|
// Only initialize if not already done or config changed
|
|
22
22
|
if (this.isInitialized &&
|
|
23
23
|
this.config.mcpEndpoint === mcpEndpoint &&
|
|
24
|
+
this.config.useCDP === useCDP &&
|
|
24
25
|
this.config.cdpEndpoint === cdpEndpoint) {
|
|
25
26
|
return this.tools;
|
|
26
27
|
}
|
|
@@ -64,13 +65,42 @@ class BrowserSessionManager {
|
|
|
64
65
|
throw new Error(`Failed to connect to MCP server via ${transportType} at ${mcpEndpoint}. Error: ${error.message}`);
|
|
65
66
|
}
|
|
66
67
|
this.isInitialized = true;
|
|
67
|
-
this.config = { mcpEndpoint, cdpEndpoint };
|
|
68
|
-
// Fetch available tools from MCP server
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
this.config = { mcpEndpoint, useCDP, cdpEndpoint };
|
|
69
|
+
// Fetch available tools from MCP server (handles pagination)
|
|
70
|
+
this.tools = await this.getAllTools();
|
|
71
|
+
// If requested, connect to an existing browser via CDP
|
|
72
|
+
if (useCDP) {
|
|
73
|
+
if (!cdpEndpoint || String(cdpEndpoint).trim() === '') {
|
|
74
|
+
throw new Error('CDP endpoint is required when Browser Mode is CDP Connection');
|
|
75
|
+
}
|
|
76
|
+
const hasConnectTool = this.tools.some((t) => t.name === 'browser_connect_cdp');
|
|
77
|
+
if (hasConnectTool) {
|
|
78
|
+
const result = await this.mcpClient.callTool({
|
|
79
|
+
name: 'browser_connect_cdp',
|
|
80
|
+
arguments: { endpoint: cdpEndpoint },
|
|
81
|
+
});
|
|
82
|
+
if (result?.isError) {
|
|
83
|
+
throw new Error(`Failed to connect via CDP: ${JSON.stringify(result)}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
72
87
|
return this.tools;
|
|
73
88
|
}
|
|
89
|
+
async getAllTools(cursor) {
|
|
90
|
+
if (!this.mcpClient) {
|
|
91
|
+
throw new Error('MCP client not initialized');
|
|
92
|
+
}
|
|
93
|
+
// SDK supports optional cursor param; keep it loosely typed for compatibility.
|
|
94
|
+
const response = await (cursor
|
|
95
|
+
? this.mcpClient.listTools({ cursor })
|
|
96
|
+
: this.mcpClient.listTools());
|
|
97
|
+
const tools = (response?.tools ?? []);
|
|
98
|
+
const nextCursor = response?.nextCursor;
|
|
99
|
+
if (nextCursor) {
|
|
100
|
+
return tools.concat(await this.getAllTools(nextCursor));
|
|
101
|
+
}
|
|
102
|
+
return tools;
|
|
103
|
+
}
|
|
74
104
|
async callTool(toolName, toolArgs) {
|
|
75
105
|
if (!this.mcpClient || !this.isInitialized) {
|
|
76
106
|
throw new Error('MCP client not initialized. Please configure credentials first.');
|
|
@@ -84,6 +114,9 @@ class BrowserSessionManager {
|
|
|
84
114
|
});
|
|
85
115
|
// Log the response for debugging
|
|
86
116
|
console.log(`[MCP] Tool "${toolName}" response:`, JSON.stringify(result, null, 2));
|
|
117
|
+
if (result?.isError) {
|
|
118
|
+
throw new Error(typeof result?.toolResult === 'string' ? result.toolResult : `Tool returned error: ${JSON.stringify(result)}`);
|
|
119
|
+
}
|
|
87
120
|
return result;
|
|
88
121
|
}
|
|
89
122
|
catch (error) {
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.SmartBrowserAutomation = void 0;
|
|
7
7
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
8
8
|
const BrowserSessionManager_1 = __importDefault(require("./BrowserSessionManager"));
|
|
9
|
+
const jsonSchemaToZod_1 = require("./jsonSchemaToZod");
|
|
9
10
|
class SmartBrowserAutomation {
|
|
10
11
|
description = {
|
|
11
12
|
displayName: 'Smart Browser Automation',
|
|
@@ -221,11 +222,23 @@ class SmartBrowserAutomation {
|
|
|
221
222
|
}
|
|
222
223
|
// Validate tool exists before executing
|
|
223
224
|
const availableTools = await sessionManager.listTools();
|
|
224
|
-
const
|
|
225
|
+
const selectedTool = availableTools.find((tool) => tool.name === toolName);
|
|
226
|
+
const toolExists = Boolean(selectedTool);
|
|
225
227
|
if (!toolExists) {
|
|
226
228
|
const availableToolNames = availableTools.map((t) => t.name).join(', ');
|
|
227
229
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Tool '${toolName}' does not exist. Available tools: ${availableToolNames}`);
|
|
228
230
|
}
|
|
231
|
+
// Validate tool parameters against the MCP tool JSON schema (when provided)
|
|
232
|
+
if (selectedTool?.inputSchema) {
|
|
233
|
+
try {
|
|
234
|
+
const schema = await (0, jsonSchemaToZod_1.jsonSchemaToZod)(selectedTool.inputSchema);
|
|
235
|
+
schema.parse(toolParams);
|
|
236
|
+
}
|
|
237
|
+
catch (validationError) {
|
|
238
|
+
const details = validationError?.issues ? JSON.stringify(validationError.issues) : validationError.message;
|
|
239
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid tool parameters for '${toolName}'.`, { description: details });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
229
242
|
// Execute the tool via MCP
|
|
230
243
|
const result = await sessionManager.callTool(toolName, toolParams);
|
|
231
244
|
returnData.push({
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type INodeType, type INodeTypeDescription, type ISupplyDataFunctions, type SupplyData } from 'n8n-workflow';
|
|
2
|
+
export declare class SmartBrowserAutomationTools implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable n8n-nodes-base/node-class-description-inputs-wrong-regular-node */
|
|
3
|
+
/* eslint-disable n8n-nodes-base/node-class-description-outputs-wrong */
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v;
|
|
19
|
+
});
|
|
20
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
21
|
+
var ownKeys = function(o) {
|
|
22
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
23
|
+
var ar = [];
|
|
24
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
25
|
+
return ar;
|
|
26
|
+
};
|
|
27
|
+
return ownKeys(o);
|
|
28
|
+
};
|
|
29
|
+
return function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
38
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
39
|
+
};
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.SmartBrowserAutomationTools = void 0;
|
|
42
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
43
|
+
const BrowserSessionManager_1 = __importDefault(require("./BrowserSessionManager"));
|
|
44
|
+
const jsonSchemaToZod_1 = require("./jsonSchemaToZod");
|
|
45
|
+
class SmartBrowserAutomationTools {
|
|
46
|
+
description = {
|
|
47
|
+
displayName: 'Smart Browser Automation Tools',
|
|
48
|
+
name: 'smartBrowserAutomationTools',
|
|
49
|
+
group: ['transform'],
|
|
50
|
+
version: 1,
|
|
51
|
+
description: 'Expose Smart Browser Automation MCP tools (with JSON-schema args) to AI Agents',
|
|
52
|
+
defaults: {
|
|
53
|
+
name: 'Browser Automation Tools',
|
|
54
|
+
},
|
|
55
|
+
inputs: [],
|
|
56
|
+
outputs: [{ type: n8n_workflow_1.NodeConnectionTypes.AiTool, displayName: 'Tools' }],
|
|
57
|
+
icon: 'file:smartBrowserAutomation.svg',
|
|
58
|
+
credentials: [
|
|
59
|
+
{
|
|
60
|
+
name: 'smartBrowserAutomationApi',
|
|
61
|
+
required: true,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
properties: [
|
|
65
|
+
{
|
|
66
|
+
displayName: 'CDP Endpoint Override',
|
|
67
|
+
name: 'cdpOverride',
|
|
68
|
+
type: 'string',
|
|
69
|
+
default: '',
|
|
70
|
+
placeholder: 'ws://localhost:9222',
|
|
71
|
+
description: 'Override the CDP endpoint from credentials (only used in CDP mode)',
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
async supplyData(itemIndex) {
|
|
76
|
+
const node = this.getNode();
|
|
77
|
+
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
78
|
+
const sessionManager = BrowserSessionManager_1.default.getInstance();
|
|
79
|
+
const cdpOverride = this.getNodeParameter('cdpOverride', itemIndex, '');
|
|
80
|
+
const useCDP = credentials.browserMode === 'cdp';
|
|
81
|
+
const cdpUrl = (cdpOverride || credentials.cdpEndpoint || '').trim();
|
|
82
|
+
try {
|
|
83
|
+
await sessionManager.initialize(credentials.mcpEndpoint, useCDP, useCDP ? cdpUrl : undefined);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
throw new n8n_workflow_1.NodeOperationError(node, `Failed to connect to MCP server: ${error.message}`, {
|
|
87
|
+
itemIndex,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const mcpTools = await sessionManager.listTools();
|
|
91
|
+
if (!mcpTools.length) {
|
|
92
|
+
throw new n8n_workflow_1.NodeOperationError(node, 'MCP Server returned no tools', { itemIndex });
|
|
93
|
+
}
|
|
94
|
+
const { DynamicStructuredTool } = await Promise.resolve().then(() => __importStar(require('langchain/tools')));
|
|
95
|
+
const { Toolkit } = await Promise.resolve().then(() => __importStar(require('langchain/agents')));
|
|
96
|
+
const tools = await Promise.all(mcpTools.map(async (tool) => {
|
|
97
|
+
const schema = await (0, jsonSchemaToZod_1.jsonSchemaToZod)(tool.inputSchema);
|
|
98
|
+
return new DynamicStructuredTool({
|
|
99
|
+
name: tool.name,
|
|
100
|
+
description: tool.description ?? '',
|
|
101
|
+
schema,
|
|
102
|
+
func: async (args) => {
|
|
103
|
+
return await sessionManager.callTool(tool.name, args);
|
|
104
|
+
},
|
|
105
|
+
metadata: { isFromToolkit: true },
|
|
106
|
+
});
|
|
107
|
+
}));
|
|
108
|
+
class SmartBrowserAutomationToolkit extends Toolkit {
|
|
109
|
+
tools;
|
|
110
|
+
constructor(tools) {
|
|
111
|
+
super();
|
|
112
|
+
this.tools = tools;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
response: new SmartBrowserAutomationToolkit(tools),
|
|
117
|
+
closeFunction: async () => await sessionManager.close(),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.SmartBrowserAutomationTools = SmartBrowserAutomationTools;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type JsonSchema = {
|
|
2
|
+
type?: string | string[];
|
|
3
|
+
properties?: Record<string, JsonSchema>;
|
|
4
|
+
required?: string[];
|
|
5
|
+
items?: JsonSchema;
|
|
6
|
+
enum?: Array<string | number | boolean | null>;
|
|
7
|
+
anyOf?: JsonSchema[];
|
|
8
|
+
oneOf?: JsonSchema[];
|
|
9
|
+
allOf?: JsonSchema[];
|
|
10
|
+
additionalProperties?: boolean | JsonSchema;
|
|
11
|
+
default?: unknown;
|
|
12
|
+
description?: string;
|
|
13
|
+
format?: string;
|
|
14
|
+
};
|
|
15
|
+
export type { JsonSchema };
|
|
16
|
+
export declare function jsonSchemaToZod(schema: JsonSchema | undefined): Promise<any>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.jsonSchemaToZod = jsonSchemaToZod;
|
|
37
|
+
async function jsonSchemaToZod(schema) {
|
|
38
|
+
const { z } = await Promise.resolve().then(() => __importStar(require('zod')));
|
|
39
|
+
const toZod = (s) => {
|
|
40
|
+
if (!s)
|
|
41
|
+
return z.any();
|
|
42
|
+
if (Array.isArray(s.oneOf) && s.oneOf.length) {
|
|
43
|
+
return z.union(s.oneOf.map((x) => toZod(x)));
|
|
44
|
+
}
|
|
45
|
+
if (Array.isArray(s.anyOf) && s.anyOf.length) {
|
|
46
|
+
return z.union(s.anyOf.map((x) => toZod(x)));
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(s.allOf) && s.allOf.length) {
|
|
49
|
+
return s.allOf.reduce((acc, cur) => acc.and(toZod(cur)), toZod(s.allOf[0]));
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(s.enum) && s.enum.length) {
|
|
52
|
+
const values = s.enum;
|
|
53
|
+
const allStrings = values.every((v) => typeof v === 'string');
|
|
54
|
+
if (allStrings) {
|
|
55
|
+
return z.enum(values);
|
|
56
|
+
}
|
|
57
|
+
return z.union(values.map((v) => z.literal(v)));
|
|
58
|
+
}
|
|
59
|
+
const type = s.type;
|
|
60
|
+
const types = Array.isArray(type) ? type : type ? [type] : [];
|
|
61
|
+
const allowsNull = types.includes('null');
|
|
62
|
+
const effectiveTypes = types.filter((t) => t !== 'null');
|
|
63
|
+
let base;
|
|
64
|
+
switch (effectiveTypes[0]) {
|
|
65
|
+
case 'string':
|
|
66
|
+
base = z.string();
|
|
67
|
+
break;
|
|
68
|
+
case 'integer':
|
|
69
|
+
base = z.number().int();
|
|
70
|
+
break;
|
|
71
|
+
case 'number':
|
|
72
|
+
base = z.number();
|
|
73
|
+
break;
|
|
74
|
+
case 'boolean':
|
|
75
|
+
base = z.boolean();
|
|
76
|
+
break;
|
|
77
|
+
case 'array':
|
|
78
|
+
base = z.array(toZod(s.items));
|
|
79
|
+
break;
|
|
80
|
+
case 'object': {
|
|
81
|
+
const shape = {};
|
|
82
|
+
const props = s.properties ?? {};
|
|
83
|
+
const required = new Set(s.required ?? []);
|
|
84
|
+
for (const [key, value] of Object.entries(props)) {
|
|
85
|
+
const zodProp = toZod(value);
|
|
86
|
+
shape[key] = required.has(key) ? zodProp : zodProp.optional();
|
|
87
|
+
}
|
|
88
|
+
base = z.object(shape);
|
|
89
|
+
if (s.additionalProperties === false) {
|
|
90
|
+
base = base.strict();
|
|
91
|
+
}
|
|
92
|
+
else if (s.additionalProperties && typeof s.additionalProperties === 'object') {
|
|
93
|
+
base = base.catchall(toZod(s.additionalProperties));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
base = base.passthrough();
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
default:
|
|
101
|
+
base = z.any();
|
|
102
|
+
}
|
|
103
|
+
if (allowsNull)
|
|
104
|
+
base = base.nullable();
|
|
105
|
+
return base;
|
|
106
|
+
};
|
|
107
|
+
return toZod(schema);
|
|
108
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-smart-browser-automation",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.6",
|
|
4
4
|
"description": "n8n node for AI-driven browser automation using MCP",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n-community-node-package",
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
"dist/credentials/SmartBrowserAutomationApi.credentials.js"
|
|
38
38
|
],
|
|
39
39
|
"nodes": [
|
|
40
|
-
"dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.js"
|
|
40
|
+
"dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.js",
|
|
41
|
+
"dist/nodes/SmartBrowserAutomation/SmartBrowserAutomationTools.node.js"
|
|
41
42
|
]
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
"n8n-workflow": "*"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
|
-
"@modelcontextprotocol/sdk": "^1.17.0"
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.17.0",
|
|
60
|
+
"zod": "^3.23.8"
|
|
59
61
|
}
|
|
60
62
|
}
|