aios-core
Version:
Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework
552 lines (484 loc) • 17.4 kB
YAML
tool:
schema_version: 2.0
id: n8n
type: mcp
name: n8n Workflow Automation
version: 1.0.0
description: n8n workflow management with execution validation and credential handling
knowledge_strategy: executable
executable_knowledge:
validators:
# Combined validator for execute_workflow
- id: validate-execute-workflow
validates: execute_workflow
language: javascript
checks:
- required_fields: [workflow_id]
function: |
(function() {
const errors = [];
// 1. Required workflow_id
if (!args.args.workflow_id && !args.args.workflowId) {
errors.push("workflow_id is required");
}
// 2. Validate data parameter structure if provided
if (args.args.data) {
if (typeof args.args.data !== 'object') {
errors.push("data must be an object");
}
}
// 3. Validate wait_for_completion is boolean
if (args.args.wait_for_completion !== undefined &&
typeof args.args.wait_for_completion !== 'boolean') {
errors.push("wait_for_completion must be boolean");
}
return {
valid: errors.length === 0,
errors: errors
};
})();
# Validator for create_workflow
- id: validate-create-workflow
validates: create_workflow
language: javascript
function: |
(function() {
const errors = [];
// 1. Required name field
if (!args.args.name) {
errors.push("name is required");
}
// 2. Validate nodes structure if provided
if (args.args.nodes) {
if (!Array.isArray(args.args.nodes)) {
errors.push("nodes must be an array");
} else {
args.args.nodes.forEach((node, index) => {
if (!node.type) {
errors.push(`nodes[${index}] missing required 'type' field`);
}
if (!node.name) {
errors.push(`nodes[${index}] missing required 'name' field`);
}
});
}
}
// 3. Validate connections structure
if (args.args.connections) {
if (typeof args.args.connections !== 'object') {
errors.push("connections must be an object");
}
}
return {
valid: errors.length === 0,
errors: errors
};
})();
# Validator for create_credential
- id: validate-create-credential
validates: create_credential
language: javascript
function: |
(function() {
const errors = [];
if (!args.args.name) {
errors.push("name is required for create_credential");
}
if (!args.args.type) {
errors.push("type is required for create_credential");
}
if (!args.args.data) {
errors.push("data is required for create_credential");
} else if (typeof args.args.data !== 'object') {
errors.push("data must be an object");
}
return {
valid: errors.length === 0,
errors: errors
};
})();
# Validator for update_credential
- id: validate-update-credential
validates: update_credential
language: javascript
function: |
(function() {
const errors = [];
if (!args.args.credential_id && !args.args.credentialId) {
errors.push("credential_id is required for update_credential");
}
return {
valid: errors.length === 0,
errors: errors
};
})();
# Validator for delete_credential
- id: validate-delete-credential
validates: delete_credential
language: javascript
function: |
(function() {
const errors = [];
if (!args.args.credential_id && !args.args.credentialId) {
errors.push("credential_id is required for delete_credential");
}
return {
valid: errors.length === 0,
errors: errors
};
})();
helpers:
- id: extract-workflow-state
language: javascript
runtime: isolated_vm
description: "Extract current state from workflow execution"
function: |
(function() {
const { execution } = args;
if (!execution) return null;
return {
id: execution.id,
status: execution.finished ? 'finished' : execution.stoppedAt ? 'stopped' : 'running',
startedAt: execution.startedAt,
finishedAt: execution.finishedAt,
mode: execution.mode
};
})();
- id: validate-node-connections
language: javascript
runtime: isolated_vm
description: "Validate node connections in workflow"
function: |
(function() {
const { nodes, connections } = args;
if (!nodes || !connections) {
return { valid: false, errors: ['Missing nodes or connections'] };
}
const errors = [];
const nodeNames = new Set(nodes.map(n => n.name));
// Check all connection sources exist
for (const [sourceName, outputs] of Object.entries(connections)) {
if (!nodeNames.has(sourceName)) {
errors.push(`Connection source '${sourceName}' not found in nodes`);
}
// Check all connection targets exist
// n8n structure: outputs = { main: [[{node, type, index}]], error: [[...]] }
for (const outputConnections of Object.values(outputs || {})) {
if (Array.isArray(outputConnections)) {
// outputConnections is an array of arrays
outputConnections.forEach(connectionGroup => {
if (Array.isArray(connectionGroup)) {
connectionGroup.forEach(conn => {
if (conn.node && !nodeNames.has(conn.node)) {
errors.push(`Connection target '${conn.node}' not found in nodes`);
}
});
}
});
}
}
}
return {
valid: errors.length === 0,
errors: errors
};
})();
- id: format-workflow-data
language: javascript
runtime: isolated_vm
description: "Format input data for workflow execution"
function: |
(function() {
const { data, workflowData } = args;
// If workflow expects specific input format, validate it
if (workflowData && workflowData.nodes) {
const triggerNode = workflowData.nodes.find(n =>
n.type.includes('trigger') ||
n.type.includes('webhook') ||
n.type === 'n8n-nodes-base.start'
);
if (triggerNode && triggerNode.parameters !== undefined) {
// Format data according to trigger expectations
return {
formatted: true,
data: data || {},
triggerNode: triggerNode.name
};
}
}
return {
formatted: false,
data: data || {}
};
})();
- id: parse-execution-error
language: javascript
runtime: isolated_vm
description: "Parse and format execution errors"
function: |
(function() {
const { error, execution } = args;
if (!error) return null;
return {
message: error.message || 'Unknown error',
node: error.node || 'unknown',
timestamp: error.timestamp || execution?.stoppedAt,
stack: error.stack || null
};
})();
- id: validate-credential-type
language: javascript
runtime: isolated_vm
description: "Validate credential type is supported"
function: |
(function() {
const { type } = args;
// Common n8n credential types
const validTypes = [
'httpBasicAuth',
'httpHeaderAuth',
'oAuth2Api',
'apiKey',
'postgres',
'mysql',
'mongodb',
'redis',
'aws',
'googleApi',
'slackApi',
'githubApi',
'jwtAuth'
];
return validTypes.includes(type);
})();
- id: build-workflow-structure
language: javascript
runtime: isolated_vm
description: "Build workflow structure from nodes and connections"
function: |
(function() {
const { name, nodes, connections } = args;
if (!name) {
return { error: 'Workflow name is required' };
}
return {
name: name,
nodes: nodes || [],
connections: connections || {},
active: false,
settings: {},
staticData: null
};
})();
- id: calculate-workflow-complexity
language: javascript
runtime: isolated_vm
description: "Calculate workflow complexity score"
function: |
(function() {
const { nodes, connections } = args;
if (!nodes) return { complexity: 0 };
let complexity = nodes.length; // Base complexity from node count
// Add complexity for connections
if (connections) {
const connectionCount = Object.values(connections).reduce((sum, outputs) => {
return sum + Object.values(outputs || {}).reduce((s, conns) => {
return s + (Array.isArray(conns) ? conns.length : 0);
}, 0);
}, 0);
complexity += connectionCount * 0.5;
}
// Add complexity for certain node types
const complexNodeTypes = ['n8n-nodes-base.if', 'n8n-nodes-base.switch', 'n8n-nodes-base.function'];
const complexNodes = nodes.filter(n => complexNodeTypes.includes(n.type)).length;
complexity += complexNodes * 2;
return {
complexity: Math.round(complexity),
nodeCount: nodes.length,
connectionCount: Object.keys(connections || {}).length,
hasComplexLogic: complexNodes > 0
};
})();
api_complexity:
workflow_execution_state:
- state: waiting
description: "Workflow is queued for execution"
next_states: [running, failed]
- state: running
description: "Workflow is currently executing"
next_states: [finished, stopped, error]
- state: finished
description: "Workflow completed successfully"
terminal: true
- state: stopped
description: "Workflow was manually stopped"
terminal: true
- state: error
description: "Workflow encountered an error"
terminal: true
retry_allowed: true
credential_types:
- type: httpBasicAuth
fields: [username, password]
description: "HTTP Basic Authentication"
- type: httpHeaderAuth
fields: [name, value]
description: "HTTP Header Authentication"
- type: oAuth2Api
fields: [clientId, clientSecret, authUrl, accessTokenUrl]
description: "OAuth 2.0 Authentication"
- type: apiKey
fields: [apiKey]
description: "API Key Authentication"
node_execution_patterns:
- pattern: sequential
description: "Nodes execute in order, one after another"
use_case: "Simple linear workflows"
- pattern: parallel
description: "Multiple nodes execute simultaneously"
use_case: "Independent data processing"
- pattern: conditional
description: "Execution path depends on node conditions"
nodes: [n8n-nodes-base.if, n8n-nodes-base.switch]
- pattern: loop
description: "Repeated execution over data items"
nodes: [n8n-nodes-base.splitInBatches]
anti_patterns:
- pattern: missing_error_handling
description: "Not handling node execution errors"
category: reliability
severity: high
wrong: |
execute_workflow({
workflow_id: "123"
// ❌ No error handling for failed execution
})
correct: |
const result = execute_workflow({
workflow_id: "123",
wait_for_completion: true
})
if (result.status === 'error') {
// ✅ Handle error appropriately
handle_execution_error(result)
}
rationale: "Always check execution status and handle errors gracefully."
- pattern: invalid_node_connections
description: "Creating workflows with disconnected or invalid nodes"
category: workflow_structure
severity: medium
wrong: |
create_workflow({
name: "Test",
nodes: [{name: "Start", type: "trigger"}, {name: "End", type: "action"}],
connections: {
"NonExistent": { // ❌ Node doesn't exist
main: [[{node: "End"}]]
}
}
})
correct: |
create_workflow({
name: "Test",
nodes: [{name: "Start", type: "trigger"}, {name: "End", type: "action"}],
connections: {
"Start": { // ✅ Correct node name
main: [[{node: "End", type: "main", index: 0}]]
}
}
})
rationale: "Use validate-node-connections helper to verify connections before workflow creation."
- pattern: missing_credentials
description: "Referencing credentials that don't exist"
category: authentication
severity: high
wrong: |
create_workflow({
nodes: [{
type: "n8n-nodes-base.httpRequest",
credentials: {
httpBasicAuth: "nonexistent" // ❌ Credential not created
}
}]
})
correct: |
// First create credential
const cred = create_credential({
type: "httpBasicAuth",
name: "My API Auth",
data: {username: "user", password: "pass"}
})
// Then reference it
create_workflow({
nodes: [{
type: "n8n-nodes-base.httpRequest",
credentials: {
httpBasicAuth: cred.id // ✅ Valid credential reference
}
}]
})
rationale: "Always create and verify credentials before referencing them in workflows."
examples:
execute_workflow:
- scenario: success
description: "Execute workflow and wait for completion"
input:
workflow_id: "wf_abc123"
wait_for_completion: true
data: { key: "value" }
output:
execution_id: "exec_xyz789"
status: "finished"
data: { result: "success" }
- scenario: failure_invalid_param
description: "Missing required workflow_id"
input:
data: { key: "value" }
error:
code: VALIDATION_ERROR
message: "workflow_id is required"
validator: validate-execute-workflow
create_workflow:
- scenario: success
description: "Create simple workflow"
input:
name: "Data Processor"
nodes:
- type: n8n-nodes-base.start
name: Start
parameters: {}
- type: n8n-nodes-base.httpRequest
name: Fetch Data
parameters:
url: "https://api.example.com/data"
connections:
Start:
main: [[{node: "Fetch Data", type: "main", index: 0}]]
output:
workflow_id: "wf_new123"
name: "Data Processor"
active: false
- scenario: failure_invalid_param
description: "Invalid node structure"
input:
name: "Test Workflow"
nodes: "not an array"
error:
code: VALIDATION_ERROR
message: "nodes must be an array"
validator: validate-create-workflow
mcp_specific:
server_command: "npx -y @illuminaresolutions/n8n-mcp-server"
transport: stdio
environment_variables:
- name: N8N_HOST
required: true
description: "n8n instance URL (e.g., https://your-n8n-instance.com)"
- name: N8N_API_KEY
required: true
description: "n8n API key for authentication"
health_check:
method: tool_call
command: list_workflows
expected_response: "Array of workflows"
timeout_ms: 5000