UNPKG

n8n

Version:

n8n Workflow Automation Tool

123 lines 4.44 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BrowserLocalMcpServer = void 0; const api_types_1 = require("@n8n/api-types"); const zod_to_json_schema_1 = require("zod-to-json-schema"); const NO_DOMAIN = 'browser'; class BrowserLocalMcpServer { constructor(toolkit, toolContext, logger) { this.toolContext = toolContext; this.logger = logger; this.toolsByName = new Map(); this.mcpTools = []; for (const tool of toolkit.tools) { const candidate = { name: tool.name, description: tool.description, inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(tool.inputSchema), annotations: { category: 'browser' }, }; const parsed = api_types_1.mcpToolSchema.safeParse(candidate); if (!parsed.success) { this.logger.warn('Skipping browser tool with unsupported input schema', { tool: tool.name, }); continue; } this.toolsByName.set(tool.name, tool); this.mcpTools.push(parsed.data); } } setDomainGate(gate) { this.gate = gate; } getAvailableTools() { return this.mcpTools; } getToolsByCategory(category) { return category === 'browser' ? this.mcpTools : []; } async callTool(req) { const tool = this.toolsByName.get(req.name); if (!tool) { return errorResult(`Unknown browser tool: ${req.name}`); } try { const { _confirmation, ...rawArgs } = req.arguments; const args = tool.inputSchema.parse(rawArgs); const gateResult = await this.gateDomainAccess(tool, args, _confirmation); if (gateResult) { return gateResult; } const result = await tool.execute(args, this.toolContext); const parsed = api_types_1.mcpToolCallResultSchema.safeParse(result); if (parsed.success) { return parsed.data; } return { content: [{ type: 'text', text: JSON.stringify(result.content) }], ...(result.isError === true ? { isError: true } : {}), }; } catch (error) { return errorResult(error instanceof Error ? error.message : String(error)); } } async gateDomainAccess(tool, args, confirmation) { const gate = this.gate; if (!gate) { return undefined; } const host = await this.affectedHost(tool, args); if (!host || host === NO_DOMAIN) { return undefined; } if (typeof confirmation === 'string') { switch (confirmation) { case 'allowForSession': await gate.tracker.approveDomain(host); return undefined; case 'allowOnce': gate.tracker.approveOnce(gate.runId, host); return undefined; default: return errorResult('Access denied by user'); } } if (gate.permissionMode === 'blocked') { return errorResult('Browser access blocked by admin'); } if (gate.permissionMode !== 'always_allow' && !gate.tracker.isHostAllowed(host, gate.runId)) { return confirmationRequiredResult(host); } return undefined; } async affectedHost(tool, args) { try { const resources = await tool.getAffectedResources(args, this.toolContext); return resources[0]?.resource; } catch { return undefined; } } } exports.BrowserLocalMcpServer = BrowserLocalMcpServer; function confirmationRequiredResult(host) { const payload = { toolGroup: 'browser', resource: host, description: `Browser: ${host}`, options: ['denyOnce', 'allowOnce', 'allowForSession'], }; return { content: [ { type: 'text', text: `${api_types_1.GATEWAY_CONFIRMATION_REQUIRED_PREFIX}${JSON.stringify(payload)}` }, ], isError: true, }; } function errorResult(message) { return { content: [{ type: 'text', text: message }], isError: true }; } //# sourceMappingURL=browser-local-mcp-server.js.map