n8n-nodes-playwright-mcp
Version:
Complete n8n Playwright node with all Microsoft Playwright MCP tools and AI assistant support for advanced browser automation
671 lines • 23.5 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.AI_INTEGRATION = exports.MCP_CAPABILITIES = exports.MCP_TOOLS = void 0;
exports.getEnabledMCPTools = getEnabledMCPTools;
exports.getOperationByMCPTool = getOperationByMCPTool;
exports.convertToMCPParameters = convertToMCPParameters;
exports.validateMCPParameters = validateMCPParameters;
exports.MCP_TOOLS = {
navigate: {
name: 'browser_navigate',
description: 'Navigate to a URL',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
description: 'The URL to navigate to',
format: 'uri'
}
},
required: ['url']
}
},
navigateBack: {
name: 'browser_navigate_back',
description: 'Go back to the previous page',
inputSchema: {
type: 'object',
properties: {}
}
},
navigateForward: {
name: 'browser_navigate_forward',
description: 'Go forward to the next page',
inputSchema: {
type: 'object',
properties: {}
}
},
snapshot: {
name: 'browser_snapshot',
description: 'Capture accessibility snapshot of the current page, this is better than screenshot',
inputSchema: {
type: 'object',
properties: {}
}
},
click: {
name: 'browser_click',
description: 'Perform click on a web page',
inputSchema: {
type: 'object',
properties: {
element: {
type: 'string',
description: 'Human-readable element description used to obtain permission to interact with the element'
},
ref: {
type: 'string',
description: 'Exact target element reference from the page snapshot'
},
doubleClick: {
type: 'boolean',
description: 'Whether to perform a double click instead of a single click'
},
button: {
type: 'string',
enum: ['left', 'right', 'middle'],
description: 'Button to click, defaults to left'
}
},
required: ['element', 'ref']
}
},
hover: {
name: 'browser_hover',
description: 'Hover over element on page',
inputSchema: {
type: 'object',
properties: {
element: {
type: 'string',
description: 'Human-readable element description used to obtain permission to interact with the element'
},
ref: {
type: 'string',
description: 'Exact target element reference from the page snapshot'
}
},
required: ['element', 'ref']
}
},
drag: {
name: 'browser_drag',
description: 'Perform drag and drop between two elements',
inputSchema: {
type: 'object',
properties: {
startElement: {
type: 'string',
description: 'Human-readable source element description used to obtain the permission to interact with the element'
},
startRef: {
type: 'string',
description: 'Exact source element reference from the page snapshot'
},
endElement: {
type: 'string',
description: 'Human-readable target element description used to obtain the permission to interact with the element'
},
endRef: {
type: 'string',
description: 'Exact target element reference from the page snapshot'
}
},
required: ['startElement', 'startRef', 'endElement', 'endRef']
}
},
selectOption: {
name: 'browser_select_option',
description: 'Select an option in a dropdown',
inputSchema: {
type: 'object',
properties: {
element: {
type: 'string',
description: 'Human-readable element description used to obtain permission to interact with the element'
},
ref: {
type: 'string',
description: 'Exact target element reference from the page snapshot'
},
values: {
type: 'array',
items: { type: 'string' },
description: 'Array of values to select in the dropdown. This can be a single value or multiple values.'
}
},
required: ['element', 'ref', 'values']
}
},
type: {
name: 'browser_type',
description: 'Type text into editable element',
inputSchema: {
type: 'object',
properties: {
element: {
type: 'string',
description: 'Human-readable element description used to obtain permission to interact with the element'
},
ref: {
type: 'string',
description: 'Exact target element reference from the page snapshot'
},
text: {
type: 'string',
description: 'Text to type into the element'
},
submit: {
type: 'boolean',
description: 'Whether to submit entered text (press Enter after)'
},
slowly: {
type: 'boolean',
description: 'Whether to type one character at a time. Useful for triggering key handlers in the page. By default entire text is filled in at once.'
}
},
required: ['element', 'ref', 'text']
}
},
pressKey: {
name: 'browser_press_key',
description: 'Press a key on the keyboard',
inputSchema: {
type: 'object',
properties: {
key: {
type: 'string',
description: 'Name of the key to press or a character to generate, such as `ArrowLeft` or `a`'
}
},
required: ['key']
}
},
evaluate: {
name: 'browser_evaluate',
description: 'Evaluate JavaScript expression on page or element',
inputSchema: {
type: 'object',
properties: {
function: {
type: 'string',
description: '() => { /* code */ } or (element) => { /* code */ } when element is provided'
},
element: {
type: 'string',
description: 'Human-readable element description used to obtain permission to interact with the element'
},
ref: {
type: 'string',
description: 'Exact target element reference from the page snapshot'
}
},
required: ['function']
}
},
fileUpload: {
name: 'browser_file_upload',
description: 'Upload one or multiple files',
inputSchema: {
type: 'object',
properties: {
paths: {
type: 'array',
items: { type: 'string' },
description: 'The absolute paths to the files to upload. Can be a single file or multiple files.'
}
},
required: ['paths']
}
},
handleDialog: {
name: 'browser_handle_dialog',
description: 'Handle a dialog',
inputSchema: {
type: 'object',
properties: {
accept: {
type: 'boolean',
description: 'Whether to accept the dialog.'
},
promptText: {
type: 'string',
description: 'The text of the prompt in case of a prompt dialog.'
}
},
required: ['accept']
}
},
close: {
name: 'browser_close',
description: 'Close the page',
inputSchema: {
type: 'object',
properties: {}
}
},
resize: {
name: 'browser_resize',
description: 'Resize the browser window',
inputSchema: {
type: 'object',
properties: {
width: {
type: 'number',
description: 'Width of the browser window'
},
height: {
type: 'number',
description: 'Height of the browser window'
}
},
required: ['width', 'height']
}
},
consoleMessages: {
name: 'browser_console_messages',
description: 'Returns all console messages',
inputSchema: {
type: 'object',
properties: {}
}
},
networkRequests: {
name: 'browser_network_requests',
description: 'Returns all network requests since loading the page',
inputSchema: {
type: 'object',
properties: {}
}
},
takeScreenshot: {
name: 'browser_take_screenshot',
description: 'Take a screenshot of the current page. You can\'t perform actions based on the screenshot, use browser_snapshot for actions.',
inputSchema: {
type: 'object',
properties: {
type: {
type: 'string',
enum: ['png', 'jpeg'],
description: 'Image format for the screenshot. Default is png.'
},
filename: {
type: 'string',
description: 'File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified.'
},
element: {
type: 'string',
description: 'Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too.'
},
ref: {
type: 'string',
description: 'Exact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too.'
},
fullPage: {
type: 'boolean',
description: 'When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Cannot be used with element screenshots.'
}
}
}
},
waitFor: {
name: 'browser_wait_for',
description: 'Wait for text to appear or disappear or a specified time to pass',
inputSchema: {
type: 'object',
properties: {
time: {
type: 'number',
description: 'The time to wait in seconds'
},
text: {
type: 'string',
description: 'The text to wait for'
},
textGone: {
type: 'string',
description: 'The text to wait for to disappear'
}
}
}
},
tabList: {
name: 'browser_tab_list',
description: 'List browser tabs',
inputSchema: {
type: 'object',
properties: {}
}
},
tabSelect: {
name: 'browser_tab_select',
description: 'Select a tab by index',
inputSchema: {
type: 'object',
properties: {
index: {
type: 'number',
description: 'The index of the tab to select'
}
},
required: ['index']
}
},
tabNew: {
name: 'browser_tab_new',
description: 'Open a new tab',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
description: 'The URL to navigate to in the new tab. If not provided, the new tab will be blank.'
}
}
}
},
tabClose: {
name: 'browser_tab_close',
description: 'Close a tab',
inputSchema: {
type: 'object',
properties: {
index: {
type: 'number',
description: 'The index of the tab to close. Closes current tab if not provided.'
}
}
}
},
install: {
name: 'browser_install',
description: 'Install the browser specified in the config. Call this if you get an error about the browser not being installed.',
inputSchema: {
type: 'object',
properties: {}
}
},
mouseMoveXY: {
name: 'browser_mouse_move_xy',
description: 'Move mouse to a given position',
inputSchema: {
type: 'object',
properties: {
element: {
type: 'string',
description: 'Human-readable element description used to obtain permission to interact with the element'
},
x: {
type: 'number',
description: 'X coordinate'
},
y: {
type: 'number',
description: 'Y coordinate'
}
},
required: ['element', 'x', 'y']
}
},
mouseClickXY: {
name: 'browser_mouse_click_xy',
description: 'Click left mouse button at a given position',
inputSchema: {
type: 'object',
properties: {
element: {
type: 'string',
description: 'Human-readable element description used to obtain permission to interact with the element'
},
x: {
type: 'number',
description: 'X coordinate'
},
y: {
type: 'number',
description: 'Y coordinate'
}
},
required: ['element', 'x', 'y']
}
},
mouseDragXY: {
name: 'browser_mouse_drag_xy',
description: 'Drag left mouse button to a given position',
inputSchema: {
type: 'object',
properties: {
element: {
type: 'string',
description: 'Human-readable element description used to obtain permission to interact with the element'
},
startX: {
type: 'number',
description: 'Start X coordinate'
},
startY: {
type: 'number',
description: 'Start Y coordinate'
},
endX: {
type: 'number',
description: 'End X coordinate'
},
endY: {
type: 'number',
description: 'End Y coordinate'
}
},
required: ['element', 'startX', 'startY', 'endX', 'endY']
}
},
savePDF: {
name: 'browser_pdf_save',
description: 'Save page as PDF',
inputSchema: {
type: 'object',
properties: {
filename: {
type: 'string',
description: 'File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified.'
}
}
}
},
getText: {
name: 'browser_get_text_legacy',
description: 'Get text from an element (legacy operation)',
inputSchema: {
type: 'object',
properties: {
selector: {
type: 'string',
description: 'CSS selector for the element'
}
},
required: ['selector']
}
},
fillForm: {
name: 'browser_fill_form_legacy',
description: 'Fill a form field (legacy operation)',
inputSchema: {
type: 'object',
properties: {
selector: {
type: 'string',
description: 'CSS selector for the form field'
},
value: {
type: 'string',
description: 'Value to fill in the form field'
}
},
required: ['selector', 'value']
}
},
clickElement: {
name: 'browser_click_element_legacy',
description: 'Click on an element (legacy operation)',
inputSchema: {
type: 'object',
properties: {
selector: {
type: 'string',
description: 'CSS selector for the element'
}
},
required: ['selector']
}
}
};
exports.MCP_CAPABILITIES = {
'core': {
name: 'core',
description: 'Core browser automation features',
tools: [
'browser_navigate', 'browser_navigate_back', 'browser_navigate_forward',
'browser_snapshot', 'browser_click', 'browser_hover', 'browser_drag', 'browser_select_option',
'browser_type', 'browser_press_key', 'browser_evaluate', 'browser_file_upload',
'browser_handle_dialog', 'browser_close', 'browser_resize', 'browser_console_messages',
'browser_network_requests', 'browser_take_screenshot', 'browser_wait_for'
],
enabled: true
},
'core-tabs': {
name: 'core-tabs',
description: 'Tab management functionality',
tools: [
'browser_tab_list', 'browser_tab_select', 'browser_tab_new', 'browser_tab_close'
],
enabled: true
},
'core-install': {
name: 'core-install',
description: 'Browser installation capabilities',
tools: [
'browser_install'
],
enabled: true
},
'vision': {
name: 'vision',
description: 'Coordinate-based interactions (requires vision capability)',
tools: [
'browser_mouse_move_xy', 'browser_mouse_click_xy', 'browser_mouse_drag_xy'
],
enabled: false
},
'pdf': {
name: 'pdf',
description: 'PDF generation and manipulation',
tools: [
'browser_pdf_save'
],
enabled: false
}
};
function getEnabledMCPTools(capabilities = ['core', 'core-tabs', 'core-install']) {
const enabledTools = [];
capabilities.forEach(cap => {
var _a;
if ((_a = exports.MCP_CAPABILITIES[cap]) === null || _a === void 0 ? void 0 : _a.enabled) {
enabledTools.push(...exports.MCP_CAPABILITIES[cap].tools);
}
});
return Object.entries(exports.MCP_TOOLS)
.filter(([_, tool]) => enabledTools.includes(tool.name))
.map(([_, tool]) => tool);
}
function getOperationByMCPTool(toolName) {
var _a;
return (_a = Object.entries(exports.MCP_TOOLS).find(([_, tool]) => tool.name === toolName)) === null || _a === void 0 ? void 0 : _a[0];
}
function convertToMCPParameters(operation, n8nParams) {
const mcpTool = exports.MCP_TOOLS[operation];
if (!mcpTool)
return n8nParams;
const mcpParams = {};
const schema = mcpTool.inputSchema;
Object.keys(schema.properties).forEach(key => {
if (n8nParams[key] !== undefined) {
mcpParams[key] = n8nParams[key];
}
});
return mcpParams;
}
function validateMCPParameters(operation, params) {
const mcpTool = exports.MCP_TOOLS[operation];
if (!mcpTool) {
return { valid: false, errors: [`Unknown operation: ${operation}`] };
}
const errors = [];
const schema = mcpTool.inputSchema;
if (schema.required) {
schema.required.forEach(required => {
if (params[required] === undefined) {
errors.push(`Missing required parameter: ${required}`);
}
});
}
Object.entries(schema.properties).forEach(([key, propSchema]) => {
if (params[key] !== undefined) {
const value = params[key];
const expectedType = propSchema.type;
if (expectedType === 'string' && typeof value !== 'string') {
errors.push(`Parameter ${key} must be a string`);
}
else if (expectedType === 'number' && typeof value !== 'number') {
errors.push(`Parameter ${key} must be a number`);
}
else if (expectedType === 'boolean' && typeof value !== 'boolean') {
errors.push(`Parameter ${key} must be a boolean`);
}
else if (expectedType === 'array' && !Array.isArray(value)) {
errors.push(`Parameter ${key} must be an array`);
}
}
});
return { valid: errors.length === 0, errors };
}
exports.AI_INTEGRATION = {
getWorkflowSuggestions(intent) {
const intentLower = intent.toLowerCase();
if (intentLower.includes('navigate') || intentLower.includes('go to')) {
return ['navigate', 'snapshot'];
}
if (intentLower.includes('click') || intentLower.includes('button')) {
return ['snapshot', 'click'];
}
if (intentLower.includes('type') || intentLower.includes('fill') || intentLower.includes('form')) {
return ['snapshot', 'type'];
}
if (intentLower.includes('screenshot') || intentLower.includes('capture')) {
return ['takeScreenshot'];
}
if (intentLower.includes('pdf') || intentLower.includes('save')) {
return ['savePDF'];
}
if (intentLower.includes('tab')) {
return ['tabList', 'tabNew', 'tabSelect'];
}
return ['navigate', 'snapshot', 'click'];
},
getOperationDescription(operation) {
const tool = exports.MCP_TOOLS[operation];
return tool ? tool.description : `Perform ${operation} operation`;
},
getParameterHints(operation) {
const tool = exports.MCP_TOOLS[operation];
if (!tool)
return {};
const hints = {};
Object.entries(tool.inputSchema.properties).forEach(([key, schema]) => {
hints[key] = schema.description || `${key} parameter`;
});
return hints;
}
};
//# sourceMappingURL=mcp-config.js.map
;