Initial commit of n8n MCP Server
A Model Context Protocol (MCP) server that integrates with n8n, providing tools for workflow and execution management via the n8n API.
This commit is contained in:
617
docs/examples/advanced-scenarios.md
Normal file
617
docs/examples/advanced-scenarios.md
Normal file
@@ -0,0 +1,617 @@
|
||||
# Advanced Scenarios
|
||||
|
||||
This page demonstrates more complex examples of using the n8n MCP Server with AI assistants.
|
||||
|
||||
## Workflow Analysis and Optimization
|
||||
|
||||
### User Prompt
|
||||
|
||||
"Analyze my workflows and suggest optimizations."
|
||||
|
||||
### Assistant Actions
|
||||
|
||||
```javascript
|
||||
// Get all workflows
|
||||
const workflows = await useMcpTool('n8n-mcp-server', 'workflow_list', {});
|
||||
|
||||
// Get execution statistics
|
||||
const stats = await accessMcpResource('n8n-mcp-server', 'n8n://execution-stats');
|
||||
|
||||
// Analyze each workflow in detail
|
||||
const analysisResults = [];
|
||||
|
||||
for (const workflow of workflows) {
|
||||
// Get detailed workflow information
|
||||
const details = await useMcpTool('n8n-mcp-server', 'workflow_get', {
|
||||
id: workflow.id
|
||||
});
|
||||
|
||||
// Get recent executions
|
||||
const executions = await useMcpTool('n8n-mcp-server', 'execution_list', {
|
||||
workflowId: workflow.id,
|
||||
limit: 10
|
||||
});
|
||||
|
||||
// Analyze workflow structure
|
||||
const nodeCount = details.nodes.length;
|
||||
const nodeTypes = new Set(details.nodes.map(node => node.type));
|
||||
|
||||
// Check for error patterns in executions
|
||||
const errorRate = executions.length > 0
|
||||
? executions.filter(e => e.status === "error").length / executions.length
|
||||
: 0;
|
||||
|
||||
// Check execution times
|
||||
const executionTimes = executions
|
||||
.filter(e => e.status === "success" && e.finishedAt && e.startedAt)
|
||||
.map(e => new Date(e.finishedAt) - new Date(e.startedAt));
|
||||
|
||||
const avgExecutionTime = executionTimes.length > 0
|
||||
? executionTimes.reduce((sum, time) => sum + time, 0) / executionTimes.length / 1000
|
||||
: 0;
|
||||
|
||||
// Generate optimization suggestions
|
||||
const suggestions = [];
|
||||
|
||||
if (nodeCount > 15) {
|
||||
suggestions.push("Consider splitting into multiple workflows for better maintainability");
|
||||
}
|
||||
|
||||
if (errorRate > 0.2) {
|
||||
suggestions.push("High error rate detected - review error handling and input validation");
|
||||
}
|
||||
|
||||
if (avgExecutionTime > 30) {
|
||||
suggestions.push("Long execution time - check for bottlenecks or inefficient operations");
|
||||
}
|
||||
|
||||
if (nodeTypes.has("n8n-nodes-base.httpRequest") && !nodeTypes.has("n8n-nodes-base.errorTrigger")) {
|
||||
suggestions.push("HTTP requests without error handling - consider adding error triggers");
|
||||
}
|
||||
|
||||
analysisResults.push({
|
||||
id: workflow.id,
|
||||
name: workflow.name,
|
||||
nodeCount,
|
||||
errorRate,
|
||||
avgExecutionTime,
|
||||
suggestions
|
||||
});
|
||||
}
|
||||
|
||||
// Format and present the analysis
|
||||
let response = "# Workflow Analysis and Optimization Suggestions\n\n";
|
||||
|
||||
analysisResults.forEach(result => {
|
||||
response += `## ${result.name}\n\n`;
|
||||
response += `**Nodes:** ${result.nodeCount}\n`;
|
||||
response += `**Error Rate:** ${(result.errorRate * 100).toFixed(1)}%\n`;
|
||||
response += `**Avg. Execution Time:** ${result.avgExecutionTime.toFixed(1)} seconds\n\n`;
|
||||
|
||||
if (result.suggestions.length > 0) {
|
||||
response += "**Optimization Suggestions:**\n";
|
||||
result.suggestions.forEach(suggestion => {
|
||||
response += `- ${suggestion}\n`;
|
||||
});
|
||||
} else {
|
||||
response += "No specific optimization suggestions for this workflow.\n";
|
||||
}
|
||||
|
||||
response += "\n";
|
||||
});
|
||||
|
||||
return response;
|
||||
```
|
||||
|
||||
## Scheduled Workflow Management
|
||||
|
||||
### User Prompt
|
||||
|
||||
"Update all my scheduled workflows to run one hour later."
|
||||
|
||||
### Assistant Actions
|
||||
|
||||
```javascript
|
||||
// Get all workflows
|
||||
const workflows = await useMcpTool('n8n-mcp-server', 'workflow_list', {});
|
||||
|
||||
// Filter for scheduled workflows (those with a Schedule node)
|
||||
const scheduledWorkflows = [];
|
||||
|
||||
for (const workflow of workflows) {
|
||||
// Get detailed workflow information
|
||||
const details = await useMcpTool('n8n-mcp-server', 'workflow_get', {
|
||||
id: workflow.id
|
||||
});
|
||||
|
||||
// Look for Schedule Trigger nodes
|
||||
const scheduleNodes = details.nodes.filter(node =>
|
||||
node.type === "n8n-nodes-base.scheduleTrigger" ||
|
||||
node.type === "n8n-nodes-base.cron"
|
||||
);
|
||||
|
||||
if (scheduleNodes.length > 0) {
|
||||
scheduledWorkflows.push({
|
||||
workflow: details,
|
||||
scheduleNodes
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (scheduledWorkflows.length === 0) {
|
||||
return "I couldn't find any workflows with scheduled triggers.";
|
||||
}
|
||||
|
||||
// Process each scheduled workflow
|
||||
const results = [];
|
||||
|
||||
for (const { workflow, scheduleNodes } of scheduledWorkflows) {
|
||||
// Create a copy of the workflow for modification
|
||||
const updatedWorkflow = { ...workflow };
|
||||
|
||||
// Update each schedule node
|
||||
for (const scheduleNode of scheduleNodes) {
|
||||
const nodeIndex = updatedWorkflow.nodes.findIndex(n => n.id === scheduleNode.id);
|
||||
|
||||
if (nodeIndex === -1) continue;
|
||||
|
||||
// Copy the node for modification
|
||||
const updatedNode = { ...updatedWorkflow.nodes[nodeIndex] };
|
||||
|
||||
// Handle different types of schedule configurations
|
||||
if (updatedNode.type === "n8n-nodes-base.scheduleTrigger") {
|
||||
if (updatedNode.parameters.cronExpression) {
|
||||
// Modify cron expression to run 1 hour later
|
||||
const cronParts = updatedNode.parameters.cronExpression.split(' ');
|
||||
if (cronParts.length === 5) {
|
||||
// Standard cron format: minute hour day month dayOfWeek
|
||||
const hour = parseInt(cronParts[1], 10);
|
||||
cronParts[1] = ((hour + 1) % 24).toString();
|
||||
updatedNode.parameters.cronExpression = cronParts.join(' ');
|
||||
}
|
||||
} else if (updatedNode.parameters.timeToRepeat) {
|
||||
// Handle specific time scheduling
|
||||
const time = updatedNode.parameters.timeToRepeat;
|
||||
if (time && time.split(':').length === 2) {
|
||||
const [hours, minutes] = time.split(':').map(part => parseInt(part, 10));
|
||||
const newHours = (hours + 1) % 24;
|
||||
updatedNode.parameters.timeToRepeat = `${newHours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
|
||||
}
|
||||
}
|
||||
} else if (updatedNode.type === "n8n-nodes-base.cron") {
|
||||
// Similar handling for cron node
|
||||
if (updatedNode.parameters.cronExpression) {
|
||||
const cronParts = updatedNode.parameters.cronExpression.split(' ');
|
||||
if (cronParts.length === 5) {
|
||||
const hour = parseInt(cronParts[1], 10);
|
||||
cronParts[1] = ((hour + 1) % 24).toString();
|
||||
updatedNode.parameters.cronExpression = cronParts.join(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the node in the workflow
|
||||
updatedWorkflow.nodes[nodeIndex] = updatedNode;
|
||||
}
|
||||
|
||||
// Save the updated workflow
|
||||
const result = await useMcpTool('n8n-mcp-server', 'workflow_update', {
|
||||
id: workflow.id,
|
||||
nodes: updatedWorkflow.nodes,
|
||||
connections: updatedWorkflow.connections
|
||||
});
|
||||
|
||||
results.push({
|
||||
name: workflow.name,
|
||||
updated: result.updatedAt
|
||||
});
|
||||
}
|
||||
|
||||
// Format and present the results
|
||||
let response = "# Updated Scheduled Workflows\n\n";
|
||||
response += "I've updated the following workflows to run one hour later:\n\n";
|
||||
|
||||
results.forEach(result => {
|
||||
response += `- **${result.name}** (Updated: ${new Date(result.updated).toLocaleString()})\n`;
|
||||
});
|
||||
|
||||
return response;
|
||||
```
|
||||
|
||||
## Error Handling and Notification System
|
||||
|
||||
### User Prompt
|
||||
|
||||
"Set up a notification system for any workflow that fails."
|
||||
|
||||
### Assistant Actions
|
||||
|
||||
```javascript
|
||||
// This scenario demonstrates creating a monitoring workflow that checks for failures
|
||||
// and sends notifications
|
||||
|
||||
// First, check if a monitoring workflow already exists
|
||||
const workflows = await useMcpTool('n8n-mcp-server', 'workflow_list', {});
|
||||
const existingMonitor = workflows.find(workflow =>
|
||||
workflow.name.toLowerCase().includes('workflow monitor') ||
|
||||
workflow.name.toLowerCase().includes('error notification')
|
||||
);
|
||||
|
||||
if (existingMonitor) {
|
||||
return `You already have a monitoring workflow: "${existingMonitor.name}" (ID: ${existingMonitor.id}). Would you like me to update it instead?`;
|
||||
}
|
||||
|
||||
// Create a new monitoring workflow
|
||||
const monitorWorkflow = await useMcpTool('n8n-mcp-server', 'workflow_create', {
|
||||
name: "Workflow Error Notification System",
|
||||
active: false, // Start inactive until configured
|
||||
nodes: [
|
||||
{
|
||||
name: "Schedule Trigger",
|
||||
type: "n8n-nodes-base.scheduleTrigger",
|
||||
position: [100, 300],
|
||||
parameters: {
|
||||
cronExpression: "*/15 * * * *" // Run every 15 minutes
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Get Failed Executions",
|
||||
type: "n8n-nodes-base.n8n",
|
||||
position: [300, 300],
|
||||
parameters: {
|
||||
resource: "execution",
|
||||
operation: "getAll",
|
||||
filters: {
|
||||
status: "error",
|
||||
// Look for executions in the last 15 minutes
|
||||
finished: {
|
||||
$gt: "={{$now.minus({ minutes: 15 }).toISOString()}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Filter Empty",
|
||||
type: "n8n-nodes-base.filter",
|
||||
position: [500, 300],
|
||||
parameters: {
|
||||
conditions: {
|
||||
boolean: [
|
||||
{
|
||||
value1: "={{ $json.length > 0 }}",
|
||||
operation: "equal",
|
||||
value2: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Format Notification",
|
||||
type: "n8n-nodes-base.function",
|
||||
position: [700, 300],
|
||||
parameters: {
|
||||
functionCode: `
|
||||
// Function to format error notifications
|
||||
const executions = items;
|
||||
const now = new Date();
|
||||
|
||||
// Group by workflow
|
||||
const workflowErrors = {};
|
||||
for (const execution of executions) {
|
||||
const workflowId = execution.workflowId;
|
||||
const workflowName = execution.workflowData.name;
|
||||
|
||||
if (!workflowErrors[workflowId]) {
|
||||
workflowErrors[workflowId] = {
|
||||
name: workflowName,
|
||||
errors: []
|
||||
};
|
||||
}
|
||||
|
||||
workflowErrors[workflowId].errors.push({
|
||||
id: execution.id,
|
||||
time: execution.finished,
|
||||
error: execution.error?.message || "Unknown error"
|
||||
});
|
||||
}
|
||||
|
||||
// Create notification text
|
||||
let notificationText = "⚠️ Workflow Error Alert ⚠️\\n\\n";
|
||||
notificationText += "The following workflows have failed:\\n\\n";
|
||||
|
||||
for (const [workflowId, data] of Object.entries(workflowErrors)) {
|
||||
notificationText += \`👉 \${data.name} (ID: \${workflowId})\\n\`;
|
||||
notificationText += \` Failed executions: \${data.errors.length}\\n\`;
|
||||
|
||||
// Add details about each failure
|
||||
data.errors.forEach(error => {
|
||||
const time = new Date(error.time).toLocaleString();
|
||||
notificationText += \` - \${time}: \${error.error}\\n\`;
|
||||
});
|
||||
|
||||
notificationText += "\\n";
|
||||
}
|
||||
|
||||
notificationText += "Check your n8n dashboard for more details.";
|
||||
|
||||
return [{
|
||||
json: {
|
||||
text: notificationText,
|
||||
subject: \`n8n Alert: \${Object.keys(workflowErrors).length} Workflow(s) Failed\`,
|
||||
timestamp: now.toISOString()
|
||||
}
|
||||
}];
|
||||
`
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Send Email",
|
||||
type: "n8n-nodes-base.emailSend",
|
||||
position: [900, 300],
|
||||
parameters: {
|
||||
to: "{{$env.EMAIL_RECIPIENT}}", // Will need to be configured
|
||||
subject: "{{$json.subject}}",
|
||||
text: "{{$json.text}}"
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: {
|
||||
"Schedule Trigger": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Get Failed Executions",
|
||||
type: "main",
|
||||
index: 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Get Failed Executions": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Filter Empty",
|
||||
type: "main",
|
||||
index: 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Filter Empty": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Format Notification",
|
||||
type: "main",
|
||||
index: 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Format Notification": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Send Email",
|
||||
type: "main",
|
||||
index: 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return `
|
||||
# Workflow Error Notification System Created
|
||||
|
||||
I've created a new workflow that will monitor for failed executions and send email notifications.
|
||||
|
||||
**Workflow ID:** ${monitorWorkflow.id}
|
||||
|
||||
## Configuration Needed:
|
||||
1. The workflow is currently **inactive** - you'll need to activate it once configured
|
||||
2. Set up the email configuration in n8n settings
|
||||
3. Configure the "Send Email" node with your recipient email address
|
||||
|
||||
## How It Works:
|
||||
- Runs every 15 minutes
|
||||
- Checks for any workflows that failed in the last 15 minutes
|
||||
- Groups failures by workflow and formats a notification
|
||||
- Sends an email with details about the failures
|
||||
|
||||
You can customize the notification format, schedule, and notification method by editing the workflow in the n8n interface.
|
||||
`;
|
||||
```
|
||||
|
||||
## Data Migration Between Workflows
|
||||
|
||||
### User Prompt
|
||||
|
||||
"Help me move data from my 'Legacy CRM' workflow to my 'New CRM' workflow."
|
||||
|
||||
### Assistant Actions
|
||||
|
||||
```javascript
|
||||
// Get all workflows
|
||||
const workflows = await useMcpTool('n8n-mcp-server', 'workflow_list', {});
|
||||
|
||||
// Find the source and target workflows
|
||||
const legacyWorkflow = workflows.find(w => w.name.toLowerCase().includes('legacy crm'));
|
||||
const newWorkflow = workflows.find(w => w.name.toLowerCase().includes('new crm'));
|
||||
|
||||
if (!legacyWorkflow) {
|
||||
return "I couldn't find a workflow with 'Legacy CRM' in the name. Please check the exact name of your source workflow.";
|
||||
}
|
||||
|
||||
if (!newWorkflow) {
|
||||
return "I couldn't find a workflow with 'New CRM' in the name. Please check the exact name of your target workflow.";
|
||||
}
|
||||
|
||||
// Create a data migration workflow
|
||||
const migrationWorkflow = await useMcpTool('n8n-mcp-server', 'workflow_create', {
|
||||
name: "Data Migration: Legacy CRM to New CRM",
|
||||
active: false, // Start inactive until confirmed
|
||||
nodes: [
|
||||
{
|
||||
name: "Manual Trigger",
|
||||
type: "n8n-nodes-base.manualTrigger",
|
||||
position: [100, 300],
|
||||
parameters: {}
|
||||
},
|
||||
{
|
||||
name: "Execute Legacy Workflow",
|
||||
type: "n8n-nodes-base.executeWorkflow",
|
||||
position: [300, 300],
|
||||
parameters: {
|
||||
workflowId: legacyWorkflow.id,
|
||||
options: {
|
||||
includeData: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Transform Data",
|
||||
type: "n8n-nodes-base.function",
|
||||
position: [500, 300],
|
||||
parameters: {
|
||||
functionCode: `
|
||||
// This is a placeholder transformation function that you'll need to customize
|
||||
// based on the actual data structure of your workflows
|
||||
|
||||
const legacyData = items;
|
||||
const transformedItems = [];
|
||||
|
||||
// Example transformation (modify based on your data structures)
|
||||
for (const item of legacyData) {
|
||||
transformedItems.push({
|
||||
json: {
|
||||
// Map legacy fields to new fields
|
||||
customer_id: item.json.id,
|
||||
customer_name: item.json.fullName || \`\${item.json.firstName || ''} \${item.json.lastName || ''}\`.trim(),
|
||||
email: item.json.emailAddress || item.json.email,
|
||||
phone: item.json.phoneNumber || item.json.phone,
|
||||
notes: item.json.comments || item.json.notes || '',
|
||||
// Add migration metadata
|
||||
migrated_from_legacy: true,
|
||||
migration_date: new Date().toISOString()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return transformedItems;
|
||||
`
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Execute New Workflow",
|
||||
type: "n8n-nodes-base.executeWorkflow",
|
||||
position: [700, 300],
|
||||
parameters: {
|
||||
workflowId: newWorkflow.id,
|
||||
options: {
|
||||
includeData: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Migration Summary",
|
||||
type: "n8n-nodes-base.function",
|
||||
position: [900, 300],
|
||||
parameters: {
|
||||
functionCode: `
|
||||
// Create a summary of the migration
|
||||
const results = items;
|
||||
const totalItems = items.length;
|
||||
const successItems = items.filter(item => !item.json.error).length;
|
||||
const errorItems = totalItems - successItems;
|
||||
|
||||
return [
|
||||
{
|
||||
json: {
|
||||
summary: "Migration Complete",
|
||||
total_records: totalItems,
|
||||
successful_records: successItems,
|
||||
failed_records: errorItems,
|
||||
completion_time: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
];
|
||||
`
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: {
|
||||
"Manual Trigger": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Execute Legacy Workflow",
|
||||
type: "main",
|
||||
index: 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Execute Legacy Workflow": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Transform Data",
|
||||
type: "main",
|
||||
index: 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Transform Data": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Execute New Workflow",
|
||||
type: "main",
|
||||
index: 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Execute New Workflow": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Migration Summary",
|
||||
type: "main",
|
||||
index: 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return `
|
||||
# Data Migration Workflow Created
|
||||
|
||||
I've created a new workflow to migrate data from "${legacyWorkflow.name}" to "${newWorkflow.name}".
|
||||
|
||||
**Migration Workflow ID:** ${migrationWorkflow.id}
|
||||
|
||||
## Important Notes:
|
||||
1. The workflow is currently **inactive** - activate it only when you're ready to perform the migration
|
||||
2. The data transformation is a placeholder - you'll need to edit the "Transform Data" function node to map fields correctly based on your specific data structures
|
||||
3. This is a one-time migration workflow - run it manually when you're ready to migrate the data
|
||||
|
||||
## Next Steps:
|
||||
1. Open the workflow in the n8n interface
|
||||
2. Edit the "Transform Data" function to correctly map your data fields
|
||||
3. Test the workflow with a small sample if possible
|
||||
4. Activate and run the workflow to perform the migration
|
||||
5. Check the migration summary for results
|
||||
|
||||
Would you like me to help you customize the data transformation based on the specific fields in your CRM workflows?
|
||||
`;
|
||||
```
|
||||
|
||||
These examples demonstrate more advanced usage patterns for the n8n MCP Server. For integration with other systems, see the [Integration Examples](./integration-examples.md) page.
|
||||
Reference in New Issue
Block a user