Skip to main content
Glama

n8n-MCP

by 88-888
example-generator.tsโ€ข28.9 kB
/** * ExampleGenerator Service * * Provides concrete, working examples for n8n nodes to help AI agents * understand how to configure them properly. */ export interface NodeExamples { minimal: Record<string, any>; common?: Record<string, any>; advanced?: Record<string, any>; } export class ExampleGenerator { /** * Curated examples for the most commonly used nodes. * Each example is a valid configuration that can be used directly. */ private static NODE_EXAMPLES: Record<string, NodeExamples> = { // HTTP Request - Most versatile node 'nodes-base.httpRequest': { minimal: { url: 'https://api.example.com/data' }, common: { method: 'POST', url: 'https://api.example.com/users', sendBody: true, contentType: 'json', specifyBody: 'json', jsonBody: '{\n "name": "John Doe",\n "email": "john@example.com"\n}' }, advanced: { method: 'POST', url: 'https://api.example.com/protected/resource', authentication: 'genericCredentialType', genericAuthType: 'headerAuth', sendHeaders: true, headerParameters: { parameters: [ { name: 'X-API-Version', value: 'v2' } ] }, sendBody: true, contentType: 'json', specifyBody: 'json', jsonBody: '{\n "action": "update",\n "data": {}\n}', // Error handling for API calls onError: 'continueRegularOutput', retryOnFail: true, maxTries: 3, waitBetweenTries: 1000, alwaysOutputData: true } }, // Webhook - Entry point for workflows 'nodes-base.webhook': { minimal: { path: 'my-webhook', httpMethod: 'POST' }, common: { path: 'webhook-endpoint', httpMethod: 'POST', responseMode: 'lastNode', responseData: 'allEntries', responseCode: 200, // Webhooks should continue on fail to avoid blocking responses onError: 'continueRegularOutput', alwaysOutputData: true } }, // Webhook data processing example 'nodes-base.code.webhookProcessing': { minimal: { language: 'javaScript', jsCode: `// โš ๏ธ CRITICAL: Webhook data is nested under 'body' property! // This Code node should be connected after a Webhook node // โŒ WRONG - This will be undefined: // const command = items[0].json.testCommand; // โœ… CORRECT - Access webhook data through body: const webhookData = items[0].json.body; const headers = items[0].json.headers; const query = items[0].json.query; // Process webhook payload return [{ json: { // Extract data from webhook body command: webhookData.testCommand, userId: webhookData.userId, data: webhookData.data, // Add metadata timestamp: DateTime.now().toISO(), requestId: headers['x-request-id'] || crypto.randomUUID(), source: query.source || 'webhook', // Original webhook info httpMethod: items[0].json.httpMethod, webhookPath: items[0].json.webhookPath } }];` } }, // Code - Custom logic 'nodes-base.code': { minimal: { language: 'javaScript', jsCode: 'return [{json: {result: "success"}}];' }, common: { language: 'javaScript', jsCode: `// Process each item and add timestamp return items.map(item => ({ json: { ...item.json, processed: true, timestamp: DateTime.now().toISO() } }));`, onError: 'continueRegularOutput' }, advanced: { language: 'javaScript', jsCode: `// Advanced data processing with proper helper checks const crypto = require('crypto'); const results = []; for (const item of items) { try { // Validate required fields if (!item.json.email || !item.json.name) { throw new Error('Missing required fields: email or name'); } // Generate secure API key const apiKey = crypto.randomBytes(16).toString('hex'); // Check if $helpers is available before using let response; if (typeof $helpers !== 'undefined' && $helpers.httpRequest) { response = await $helpers.httpRequest({ method: 'POST', url: 'https://api.example.com/process', body: { email: item.json.email, name: item.json.name, apiKey }, headers: { 'Content-Type': 'application/json' } }); } else { // Fallback if $helpers not available response = { message: 'HTTP requests not available in this n8n version' }; } // Add to results with response data results.push({ json: { ...item.json, apiResponse: response, processedAt: DateTime.now().toISO(), status: 'success' } }); } catch (error) { // Include failed items with error info results.push({ json: { ...item.json, error: error.message, status: 'failed', processedAt: DateTime.now().toISO() } }); } } return results;`, onError: 'continueRegularOutput', retryOnFail: true, maxTries: 2 } }, // Additional Code node examples 'nodes-base.code.dataTransform': { minimal: { language: 'javaScript', jsCode: `// Transform CSV-like data to JSON return items.map(item => { const lines = item.json.data.split('\\n'); const headers = lines[0].split(','); const rows = lines.slice(1).map(line => { const values = line.split(','); return headers.reduce((obj, header, i) => { obj[header.trim()] = values[i]?.trim() || ''; return obj; }, {}); }); return {json: {rows, count: rows.length}}; });` } }, 'nodes-base.code.aggregation': { minimal: { language: 'javaScript', jsCode: `// Aggregate data from all items const totals = items.reduce((acc, item) => { acc.count++; acc.sum += item.json.amount || 0; acc.categories[item.json.category] = (acc.categories[item.json.category] || 0) + 1; return acc; }, {count: 0, sum: 0, categories: {}}); return [{ json: { totalItems: totals.count, totalAmount: totals.sum, averageAmount: totals.sum / totals.count, categoryCounts: totals.categories, processedAt: DateTime.now().toISO() } }];` } }, 'nodes-base.code.filtering': { minimal: { language: 'javaScript', jsCode: `// Filter items based on conditions return items .filter(item => { const amount = item.json.amount || 0; const status = item.json.status || ''; return amount > 100 && status === 'active'; }) .map(item => ({json: item.json}));` } }, 'nodes-base.code.jmespathFiltering': { minimal: { language: 'javaScript', jsCode: `// JMESPath filtering - IMPORTANT: Use backticks for numeric literals! const allItems = items.map(item => item.json); // โœ… CORRECT - Filter with numeric literals using backticks const expensiveItems = $jmespath(allItems, '[?price >= \`100\`]'); const lowStock = $jmespath(allItems, '[?inventory < \`10\`]'); const highPriority = $jmespath(allItems, '[?priority == \`1\`]'); // Combine multiple conditions const urgentExpensive = $jmespath(allItems, '[?price >= \`100\` && priority == \`1\`]'); // String comparisons don't need backticks const activeItems = $jmespath(allItems, '[?status == "active"]'); // Return filtered results return expensiveItems.map(item => ({json: item}));` } }, 'nodes-base.code.pythonExample': { minimal: { language: 'python', pythonCode: `# Python data processing - use underscore prefix for built-in variables import json from datetime import datetime import re results = [] # Use _input.all() to get items in Python for item in _input.all(): # Convert JsProxy to Python dict to avoid issues with null values item_data = item.json.to_py() # Clean email addresses email = item_data.get('email', '') if email and re.match(r'^[\\w\\.-]+@[\\w\\.-]+\\.\\w+$', email): cleaned_data = { 'email': email.lower(), 'name': item_data.get('name', '').title(), 'validated': True, 'timestamp': datetime.now().isoformat() } else: # Spread operator doesn't work with JsProxy, use dict() cleaned_data = dict(item_data) cleaned_data['validated'] = False cleaned_data['error'] = 'Invalid email format' results.append({'json': cleaned_data}) return results` } }, 'nodes-base.code.aiTool': { minimal: { language: 'javaScript', mode: 'runOnceForEachItem', jsCode: `// Code node as AI tool - calculate discount const quantity = $json.quantity || 1; const price = $json.price || 0; let discountRate = 0; if (quantity >= 100) discountRate = 0.20; else if (quantity >= 50) discountRate = 0.15; else if (quantity >= 20) discountRate = 0.10; else if (quantity >= 10) discountRate = 0.05; const subtotal = price * quantity; const discount = subtotal * discountRate; const total = subtotal - discount; return [{ json: { quantity, price, subtotal, discountRate: discountRate * 100, discountAmount: discount, total, savings: discount } }];` } }, 'nodes-base.code.crypto': { minimal: { language: 'javaScript', jsCode: `// Using crypto in Code nodes - it IS available! const crypto = require('crypto'); // Generate secure tokens const token = crypto.randomBytes(32).toString('hex'); const uuid = crypto.randomUUID(); // Create hashes const hash = crypto.createHash('sha256') .update(items[0].json.data || 'test') .digest('hex'); return [{ json: { token, uuid, hash, timestamp: DateTime.now().toISO() } }];` } }, 'nodes-base.code.staticData': { minimal: { language: 'javaScript', jsCode: `// Using workflow static data correctly // IMPORTANT: $getWorkflowStaticData is a standalone function! const staticData = $getWorkflowStaticData('global'); // Initialize counter if not exists if (!staticData.processCount) { staticData.processCount = 0; staticData.firstRun = DateTime.now().toISO(); } // Update counter staticData.processCount++; staticData.lastRun = DateTime.now().toISO(); // Process items const results = items.map(item => ({ json: { ...item.json, runNumber: staticData.processCount, processed: true } })); return results;` } }, // Set - Data manipulation 'nodes-base.set': { minimal: { mode: 'manual', assignments: { assignments: [ { id: '1', name: 'status', value: 'active', type: 'string' } ] } }, common: { mode: 'manual', includeOtherFields: true, assignments: { assignments: [ { id: '1', name: 'status', value: 'processed', type: 'string' }, { id: '2', name: 'processedAt', value: '={{ $now.toISO() }}', type: 'string' }, { id: '3', name: 'itemCount', value: '={{ $items().length }}', type: 'number' } ] } } }, // If - Conditional logic 'nodes-base.if': { minimal: { conditions: { conditions: [ { id: '1', leftValue: '={{ $json.status }}', rightValue: 'active', operator: { type: 'string', operation: 'equals' } } ] } }, common: { conditions: { conditions: [ { id: '1', leftValue: '={{ $json.status }}', rightValue: 'active', operator: { type: 'string', operation: 'equals' } }, { id: '2', leftValue: '={{ $json.count }}', rightValue: 10, operator: { type: 'number', operation: 'gt' } } ] }, combineOperation: 'all' } }, // PostgreSQL - Database operations 'nodes-base.postgres': { minimal: { operation: 'executeQuery', query: 'SELECT * FROM users LIMIT 10' }, common: { operation: 'insert', table: 'users', columns: 'name,email,created_at', additionalFields: {} }, advanced: { operation: 'executeQuery', query: `INSERT INTO users (name, email, status) VALUES ($1, $2, $3) ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name, updated_at = NOW() RETURNING *;`, additionalFields: { queryParams: '={{ $json.name }},{{ $json.email }},active' }, // Database operations should retry on connection errors retryOnFail: true, maxTries: 3, waitBetweenTries: 2000, onError: 'continueErrorOutput' } }, // OpenAI - AI operations 'nodes-base.openAi': { minimal: { resource: 'chat', operation: 'message', modelId: 'gpt-3.5-turbo', messages: { values: [ { role: 'user', content: 'Hello, how can you help me?' } ] } }, common: { resource: 'chat', operation: 'message', modelId: 'gpt-4', messages: { values: [ { role: 'system', content: 'You are a helpful assistant that summarizes text concisely.' }, { role: 'user', content: '={{ $json.text }}' } ] }, options: { maxTokens: 150, temperature: 0.7 }, // AI calls should handle rate limits and transient errors retryOnFail: true, maxTries: 3, waitBetweenTries: 5000, onError: 'continueRegularOutput', alwaysOutputData: true } }, // Google Sheets - Spreadsheet operations 'nodes-base.googleSheets': { minimal: { operation: 'read', documentId: { __rl: true, value: 'https://docs.google.com/spreadsheets/d/your-sheet-id', mode: 'url' }, sheetName: 'Sheet1' }, common: { operation: 'append', documentId: { __rl: true, value: 'your-sheet-id', mode: 'id' }, sheetName: 'Sheet1', dataStartRow: 2, columns: { mappingMode: 'defineBelow', value: { 'Name': '={{ $json.name }}', 'Email': '={{ $json.email }}', 'Date': '={{ $now.toISO() }}' } } } }, // Slack - Messaging 'nodes-base.slack': { minimal: { resource: 'message', operation: 'post', channel: '#general', text: 'Hello from n8n!' }, common: { resource: 'message', operation: 'post', channel: '#notifications', text: 'New order received!', attachments: [ { color: '#36a64f', title: 'Order #{{ $json.orderId }}', fields: { item: [ { title: 'Customer', value: '{{ $json.customerName }}', short: true }, { title: 'Amount', value: '${{ $json.amount }}', short: true } ] } } ], // Messaging services should handle rate limits retryOnFail: true, maxTries: 2, waitBetweenTries: 3000, onError: 'continueRegularOutput' } }, // Email - Email operations 'nodes-base.emailSend': { minimal: { fromEmail: 'sender@example.com', toEmail: 'recipient@example.com', subject: 'Test Email', text: 'This is a test email from n8n.' }, common: { fromEmail: 'notifications@company.com', toEmail: '={{ $json.email }}', subject: 'Welcome to our service, {{ $json.name }}!', html: `<h1>Welcome!</h1> <p>Hi {{ $json.name }},</p> <p>Thank you for signing up. We're excited to have you on board!</p> <p>Best regards,<br>The Team</p>`, options: { ccEmail: 'admin@company.com' }, // Email sending should handle transient failures retryOnFail: true, maxTries: 3, waitBetweenTries: 2000, onError: 'continueRegularOutput' } }, // Merge - Combining data 'nodes-base.merge': { minimal: { mode: 'append' }, common: { mode: 'mergeByKey', propertyName1: 'id', propertyName2: 'userId' } }, // Function - Legacy custom functions 'nodes-base.function': { minimal: { functionCode: 'return items;' }, common: { functionCode: `// Add a timestamp to each item const processedItems = items.map(item => { return { ...item, json: { ...item.json, processedAt: new Date().toISOString() } }; }); return processedItems;` } }, // Split In Batches - Batch processing 'nodes-base.splitInBatches': { minimal: { batchSize: 10 }, common: { batchSize: 100, options: { reset: false } } }, // Redis - Cache operations 'nodes-base.redis': { minimal: { operation: 'set', key: 'myKey', value: 'myValue' }, common: { operation: 'set', key: 'user:{{ $json.userId }}', value: '={{ JSON.stringify($json) }}', expire: true, ttl: 3600 } }, // MongoDB - NoSQL operations 'nodes-base.mongoDb': { minimal: { operation: 'find', collection: 'users' }, common: { operation: 'findOneAndUpdate', collection: 'users', query: '{ "email": "{{ $json.email }}" }', update: '{ "$set": { "lastLogin": "{{ $now.toISO() }}" } }', options: { upsert: true, returnNewDocument: true }, // NoSQL operations should handle connection issues retryOnFail: true, maxTries: 3, waitBetweenTries: 1000, onError: 'continueErrorOutput' } }, // MySQL - Database operations 'nodes-base.mySql': { minimal: { operation: 'executeQuery', query: 'SELECT * FROM products WHERE active = 1' }, common: { operation: 'insert', table: 'orders', columns: 'customer_id,product_id,quantity,order_date', options: { queryBatching: 'independently' }, // Database writes should handle connection errors retryOnFail: true, maxTries: 3, waitBetweenTries: 2000, onError: 'stopWorkflow' } }, // FTP - File transfer 'nodes-base.ftp': { minimal: { operation: 'download', path: '/files/data.csv' }, common: { operation: 'upload', path: '/uploads/', fileName: 'report_{{ $now.format("yyyy-MM-dd") }}.csv', binaryData: true, binaryPropertyName: 'data' } }, // SSH - Remote execution 'nodes-base.ssh': { minimal: { resource: 'command', operation: 'execute', command: 'ls -la' }, common: { resource: 'command', operation: 'execute', command: 'cd /var/logs && tail -n 100 app.log | grep ERROR', cwd: '/home/user' } }, // Execute Command - Local execution 'nodes-base.executeCommand': { minimal: { command: 'echo "Hello from n8n"' }, common: { command: 'node process-data.js --input "{{ $json.filename }}"', cwd: '/app/scripts' } }, // GitHub - Version control 'nodes-base.github': { minimal: { resource: 'issue', operation: 'get', owner: 'n8n-io', repository: 'n8n', issueNumber: 123 }, common: { resource: 'issue', operation: 'create', owner: '={{ $json.organization }}', repository: '={{ $json.repo }}', title: 'Bug: {{ $json.title }}', body: `## Description {{ $json.description }} ## Steps to Reproduce {{ $json.steps }} ## Expected Behavior {{ $json.expected }}`, assignees: ['maintainer'], labels: ['bug', 'needs-triage'] } }, // Error Handling Examples and Patterns 'error-handling.modern-patterns': { minimal: { // Basic error handling - continue on error onError: 'continueRegularOutput' }, common: { // Use error output for special handling onError: 'continueErrorOutput', alwaysOutputData: true }, advanced: { // Stop workflow on critical errors onError: 'stopWorkflow', // But retry first retryOnFail: true, maxTries: 3, waitBetweenTries: 2000 } }, 'error-handling.api-with-retry': { minimal: { url: 'https://api.example.com/data', retryOnFail: true, maxTries: 3, waitBetweenTries: 1000 }, common: { method: 'GET', url: 'https://api.example.com/users/{{ $json.userId }}', retryOnFail: true, maxTries: 5, waitBetweenTries: 2000, alwaysOutputData: true, // Headers for better debugging sendHeaders: true, headerParameters: { parameters: [ { name: 'X-Request-ID', value: '={{ $workflow.id }}-{{ $execution.id }}' } ] } }, advanced: { method: 'POST', url: 'https://api.example.com/critical-operation', sendBody: true, contentType: 'json', specifyBody: 'json', jsonBody: '{{ JSON.stringify($json) }}', // Exponential backoff pattern retryOnFail: true, maxTries: 5, waitBetweenTries: 1000, // Always output for debugging alwaysOutputData: true, // Stop workflow on error for critical operations onError: 'stopWorkflow' } }, 'error-handling.fault-tolerant': { minimal: { // For non-critical operations onError: 'continueRegularOutput' }, common: { // Data processing that shouldn't stop the workflow onError: 'continueRegularOutput', alwaysOutputData: true }, advanced: { // Combination for resilient processing onError: 'continueRegularOutput', retryOnFail: true, maxTries: 2, waitBetweenTries: 500, alwaysOutputData: true } }, 'error-handling.database-patterns': { minimal: { // Database reads can continue on error onError: 'continueRegularOutput', alwaysOutputData: true }, common: { // Database writes should retry then stop retryOnFail: true, maxTries: 3, waitBetweenTries: 2000, onError: 'stopWorkflow' }, advanced: { // Transaction-safe operations onError: 'continueErrorOutput', retryOnFail: false, // Don't retry transactions alwaysOutputData: true } }, 'error-handling.webhook-patterns': { minimal: { // Always respond to webhooks onError: 'continueRegularOutput', alwaysOutputData: true }, common: { // Process errors separately onError: 'continueErrorOutput', alwaysOutputData: true, // Add custom error response responseCode: 200, responseData: 'allEntries' } }, 'error-handling.ai-patterns': { minimal: { // AI calls should handle rate limits retryOnFail: true, maxTries: 3, waitBetweenTries: 5000, onError: 'continueRegularOutput' }, common: { // Exponential backoff for rate limits retryOnFail: true, maxTries: 5, waitBetweenTries: 2000, onError: 'continueRegularOutput', alwaysOutputData: true } } }; /** * Get examples for a specific node type */ static getExamples(nodeType: string, essentials?: any): NodeExamples { // Return curated examples if available const examples = this.NODE_EXAMPLES[nodeType]; if (examples) { return examples; } // Generate basic examples for unconfigured nodes return this.generateBasicExamples(nodeType, essentials); } /** * Generate basic examples for nodes without curated ones */ private static generateBasicExamples(nodeType: string, essentials?: any): NodeExamples { const minimal: Record<string, any> = {}; // Add required fields with sensible defaults if (essentials?.required) { for (const prop of essentials.required) { minimal[prop.name] = this.getDefaultValue(prop); } } // Add first common property if no required fields if (Object.keys(minimal).length === 0 && essentials?.common?.length > 0) { const firstCommon = essentials.common[0]; minimal[firstCommon.name] = this.getDefaultValue(firstCommon); } return { minimal }; } /** * Generate a sensible default value for a property */ private static getDefaultValue(prop: any): any { // Use configured default if available if (prop.default !== undefined) { return prop.default; } // Generate based on type and name switch (prop.type) { case 'string': return this.getStringDefault(prop); case 'number': return prop.name.includes('port') ? 80 : prop.name.includes('timeout') ? 30000 : prop.name.includes('limit') ? 10 : 0; case 'boolean': return false; case 'options': case 'multiOptions': return prop.options?.[0]?.value || ''; case 'json': return '{\n "key": "value"\n}'; case 'collection': case 'fixedCollection': return {}; default: return ''; } } /** * Get default value for string properties based on name */ private static getStringDefault(prop: any): string { const name = prop.name.toLowerCase(); // URL/endpoint fields if (name.includes('url') || name === 'endpoint') { return 'https://api.example.com'; } // Email fields if (name.includes('email')) { return name.includes('from') ? 'sender@example.com' : 'recipient@example.com'; } // Path fields if (name.includes('path')) { return name.includes('webhook') ? 'my-webhook' : '/path/to/file'; } // Name fields if (name === 'name' || name.includes('username')) { return 'John Doe'; } // Key fields if (name.includes('key')) { return 'myKey'; } // Query fields if (name === 'query' || name.includes('sql')) { return 'SELECT * FROM table_name LIMIT 10'; } // Collection/table fields if (name === 'collection' || name === 'table') { return 'users'; } // Use placeholder if available if (prop.placeholder) { return prop.placeholder; } return ''; } /** * Get example for a specific use case */ static getTaskExample(nodeType: string, task: string): Record<string, any> | undefined { const examples = this.NODE_EXAMPLES[nodeType]; if (!examples) return undefined; // Map common tasks to example types const taskMap: Record<string, keyof NodeExamples> = { 'basic': 'minimal', 'simple': 'minimal', 'typical': 'common', 'standard': 'common', 'complex': 'advanced', 'full': 'advanced' }; const exampleType = taskMap[task] || 'common'; return examples[exampleType] || examples.minimal; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/88-888/n8n-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server